From 17669b7be0f852dc111109d1fcd52e2796cbd502 Mon Sep 17 00:00:00 2001 From: RainLoop Team Date: Wed, 17 Aug 2016 01:01:20 +0300 Subject: [PATCH] es5 -> es2015 (last stage) Signature plugin fixes Add view decorator A large number of fixes --- .cmds | 6 +- .eslintrc.js | 10 +- .gitignore | 1 + .travis.yml | 12 +- README.md | 46 +- dev/App/User.js | 253 +- dev/Common/Audio.js | 1 - dev/Common/Booter.js | 33 +- dev/Common/Globals.js | 44 +- dev/Common/HtmlEditor.js | 30 +- dev/Common/Jassl.js | 54 + dev/Common/Momentor.js | 5 +- dev/Common/Selector.js | 181 +- dev/Common/Utils.js | 109 +- dev/Component/AbstractInput.js | 10 +- dev/External/Opentip.js | 10 +- dev/External/ko.js | 1118 ++-- dev/Helper/Apps/Admin.js | 7 + dev/Helper/Apps/User.js | 7 + dev/Html/PreviewMessage.html | 114 + dev/Knoin/AbstractView.js | 123 - dev/Knoin/AbstractViewNext.js | 64 + dev/Knoin/Knoin.js | 118 +- dev/Model/Email.js | 11 +- dev/Model/Filter.js | 7 +- dev/Model/FilterCondition.js | 16 +- dev/Model/Folder.js | 12 +- dev/Model/Message.js | 165 +- dev/Promises/AbstractAjax.js | 342 +- dev/Promises/AbstractBasic.js | 74 +- dev/Promises/User/Ajax.js | 108 +- dev/Promises/User/Populator.js | 334 +- dev/Remote/AbstractAjax.js | 527 +- dev/Remote/Admin/Ajax.js | 584 +- dev/Remote/User/Ajax.js | 1665 +++-- dev/Screen/AbstractSettings.js | 84 +- dev/Screen/Admin/Login.js | 9 +- dev/Screen/Admin/Settings.js | 14 +- dev/Screen/User/About.js | 11 +- dev/Screen/User/Login.js | 11 +- dev/Screen/User/MailBox.js | 32 +- dev/Screen/User/Settings.js | 15 +- dev/Settings/.gitignore | 2 - dev/Settings/Admin/About.js | 10 +- dev/Settings/Admin/Branding.js | 2 + dev/Settings/Admin/Contacts.js | 6 +- dev/Settings/Admin/Domains.js | 10 +- dev/Settings/Admin/Login.js | 8 +- dev/Settings/Admin/Packages.js | 6 +- dev/Settings/Admin/Plugins.js | 18 +- dev/Settings/Admin/Prem/Branding.js | 105 + dev/Settings/Admin/Prem/Licensing.js | 71 + dev/Settings/Admin/Security.js | 2 +- dev/Settings/User/Accounts.js | 23 +- dev/Settings/User/ChangePassword.js | 6 +- dev/Settings/User/Filters.js | 7 +- dev/Settings/User/Folders.js | 10 +- dev/Settings/User/General.js | 2 +- dev/Settings/User/OpenPgp.js | 8 +- dev/Settings/User/Social.js | 30 +- dev/Settings/User/Templates.js | 19 +- dev/Stores/AbstractApp.js | 6 +- dev/Stores/Admin/Capa.js | 71 +- dev/Stores/Admin/Core.js | 33 +- dev/Stores/Admin/Domain.js | 18 +- dev/Stores/Admin/License.js | 21 +- dev/Stores/Admin/Package.js | 17 +- dev/Stores/Admin/Plugin.js | 15 +- dev/Stores/Language.js | 67 +- dev/Stores/Social.js | 170 +- dev/Stores/Theme.js | 44 +- dev/Stores/User/Account.js | 84 +- dev/Stores/User/App.js | 6 +- dev/Stores/User/Contact.js | 54 +- dev/Stores/User/Filter.js | 21 +- dev/Stores/User/Folder.js | 440 +- dev/Stores/User/Identity.js | 3 +- dev/Stores/User/Message.js | 1556 +++-- dev/Stores/User/Notification.js | 363 +- dev/Stores/User/Pgp.js | 792 ++- dev/Stores/User/Quota.js | 47 +- dev/Stores/User/Settings.js | 146 +- dev/Stores/User/Template.js | 42 +- dev/Styles/@Boot.css | 6 +- dev/Styles/Animations.less | 9 + dev/Styles/_End.less | 7 + dev/View/Admin/Login.js | 200 +- dev/View/Admin/Settings/Menu.js | 115 +- dev/View/Admin/Settings/Pane.js | 82 +- dev/View/Popup/Account.js | 191 +- dev/View/Popup/Activate.js | 215 +- dev/View/Popup/AddOpenPgpKey.js | 182 +- dev/View/Popup/AdvancedSearch.js | 323 +- dev/View/Popup/Ask.js | 215 +- dev/View/Popup/Compose.js | 3795 ++++++------ dev/View/Popup/ComposeOpenPgp.js | 819 ++- dev/View/Popup/Contacts.js | 1378 ++--- dev/View/Popup/Domain.js | 842 ++- dev/View/Popup/DomainAlias.js | 173 +- dev/View/Popup/Filter.js | 330 +- dev/View/Popup/FolderClear.js | 168 +- dev/View/Popup/FolderCreate.js | 158 +- dev/View/Popup/FolderSystem.js | 201 +- dev/View/Popup/Identity.js | 328 +- dev/View/Popup/KeyboardShortcutsHelp.js | 95 +- dev/View/Popup/Languages.js | 136 +- dev/View/Popup/MessageOpenPgp.js | 268 +- dev/View/Popup/NewOpenPgpKey.js | 222 +- dev/View/Popup/Plugin.js | 249 +- dev/View/Popup/Template.js | 323 +- dev/View/Popup/TwoFactorConfiguration.js | 373 +- dev/View/Popup/TwoFactorTest.js | 117 +- dev/View/Popup/ViewOpenPgpKey.js | 98 +- dev/View/Popup/WelcomePage.js | 82 +- dev/View/User/About.js | 34 +- dev/View/User/AbstractSystemDropDown.js | 219 +- dev/View/User/Login.js | 819 ++- dev/View/User/MailBox/FolderList.js | 478 +- dev/View/User/MailBox/MessageList.js | 1831 +++--- dev/View/User/MailBox/MessageView.js | 2239 ++++--- dev/View/User/MailBox/SystemDropDown.js | 25 +- dev/View/User/Settings/Menu.js | 132 +- dev/View/User/Settings/Pane.js | 106 +- dev/View/User/Settings/SystemDropDown.js | 25 +- dev/boot.js | 3 - dev/bootstrap.js | 4 +- gulpfile.js | 109 +- jsconfig.json | 43 +- npm-shrinkwrap.json | 366 +- package.json | 34 +- .../app/libraries/MailSo/Base/HtmlUtils.php | 3130 +++++----- .../libraries/MailSo/Imap/FetchResponse.php | 547 +- .../app/libraries/MailSo/Mail/MailClient.php | 5330 ++++++++--------- .../0.0.0/app/libraries/MailSo/Mime/Email.php | 653 +- .../app/libraries/MailSo/Mime/EmailDep.php | 339 ++ .../v/0.0.0/app/libraries/RainLoop/.gitignore | 2 - .../0.0.0/app/libraries/RainLoop/Actions.php | 66 +- .../v/0.0.0/app/libraries/RainLoop/Api.php | 546 +- .../libraries/RainLoop/Config/Application.php | 1 - .../Providers/Domain/DefaultDomain.php | 812 +-- .../app/libraries/RainLoop/Providers/Prem.php | 392 ++ .../0.0.0/app/templates/Themes/template.less | 594 +- .../app/templates/Views/Admin/AdminLogin.html | 92 +- .../0.0.0/app/templates/Views/User/Login.html | 290 +- .../templates/Views/User/MailFolderList.html | 74 +- .../templates/Views/User/PopupsAccount.html | 100 +- .../Views/User/PopupsAddOpenPgpKey.html | 53 +- rainloop/v/0.0.0/static/js/min/.empty | 0 tests/Common/NpmTest.php | 25 - tests/MailSo/Mime/EmailTest.php | 48 +- vendors/ckeditor-plugins/signature/plugin.js | 260 +- webpack.config.builder.js | 47 +- webpack.config.js | 2 + 153 files changed, 21193 insertions(+), 21115 deletions(-) create mode 100644 dev/Common/Jassl.js create mode 100644 dev/Helper/Apps/Admin.js create mode 100644 dev/Helper/Apps/User.js create mode 100644 dev/Html/PreviewMessage.html delete mode 100644 dev/Knoin/AbstractView.js create mode 100644 dev/Knoin/AbstractViewNext.js delete mode 100644 dev/Settings/.gitignore create mode 100644 dev/Settings/Admin/Prem/Branding.js create mode 100644 dev/Settings/Admin/Prem/Licensing.js create mode 100644 rainloop/v/0.0.0/app/libraries/MailSo/Mime/EmailDep.php delete mode 100644 rainloop/v/0.0.0/app/libraries/RainLoop/.gitignore create mode 100644 rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Prem.php create mode 100644 rainloop/v/0.0.0/static/js/min/.empty delete mode 100644 tests/Common/NpmTest.php create mode 100644 webpack.config.js diff --git a/.cmds b/.cmds index 870d62315..c66dd8e86 100644 --- a/.cmds +++ b/.cmds @@ -3,10 +3,10 @@ tx pull -a # dependencies checker -npm-check --skip-unused +npm-check --skip-unused --save-exact # dependencies locker npm shrinkwrap --dev -# js code validation -gulp v +# webpack +webpack --color --watch diff --git a/.eslintrc.js b/.eslintrc.js index c5fbfabc0..cc99bc9db 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,6 +4,7 @@ module.exports = { 'ecmaFeatures': { 'modules': true }, + "parser": "babel-eslint", 'parserOptions': { 'ecmaVersion': 6, 'sourceType': 'module' @@ -11,8 +12,7 @@ module.exports = { 'env': { 'node': true, 'commonjs': true, - 'es6': true, - 'browser': true + 'es6': true }, 'globals': { 'RL_COMMUNITY': true, @@ -84,7 +84,7 @@ module.exports = { 'no-implicit-coercion': [2, {'allow': ['!!', '+']}], 'no-implicit-globals': 2, 'no-implied-eval': 2, -// 'no-invalid-this': 2, + 'no-invalid-this': 2, 'no-iterator': 2, 'no-labels': 2, 'no-lone-blocks': 2, @@ -263,9 +263,9 @@ module.exports = { 'no-useless-computed-key': 2, 'no-useless-constructor': 2, 'no-useless-rename': 2, -// 'no-var': 2, + 'no-var': 2, // 'object-shorthand': 2, -// 'prefer-arrow-callback': 2, + 'prefer-arrow-callback': 2, 'prefer-const': 2, // 'prefer-reflect': 2, diff --git a/.gitignore b/.gitignore index 7c1bec277..e33a5959b 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ /rainloop/v/0.0.0/static/css/*.css /rainloop/v/0.0.0/static/js/*.js /rainloop/v/0.0.0/static/js/**/*.js +!/rainloop/v/0.0.0/static/js/min/.gitempty /rainloop/v/0.0.0/app/localization/moment/* !/rainloop/v/0.0.0/app/localization/moment/.gitempty /node_modules diff --git a/.travis.yml b/.travis.yml index 5232519ef..e17906f9d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,9 @@ php: - '5.5' - '5.6' - '7.0' -before_script: - - sudo apt-get install -y build-essential libssl-dev - - curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh | bash - - nvm install 4.4.5 - - nvm use 4.4.5 - - npm install -g eslint +#before_script: +# - sudo apt-get install -y build-essential libssl-dev +# - curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh | bash +# - nvm install 4.4.5 +# - nvm use 4.4.5 +# - npm install -g eslint babel-eslint diff --git a/README.md b/README.md index 5e5991eaa..42919fab3 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,23 @@ -RainLoop Webmail [![Build Status](https://travis-ci.org/RainLoop/rainloop-webmail.svg?branch=master)](https://travis-ci.org/RainLoop/rainloop-webmail) -================== - -Simple, modern & fast web-based email client. - -Modest system requirements, decent performance, simple installation and upgrade, no database required - all these make RainLoop Webmail a perfect choice for your email solution. - -For more information about the product, check [rainloop.net](http://www.rainloop.net/). - -Information about installing the product, check the [documentation page](http://www.rainloop.net/docs/installation/). - -## Attention - -This is **NOT** a stable version of RainLoop Webmail. -It's not recommended to use in production environment. - -## License - -**RainLoop Webmail (Community edition)** is released under -**GNU AFFERO GENERAL PUBLIC LICENSE Version 3 (AGPL)**. -http://www.gnu.org/licenses/agpl-3.0.html - -Copyright (c) 2016 Rainloop Team +RainLoop Webmail [![Build Status](https://travis-ci.org/RainLoop/rainloop-webmail.svg?branch=master)](https://travis-ci.org/RainLoop/rainloop-webmail) [![devDependency Status](https://david-dm.org/RainLoop/rainloop-webmail/dev-status.svg)](https://david-dm.org/RainLoop/rainloop-webmail?type=dev) +================== + +Simple, modern & fast web-based email client. + +Modest system requirements, decent performance, simple installation and upgrade, no database required - all these make RainLoop Webmail a perfect choice for your email solution. + +For more information about the product, check [rainloop.net](http://www.rainloop.net/). + +Information about installing the product, check the [documentation page](http://www.rainloop.net/docs/installation/). + +## Attention + +This is **NOT** a stable version of RainLoop Webmail. +It's not recommended to use in production environment. + +## License + +**RainLoop Webmail (Community edition)** is released under +**GNU AFFERO GENERAL PUBLIC LICENSE Version 3 (AGPL)**. +http://www.gnu.org/licenses/agpl-3.0.html + +Copyright (c) 2016 Rainloop Team diff --git a/dev/App/User.js b/dev/App/User.js index 9a4df785e..5a77cfbfc 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -7,7 +7,7 @@ import Tinycon from 'Tinycon'; import { noop, trim, log, has, isArray, inArray, isUnd, isNormal, isPosNumeric, isNonEmptyArray, - pInt, pString, delegateRunOnDestroy, mailToHelper, windowResize + pInt, pString, delegateRunOnDestroy, mailToHelper, windowResize, jassl } from 'Common/Utils'; import { @@ -241,33 +241,33 @@ class AppUser extends AbstractApp sTrashFolder = FolderStore.trashFolder(), sSpamFolder = FolderStore.spamFolder(); - _.each(this.moveCache, (oItem) => { + _.each(this.moveCache, (item) => { - var - bSpam = sSpamFolder === oItem.To, - bTrash = sTrashFolder === oItem.To, - bHam = !bSpam && sSpamFolder === oItem.From && Cache.getFolderInboxName() === oItem.To; + const + isSpam = sSpamFolder === item.To, + isTrash = sTrashFolder === item.To, + isHam = !isSpam && sSpamFolder === item.From && Cache.getFolderInboxName() === item.To; - Remote.messagesMove(this.moveOrDeleteResponseHelper, oItem.From, oItem.To, oItem.Uid, - bSpam ? 'SPAM' : (bHam ? 'HAM' : ''), bSpam || bTrash); + Remote.messagesMove(this.moveOrDeleteResponseHelper, item.From, item.To, item.Uid, + isSpam ? 'SPAM' : (isHam ? 'HAM' : ''), isSpam || isTrash); }); this.moveCache = {}; } - messagesMoveHelper(sFromFolderFullNameRaw, sToFolderFullNameRaw, aUidForMove) { + messagesMoveHelper(fromFolderFullNameRaw, toFolderFullNameRaw, uidsForMove) { - var sH = '$$' + sFromFolderFullNameRaw + '$$' + sToFolderFullNameRaw + '$$'; - if (!this.moveCache[sH]) + const hash = '$$' + fromFolderFullNameRaw + '$$' + toFolderFullNameRaw + '$$'; + if (!this.moveCache[hash]) { - this.moveCache[sH] = { - From: sFromFolderFullNameRaw, - To: sToFolderFullNameRaw, + this.moveCache[hash] = { + From: fromFolderFullNameRaw, + To: toFolderFullNameRaw, Uid: [] }; } - this.moveCache[sH].Uid = _.union(this.moveCache[sH].Uid, aUidForMove); + this.moveCache[hash].Uid = _.union(this.moveCache[hash].Uid, uidsForMove); this.messagesMoveTrigger(); } @@ -451,20 +451,20 @@ class AppUser extends AbstractApp if (PgpStore.capaOpenPGP()) { - var - aKeys = [], - oEmail = new EmailModel(), - oOpenpgpKeyring = PgpStore.openpgpKeyring, - oOpenpgpKeys = oOpenpgpKeyring ? oOpenpgpKeyring.getAllKeys() : []; + const + keys = [], + email = new EmailModel(), + openpgpKeyring = PgpStore.openpgpKeyring, + openpgpKeys = openpgpKeyring ? openpgpKeyring.getAllKeys() : []; - _.each(oOpenpgpKeys, (oItem, iIndex) => { + _.each(openpgpKeys, (oItem, iIndex) => { if (oItem && oItem.primaryKey) { - var + const aEmails = [], aUsers = [], - oPrimaryUser = oItem.getPrimaryUser(), - sUser = (oPrimaryUser && oPrimaryUser.user) ? oPrimaryUser.user.userId.userid : + primaryUser = oItem.getPrimaryUser(), + user = (primaryUser && primaryUser.user) ? primaryUser.user.userId.userid : (oItem.users && oItem.users[0] ? oItem.users[0].userId.userid : ''); if (oItem.users) @@ -472,11 +472,11 @@ class AppUser extends AbstractApp _.each(oItem.users, (item) => { if (item.userId) { - oEmail.clear(); - oEmail.mailsoParse(item.userId.userid); - if (oEmail.validate()) + email.clear(); + email.mailsoParse(item.userId.userid); + if (email.validate()) { - aEmails.push(oEmail.email); + aEmails.push(email.email); aUsers.push(item.userId.userid); } } @@ -485,7 +485,7 @@ class AppUser extends AbstractApp if (aEmails.length) { - aKeys.push(new OpenPgpKeyModel( + keys.push(new OpenPgpKeyModel( iIndex, oItem.primaryKey.getFingerprint(), oItem.primaryKey.getKeyId().toHex().toLowerCase(), @@ -496,14 +496,14 @@ class AppUser extends AbstractApp aEmails, oItem.isPrivate(), oItem.armor(), - sUser) + user) ); } } }); delegateRunOnDestroy(PgpStore.openpgpkeys()); - PgpStore.openpgpkeys(aKeys); + PgpStore.openpgpkeys(keys); } } @@ -549,10 +549,11 @@ class AppUser extends AbstractApp if (StorageResultType.Success === sResult && oData.Result) { - var + const aCounts = {}, - sParentEmail = Settings.settingsGet('ParentEmail'), sAccountEmail = AccountStore.email(); + let + sParentEmail = Settings.settingsGet('ParentEmail'); sParentEmail = '' === sParentEmail ? sAccountEmail : sParentEmail; @@ -735,14 +736,15 @@ class AppUser extends AbstractApp const utc = Momentor.momentNowUnix(); _.each(oData.Result.List, (oItem) => { - var - sHash = Cache.getFolderHash(oItem.Folder), - oFolder = Cache.getFolderFromCacheList(oItem.Folder), - bUnreadCountChange = false; + const + hash = Cache.getFolderHash(oItem.Folder), + folder = Cache.getFolderFromCacheList(oItem.Folder); + let + unreadCountChange = false; - if (oFolder) + if (folder) { - oFolder.interval = utc; + folder.interval = utc; if (oItem.Hash) { @@ -751,39 +753,39 @@ class AppUser extends AbstractApp if (isNormal(oItem.MessageCount)) { - oFolder.messageCountAll(oItem.MessageCount); + folder.messageCountAll(oItem.MessageCount); } if (isNormal(oItem.MessageUnseenCount)) { - if (pInt(oFolder.messageCountUnread()) !== pInt(oItem.MessageUnseenCount)) + if (pInt(folder.messageCountUnread()) !== pInt(oItem.MessageUnseenCount)) { - bUnreadCountChange = true; + unreadCountChange = true; } - oFolder.messageCountUnread(oItem.MessageUnseenCount); + folder.messageCountUnread(oItem.MessageUnseenCount); } - if (bUnreadCountChange) + if (unreadCountChange) { - Cache.clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw); + Cache.clearMessageFlagsFromCacheByFolder(folder.fullNameRaw); } - if (oItem.Hash !== sHash || '' === sHash) + if (oItem.Hash !== hash || '' === hash) { - if (oFolder.fullNameRaw === FolderStore.currentFolderFullNameRaw()) + if (folder.fullNameRaw === FolderStore.currentFolderFullNameRaw()) { this.reloadMessageList(); } } - else if (bUnreadCountChange) + else if (unreadCountChange) { - if (oFolder.fullNameRaw === FolderStore.currentFolderFullNameRaw()) + if (folder.fullNameRaw === FolderStore.currentFolderFullNameRaw()) { const aList = MessageStore.messageList(); if (isNonEmptyArray(aList)) { - this.folderInformation(oFolder.fullNameRaw, aList); + this.folderInformation(folder.fullNameRaw, aList); } } } @@ -804,76 +806,76 @@ class AppUser extends AbstractApp * @param {string} sFolderFullNameRaw * @param {string|bool} mUid * @param {number} iSetAction - * @param {Array=} aMessages = null + * @param {Array=} messages = null */ - messageListAction(sFolderFullNameRaw, mUid, iSetAction, aMessages) { + messageListAction(sFolderFullNameRaw, mUid, iSetAction, messages) { - var - oFolder = null, - aRootUids = [], - iAlreadyUnread = 0; + let + folder = null, + alreadyUnread = 0, + rootUids = []; - if (isUnd(aMessages)) + if (isUnd(messages) || !messages) { - aMessages = MessageStore.messageListChecked(); + messages = MessageStore.messageListChecked(); } - aRootUids = _.uniq(_.compact(_.map(aMessages, (oMessage) => (oMessage && oMessage.uid ? oMessage.uid : null)))); + rootUids = _.uniq(_.compact(_.map(messages, (oMessage) => (oMessage && oMessage.uid ? oMessage.uid : null)))); - if ('' !== sFolderFullNameRaw && 0 < aRootUids.length) + if ('' !== sFolderFullNameRaw && 0 < rootUids.length) { switch (iSetAction) { case MessageSetAction.SetSeen: - _.each(aRootUids, (sSubUid) => { - iAlreadyUnread += Cache.storeMessageFlagsToCacheBySetAction( + _.each(rootUids, (sSubUid) => { + alreadyUnread += Cache.storeMessageFlagsToCacheBySetAction( sFolderFullNameRaw, sSubUid, iSetAction); }); - oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw); - if (oFolder) + folder = Cache.getFolderFromCacheList(sFolderFullNameRaw); + if (folder) { - oFolder.messageCountUnread(oFolder.messageCountUnread() - iAlreadyUnread); + folder.messageCountUnread(folder.messageCountUnread() - alreadyUnread); } - Remote.messageSetSeen(noop, sFolderFullNameRaw, aRootUids, true); + Remote.messageSetSeen(noop, sFolderFullNameRaw, rootUids, true); break; case MessageSetAction.UnsetSeen: - _.each(aRootUids, (sSubUid) => { - iAlreadyUnread += Cache.storeMessageFlagsToCacheBySetAction( + _.each(rootUids, (sSubUid) => { + alreadyUnread += Cache.storeMessageFlagsToCacheBySetAction( sFolderFullNameRaw, sSubUid, iSetAction); }); - oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw); - if (oFolder) + folder = Cache.getFolderFromCacheList(sFolderFullNameRaw); + if (folder) { - oFolder.messageCountUnread(oFolder.messageCountUnread() - iAlreadyUnread + aRootUids.length); + folder.messageCountUnread(folder.messageCountUnread() - alreadyUnread + rootUids.length); } - Remote.messageSetSeen(noop, sFolderFullNameRaw, aRootUids, false); + Remote.messageSetSeen(noop, sFolderFullNameRaw, rootUids, false); break; case MessageSetAction.SetFlag: - _.each(aRootUids, (sSubUid) => { + _.each(rootUids, (sSubUid) => { Cache.storeMessageFlagsToCacheBySetAction( sFolderFullNameRaw, sSubUid, iSetAction); }); - Remote.messageSetFlagged(noop, sFolderFullNameRaw, aRootUids, true); + Remote.messageSetFlagged(noop, sFolderFullNameRaw, rootUids, true); break; case MessageSetAction.UnsetFlag: - _.each(aRootUids, (sSubUid) => { + _.each(rootUids, (sSubUid) => { Cache.storeMessageFlagsToCacheBySetAction( sFolderFullNameRaw, sSubUid, iSetAction); }); - Remote.messageSetFlagged(noop, sFolderFullNameRaw, aRootUids, false); + Remote.messageSetFlagged(noop, sFolderFullNameRaw, rootUids, false); break; // no default } @@ -985,12 +987,13 @@ class AppUser extends AbstractApp initHorizontalLayoutResizer(sClientSideKeyName) { - var - iMinHeight = 200, - iMaxHeight = 500, + let oTop = null, - oBottom = null, + oBottom = null; + const + minHeight = 200, + maxHeight = 500, fSetHeight = (height) => { if (height) { @@ -1009,9 +1012,7 @@ class AppUser extends AbstractApp fResizeCreateFunction = (event) => { if (event && event.target) { - var oResizableHandle = $(event.target).find('.ui-resizable-handle'); - - oResizableHandle + $(event.target).find('.ui-resizable-handle') .on('mousedown', () => { $html.addClass('rl-resizer'); }) @@ -1043,8 +1044,8 @@ class AppUser extends AbstractApp oOptions = { helper: 'ui-resizable-helper-h', - minHeight: iMinHeight, - maxHeight: iMaxHeight, + minHeight: minHeight, + maxHeight: maxHeight, handles: 's', create: fResizeCreateFunction, resize: fResizeResizeFunction, @@ -1078,7 +1079,7 @@ class AppUser extends AbstractApp } const iHeight = pInt(Local.get(sClientSideKeyName)) || 300; - fSetHeight(iHeight > iMinHeight ? iHeight : iMinHeight); + fSetHeight(iHeight > minHeight ? iHeight : minHeight); } }; @@ -1091,11 +1092,11 @@ class AppUser extends AbstractApp initVerticalLayoutResizer(sClientSideKeyName) { - var - iDisabledWidth = 60, - iMinWidth = 155, - oLeft = $('#rl-left'), - oRight = $('#rl-right'), + const + disabledWidth = 60, + minWidth = 155, + lLeft = $('#rl-left'), + right = $('#rl-right'), mLeftWidth = Local.get(sClientSideKeyName) || null, @@ -1106,11 +1107,11 @@ class AppUser extends AbstractApp $html.removeClass('rl-resizer'); - oLeft.css({ + lLeft.css({ width: '' + iWidth + 'px' }); - oRight.css({ + right.css({ left: '' + iWidth + 'px' }); } @@ -1119,14 +1120,14 @@ class AppUser extends AbstractApp fDisable = (bDisable) => { if (bDisable) { - oLeft.resizable('disable'); - fSetWidth(iDisabledWidth); + lLeft.resizable('disable'); + fSetWidth(disabledWidth); } else { - oLeft.resizable('enable'); - var iWidth = pInt(Local.get(sClientSideKeyName)) || iMinWidth; - fSetWidth(iWidth > iMinWidth ? iWidth : iMinWidth); + lLeft.resizable('enable'); + const width = pInt(Local.get(sClientSideKeyName)) || minWidth; + fSetWidth(width > minWidth ? width : minWidth); } }, @@ -1156,11 +1157,11 @@ class AppUser extends AbstractApp leftPanelWidth(oObject.size.width); - oRight.css({ + right.css({ left: '' + oObject.size.width + 'px' }); - oLeft.css({ + lLeft.css({ position: '', top: '', left: '', @@ -1171,12 +1172,12 @@ class AppUser extends AbstractApp if (null !== mLeftWidth) { - fSetWidth(mLeftWidth > iMinWidth ? mLeftWidth : iMinWidth); + fSetWidth(mLeftWidth > minWidth ? mLeftWidth : minWidth); } - oLeft.resizable({ + lLeft.resizable({ helper: 'ui-resizable-helper-w', - minWidth: iMinWidth, + minWidth: minWidth, maxWidth: 350, handles: 'e', create: fResizeCreateFunction, @@ -1229,7 +1230,7 @@ class AppUser extends AbstractApp setHash(Links.root(), true); routeOff(); - _.defer(function() { + _.defer(() => { window.location.href = customLoginLink; }); } @@ -1253,13 +1254,15 @@ class AppUser extends AbstractApp require('Stores/User/Account').populate(); require('Stores/User/Contact').populate(); - var - sJsHash = Settings.appSettingsGet('jsHash'), - sStartupUrl = pString(Settings.settingsGet('StartupUrl')), - iContactsSyncInterval = pInt(Settings.settingsGet('ContactsSyncInterval')), - bGoogle = Settings.settingsGet('AllowGoogleSocial'), - bFacebook = Settings.settingsGet('AllowFacebookSocial'), - bTwitter = Settings.settingsGet('AllowTwitterSocial'); + let + contactsSyncInterval = pInt(Settings.settingsGet('ContactsSyncInterval')); + + const + jsHash = Settings.appSettingsGet('jsHash'), + startupUrl = pString(Settings.settingsGet('StartupUrl')), + allowGoogle = Settings.settingsGet('AllowGoogleSocial'), + allowFacebook = Settings.settingsGet('AllowFacebookSocial'), + allowTwitter = Settings.settingsGet('AllowTwitterSocial'); if (progressJs) { @@ -1294,14 +1297,14 @@ class AppUser extends AbstractApp if (value) { - if ('' !== sStartupUrl) + if ('' !== startupUrl) { routeOff(); - setHash(Links.root(sStartupUrl), true); + setHash(Links.root(startupUrl), true); routeOn(); } - if (window.jassl && window.crypto && window.crypto.getRandomValues && Settings.capa(Capa.OpenPGP)) + if (jassl && window.crypto && window.crypto.getRandomValues && Settings.capa(Capa.OpenPGP)) { const openpgpCallback = (openpgp) => { @@ -1333,7 +1336,7 @@ class AppUser extends AbstractApp } else { - window.jassl(Links.openPgpJs()).then(() => { + jassl(Links.openPgpJs()).then(() => { if (window.openpgp) { openpgpCallback(window.openpgp); @@ -1352,7 +1355,7 @@ class AppUser extends AbstractApp // false ? AboutUserScreen : null ]); - if (bGoogle || bFacebook || bTwitter) + if (allowGoogle || allowFacebook || allowTwitter) { this.socialUsers(true); } @@ -1370,13 +1373,13 @@ class AppUser extends AbstractApp Events.sub('interval.15m', () => this.quota()); Events.sub('interval.20m', () => this.foldersReload()); - iContactsSyncInterval = 5 <= iContactsSyncInterval ? iContactsSyncInterval : 20; - iContactsSyncInterval = 320 >= iContactsSyncInterval ? iContactsSyncInterval : 320; + contactsSyncInterval = 5 <= contactsSyncInterval ? contactsSyncInterval : 20; + contactsSyncInterval = 320 >= contactsSyncInterval ? contactsSyncInterval : 320; _.delay(() => this.contactsSync(), 10000); _.delay(() => this.folderInformationMultiply(true), 2000); - window.setInterval(() => this.contactsSync(), iContactsSyncInterval * 60000 + 5000); + window.setInterval(() => this.contactsSync(), contactsSyncInterval * 60000 + 5000); this.accountsAndIdentities(true); @@ -1451,25 +1454,25 @@ class AppUser extends AbstractApp this.bootstartLoginScreen(); } - if (bGoogle) + if (allowGoogle) { - window['rl_' + sJsHash + '_google_service'] = () => { + window['rl_' + jsHash + '_google_service'] = () => { SocialStore.google.loading(true); this.socialUsers(); }; } - if (bFacebook) + if (allowFacebook) { - window['rl_' + sJsHash + '_facebook_service'] = () => { + window['rl_' + jsHash + '_facebook_service'] = () => { SocialStore.facebook.loading(true); this.socialUsers(); }; } - if (bTwitter) + if (allowTwitter) { - window['rl_' + sJsHash + '_twitter_service'] = () => { + window['rl_' + jsHash + '_twitter_service'] = () => { SocialStore.twitter.loading(true); this.socialUsers(); }; diff --git a/dev/Common/Audio.js b/dev/Common/Audio.js index e989478ce..720f283b8 100644 --- a/dev/Common/Audio.js +++ b/dev/Common/Audio.js @@ -39,7 +39,6 @@ class Audio if (this.supported) { $(this.player).on('ended error', () => this.stop()); - Events.sub('audio.api.stop', () => this.stop()); } } diff --git a/dev/Common/Booter.js b/dev/Common/Booter.js index 0c62170d3..cbabd1a94 100644 --- a/dev/Common/Booter.js +++ b/dev/Common/Booter.js @@ -1,11 +1,11 @@ +/* global RL_ES6 */ + import window from 'window'; import progressJs from 'progressJs'; import Promise from 'Promise'; -import STYLES_CSS from 'Styles/@Boot.css'; -import LAYOUT_HTML from 'Html/Layout.html'; - +import {jassl} from 'Common/Jassl'; import {getHash, setHash, clearHash} from 'Storage/RainLoop'; let RL_APP_DATA_STORAGE = null; @@ -64,7 +64,7 @@ class Q2 extends Q1 { constructor() { super() } } */ function getComputedStyle(id, name) { - var element = window.document.getElementById(id); + const element = window.document.getElementById(id); return element.currentStyle ? element.currentStyle[name] : (window.getComputedStyle ? window.getComputedStyle(element, null).getPropertyValue(name) : null); } @@ -94,14 +94,11 @@ function includeLayout() { const app = window.document.getElementById('rl-app'); - if (STYLES_CSS) - { - includeStyle(STYLES_CSS); - } + require('style-loader!Styles/@Boot.css'); - if (app && LAYOUT_HTML) + if (app) { - app.innerHTML = LAYOUT_HTML.replace(/[\r\n\t]+/g, ''); + app.innerHTML = require('Html/Layout.html').replace(/[\r\n\t]+/g, ''); return true; } @@ -223,7 +220,7 @@ function runApp() { const appData = window.__rlah_data(); - if (window.jassl && progressJs && appData && appData.TemplatesLink && appData.LangLink && + if (jassl && progressJs && appData && appData.TemplatesLink && appData.LangLink && appData.StaticLibJsLink && appData.StaticAppJsLink && appData.StaticAppJsNextLink && appData.StaticEditorJsLink) { const p = progressJs; @@ -232,7 +229,7 @@ function runApp() p.start().set(5); const - libs = window.jassl(appData.StaticLibJsLink).then(() => { + libs = jassl(appData.StaticLibJsLink).then(() => { if (window.$) { window.$('#rl-check').remove(); @@ -247,18 +244,18 @@ function runApp() } }), common = Promise.all([ - window.jassl(appData.TemplatesLink), - window.jassl(appData.LangLink) + jassl(appData.TemplatesLink), + jassl(appData.LangLink) ]); Promise.all([libs, common]) .then(() => { p.set(30); - return window.jassl(useJsNextBundle ? appData.StaticAppJsNextLink : appData.StaticAppJsLink); + return jassl(useJsNextBundle ? appData.StaticAppJsNextLink : appData.StaticAppJsLink); }) .then(() => { p.set(50); - return appData.PluginsLink ? window.jassl(appData.PluginsLink) : window.Promise.resolve(); + return appData.PluginsLink ? jassl(appData.PluginsLink) : window.Promise.resolve(); }) .then(() => { p.set(70); @@ -268,7 +265,7 @@ function runApp() runMainBoot(true); throw e; }) - .then(() => window.jassl(appData.StaticEditorJsLink)) + .then(() => jassl(appData.StaticEditorJsLink)) .then(() => { if (window.CKEDITOR && window.__initEditor) { window.__initEditor(); @@ -320,7 +317,7 @@ window.__runBoot = function() { window.document.location.replace('./?/NoCookie'); } - const root = document.documentElement; + const root = window.document.documentElement; if ('none' !== getComputedStyle('rl-check', 'display')) { root.className += ' no-css'; diff --git a/dev/Common/Globals.js b/dev/Common/Globals.js index 8684c777e..ff4d72baa 100644 --- a/dev/Common/Globals.js +++ b/dev/Common/Globals.js @@ -1,4 +1,6 @@ +/* global RL_COMMUNITY */ + import window from 'window'; import _ from '_'; import $ from '$'; @@ -167,9 +169,7 @@ let bAllowPdfPreview = !bMobileDevice; if (bAllowPdfPreview && window.navigator && window.navigator.mimeTypes) { - bAllowPdfPreview = !!_.find(window.navigator.mimeTypes, function(oType) { - return oType && 'application/pdf' === oType.type; - }); + bAllowPdfPreview = !!_.find(window.navigator.mimeTypes, (type) => type && 'application/pdf' === type.type); if (!bAllowPdfPreview) { @@ -203,33 +203,29 @@ export const keyScopeReal = ko.observable(KeyState.All); export const keyScopeFake = ko.observable(KeyState.All); export const keyScope = ko.computed({ - owner: this, read: () => keyScopeFake(), - write: function(sValue) { + write: (value) => { - if (KeyState.Menu !== sValue) + if (KeyState.Menu !== value) { - if (KeyState.Compose === sValue) + if (KeyState.Compose === value) { // disableKeyFilter - key.filter = function() { - return useKeyboardShortcuts(); - }; + key.filter = () => useKeyboardShortcuts(); } else { // restoreKeyFilter - key.filter = function(event) { + key.filter = (event) => { if (useKeyboardShortcuts()) { - var - oElement = event.target || event.srcElement, - sTagName = oElement ? oElement.tagName : ''; + const + el = event.target || event.srcElement, + tagName = el ? el.tagName.toUpperCase() : ''; - sTagName = sTagName.toUpperCase(); - return !('INPUT' === sTagName || 'SELECT' === sTagName || 'TEXTAREA' === sTagName || - (oElement && 'DIV' === sTagName && ('editorHtmlArea' === oElement.className || 'true' === '' + oElement.contentEditable)) + return !('INPUT' === tagName || 'SELECT' === tagName || 'TEXTAREA' === tagName || + (el && 'DIV' === tagName && ('editorHtmlArea' === el.className || 'true' === '' + el.contentEditable)) ); } @@ -237,24 +233,24 @@ export const keyScope = ko.computed({ }; } - keyScopeFake(sValue); + keyScopeFake(value); if (dropdownVisibility()) { - sValue = KeyState.Menu; + value = KeyState.Menu; } } - keyScopeReal(sValue); + keyScopeReal(value); } }); -keyScopeReal.subscribe(function(sValue) { +keyScopeReal.subscribe((value) => { // window.console.log('keyScope=' + sValue); // DEBUG - key.setScope(sValue); + key.setScope(value); }); -dropdownVisibility.subscribe(function(bValue) { - if (bValue) +dropdownVisibility.subscribe((value) => { + if (value) { keyScope(KeyState.Menu); } diff --git a/dev/Common/HtmlEditor.js b/dev/Common/HtmlEditor.js index 0f3393918..2f5a1962a 100644 --- a/dev/Common/HtmlEditor.js +++ b/dev/Common/HtmlEditor.js @@ -87,20 +87,11 @@ class HtmlEditor } } - /** - * @param {string} text - * @returns {string} - */ - clearSignatureSigns(text) { - return text.replace(/(\u200C|\u0002)/g, ''); - } - /** * @param {boolean=} wrapIsHtml = false - * @param {boolean=} clearSignatureSigns = false * @returns {string} */ - getData(wrapIsHtml = false, clearSignatureSigns = false) { + getData(wrapIsHtml = false) { let result = ''; if (this.editor) @@ -119,11 +110,6 @@ class HtmlEditor } } catch (e) {} // eslint-disable-line no-empty - - if (clearSignatureSigns) - { - result = this.clearSignatureSigns(result); - } } return result; @@ -131,11 +117,10 @@ class HtmlEditor /** * @param {boolean=} wrapIsHtml = false - * @param {boolean=} clearSignatureSigns = false * @returns {string} */ - getDataWithHtmlMark(wrapIsHtml = false, clearSignatureSigns = false) { - return (this.isHtml() ? ':HTML:' : '') + this.getData(wrapIsHtml, clearSignatureSigns); + getDataWithHtmlMark(wrapIsHtml = false) { + return (this.isHtml() ? ':HTML:' : '') + this.getData(wrapIsHtml); } modeToggle(plain, resize) { @@ -149,12 +134,9 @@ class HtmlEditor this.editor.setMode('wysiwyg'); } } - else + else if ('wysiwyg' === this.editor.mode) { - if ('wysiwyg' === this.editor.mode) - { - this.editor.setMode('plain'); - } + this.editor.setMode('plain'); } } catch (e) {} // eslint-disable-line no-empty @@ -302,7 +284,7 @@ class HtmlEditor if (file && window.FileReader && event.data.dataTransfer.id && file.type && file.type.match(/^image/i)) { - var + const id = event.data.dataTransfer.id, imageId = `[img=${id}]`, reader = new window.FileReader(); diff --git a/dev/Common/Jassl.js b/dev/Common/Jassl.js new file mode 100644 index 000000000..8da12eca3 --- /dev/null +++ b/dev/Common/Jassl.js @@ -0,0 +1,54 @@ + +import window from 'window'; +import Promise from 'Promise'; + +// let rainloopCaches = window.caches && window.caches.open ? window.caches : null; + +/** + * @param {src} src + * @param {boolean} async = false + * @returns {Promise} + */ +export function jassl(src, async = false) { + + if (!Promise || !Promise.all) + { + throw new Error('Promises are not available your environment.'); + } + + if (!src) + { + throw new Error('src should not be empty.'); + } + + return new Promise((resolve, reject) => { + + const element = window.document.createElement('script'); + + element.onload = () => { + resolve(src); + }; + + element.onerror = () => { + reject(new Error(src)); + }; + + element.async = true === async; + element.src = src; + + window.document.body.appendChild(element); + })/* .then((s) => { + + const found = s && rainloopCaches ? s.match(/rainloop\/v\/([^\/]+)\/static\//) : null; + if (found && found[1]) + { + rainloopCaches.open('rainloop-offline-' + found[1]).then( + (cache) => cache.add(s) + ).catch(() => { + rainloopCaches = null; + }); + } + + return s; + })*/; +} diff --git a/dev/Common/Momentor.js b/dev/Common/Momentor.js index 61547ecb0..35853f30d 100644 --- a/dev/Common/Momentor.js +++ b/dev/Common/Momentor.js @@ -125,9 +125,10 @@ export function format(timeStampInUTC, formatStr) */ export function momentToNode(element) { - var + let key = '', - time = 0, + time = 0; + const $el = $(element); time = $el.data('moment-time'); diff --git a/dev/Common/Selector.js b/dev/Common/Selector.js index 33baa8cd9..bd40637e4 100644 --- a/dev/Common/Selector.js +++ b/dev/Common/Selector.js @@ -159,14 +159,16 @@ class Selector this.list.subscribe((aItems) => { - var - oTemp = null, - bGetNext = false, - aUids = [], - mNextFocused = mFocused, - bChecked = false, - bSelected = false, - iLen = 0; + let + temp = null, + getNext = false, + isNextFocused = mFocused, + isChecked = false, + isSelected = false, + len = 0; + + const + uids = []; this.selectedItemUseCallback = false; @@ -175,37 +177,37 @@ class Selector if (isArray(aItems)) { - iLen = aCheckedCache.length; + len = aCheckedCache.length; - _.each(aItems, (oItem) => { + _.each(aItems, (item) => { - var sUid = this.getItemUid(oItem); - aUids.push(sUid); + const uid = this.getItemUid(item); + uids.push(uid); - if (null !== mFocused && mFocused === sUid) + if (null !== mFocused && mFocused === uid) { - this.focusedItem(oItem); + this.focusedItem(item); mFocused = null; } - if (0 < iLen && -1 < inArray(sUid, aCheckedCache)) + if (0 < len && -1 < inArray(uid, aCheckedCache)) { - bChecked = true; - oItem.checked(true); - iLen -= 1; + isChecked = true; + item.checked(true); + len -= 1; } - if (!bChecked && null !== mSelected && mSelected === sUid) + if (!isChecked && null !== mSelected && mSelected === uid) { - bSelected = true; - this.selectedItem(oItem); + isSelected = true; + this.selectedItem(item); mSelected = null; } }); this.selectedItemUseCallback = true; - if (!bChecked && !bSelected && this.autoSelect()) + if (!isChecked && !isSelected && this.autoSelect()) { if (this.focusedItem()) { @@ -213,53 +215,53 @@ class Selector } else if (0 < aItems.length) { - if (null !== mNextFocused) + if (null !== isNextFocused) { - bGetNext = false; - mNextFocused = _.find(aCache, (sUid) => { - if (bGetNext && -1 < inArray(sUid, aUids)) + getNext = false; + isNextFocused = _.find(aCache, (sUid) => { + if (getNext && -1 < inArray(sUid, uids)) { return sUid; } - else if (mNextFocused === sUid) + else if (isNextFocused === sUid) { - bGetNext = true; + getNext = true; } return false; }); - if (mNextFocused) + if (isNextFocused) { - oTemp = _.find(aItems, (oItem) => mNextFocused === this.getItemUid(oItem)); + temp = _.find(aItems, (oItem) => isNextFocused === this.getItemUid(oItem)); } } - this.selectedItem(oTemp || null); + this.selectedItem(temp || null); this.focusedItem(this.selectedItem()); } } if ((0 !== this.iSelectNextHelper || 0 !== this.iFocusedNextHelper) && 0 < aItems.length && !this.focusedItem()) { - oTemp = null; + temp = null; if (0 !== this.iFocusedNextHelper) { - oTemp = aItems[-1 === this.iFocusedNextHelper ? aItems.length - 1 : 0] || null; + temp = aItems[-1 === this.iFocusedNextHelper ? aItems.length - 1 : 0] || null; } - if (!oTemp && 0 !== this.iSelectNextHelper) + if (!temp && 0 !== this.iSelectNextHelper) { - oTemp = aItems[-1 === this.iSelectNextHelper ? aItems.length - 1 : 0] || null; + temp = aItems[-1 === this.iSelectNextHelper ? aItems.length - 1 : 0] || null; } - if (oTemp) + if (temp) { if (0 !== this.iSelectNextHelper) { - this.selectedItem(oTemp || null); + this.selectedItem(temp || null); } - this.focusedItem(oTemp || null); + this.focusedItem(temp || null); this.scrollToFocused(); @@ -288,12 +290,9 @@ class Selector (this.oCallbacks.onItemSelect || noop)(item || null); } } - else + else if (item) { - if (item) - { - (this.oCallbacks.onItemSelect || noop)(item); - } + (this.oCallbacks.onItemSelect || noop)(item); } } @@ -446,62 +445,64 @@ class Selector */ newSelectPosition(iEventKeyCode, bShiftKey, bForceSelect) { - var - iIndex = 0, - iPageStep = 10, - bNext = false, - bStop = false, - oResult = null, - aList = this.list(), - iListLen = aList ? aList.length : 0, - oFocused = this.focusedItem(); + let + index = 0, + isNext = false, + isStop = false, + result = null; - if (0 < iListLen) + const + pageStep = 10, + list = this.list(), + listLen = list ? list.length : 0, + focused = this.focusedItem(); + + if (0 < listLen) { - if (!oFocused) + if (!focused) { if (EventKeyCode.Down === iEventKeyCode || EventKeyCode.Insert === iEventKeyCode || EventKeyCode.Space === iEventKeyCode || EventKeyCode.Home === iEventKeyCode || EventKeyCode.PageUp === iEventKeyCode) { - oResult = aList[0]; + result = list[0]; } else if (EventKeyCode.Up === iEventKeyCode || EventKeyCode.End === iEventKeyCode || EventKeyCode.PageDown === iEventKeyCode) { - oResult = aList[aList.length - 1]; + result = list[list.length - 1]; } } - else if (oFocused) + else if (focused) { if (EventKeyCode.Down === iEventKeyCode || EventKeyCode.Up === iEventKeyCode || EventKeyCode.Insert === iEventKeyCode || EventKeyCode.Space === iEventKeyCode) { - _.each(aList, (item) => { - if (!bStop) + _.each(list, (item) => { + if (!isStop) { switch (iEventKeyCode) { case EventKeyCode.Up: - if (oFocused === item) + if (focused === item) { - bStop = true; + isStop = true; } else { - oResult = item; + result = item; } break; case EventKeyCode.Down: case EventKeyCode.Insert: - if (bNext) + if (isNext) { - oResult = item; - bStop = true; + result = item; + isStop = true; } - else if (oFocused === item) + else if (focused === item) { - bNext = true; + isNext = true; } break; // no default @@ -509,7 +510,7 @@ class Selector } }); - if (!oResult && (EventKeyCode.Down === iEventKeyCode || EventKeyCode.Up === iEventKeyCode)) + if (!result && (EventKeyCode.Down === iEventKeyCode || EventKeyCode.Up === iEventKeyCode)) { this.doUpUpOrDownDown(EventKeyCode.Up === iEventKeyCode); } @@ -518,35 +519,35 @@ class Selector { if (EventKeyCode.Home === iEventKeyCode) { - oResult = aList[0]; + result = list[0]; } else if (EventKeyCode.End === iEventKeyCode) { - oResult = aList[aList.length - 1]; + result = list[list.length - 1]; } } else if (EventKeyCode.PageDown === iEventKeyCode) { - for (; iIndex < iListLen; iIndex++) + for (; index < listLen; index++) { - if (oFocused === aList[iIndex]) + if (focused === list[index]) { - iIndex += iPageStep; - iIndex = iListLen - 1 < iIndex ? iListLen - 1 : iIndex; - oResult = aList[iIndex]; + index += pageStep; + index = listLen - 1 < index ? listLen - 1 : index; + result = list[index]; break; } } } else if (EventKeyCode.PageUp === iEventKeyCode) { - for (iIndex = iListLen; 0 <= iIndex; iIndex--) + for (index = listLen; 0 <= index; index--) { - if (oFocused === aList[iIndex]) + if (focused === list[index]) { - iIndex -= iPageStep; - iIndex = 0 > iIndex ? 0 : iIndex; - oResult = aList[iIndex]; + index -= pageStep; + index = 0 > index ? 0 : index; + result = list[index]; break; } } @@ -554,45 +555,45 @@ class Selector } } - if (oResult) + if (result) { - this.focusedItem(oResult); + this.focusedItem(result); - if (oFocused) + if (focused) { if (bShiftKey) { if (EventKeyCode.Up === iEventKeyCode || EventKeyCode.Down === iEventKeyCode) { - oFocused.checked(!oFocused.checked()); + focused.checked(!focused.checked()); } } else if (EventKeyCode.Insert === iEventKeyCode || EventKeyCode.Space === iEventKeyCode) { - oFocused.checked(!oFocused.checked()); + focused.checked(!focused.checked()); } } if ((this.autoSelect() || !!bForceSelect) && !this.isListChecked() && EventKeyCode.Space !== iEventKeyCode) { - this.selectedItem(oResult); + this.selectedItem(result); } this.scrollToFocused(); } - else if (oFocused) + else if (focused) { if (bShiftKey && (EventKeyCode.Up === iEventKeyCode || EventKeyCode.Down === iEventKeyCode)) { - oFocused.checked(!oFocused.checked()); + focused.checked(!focused.checked()); } else if (EventKeyCode.Insert === iEventKeyCode || EventKeyCode.Space === iEventKeyCode) { - oFocused.checked(!oFocused.checked()); + focused.checked(!focused.checked()); } - this.focusedItem(oFocused); + this.focusedItem(focused); } } diff --git a/dev/Common/Utils.js b/dev/Common/Utils.js index 31a458ae3..0b90f8442 100644 --- a/dev/Common/Utils.js +++ b/dev/Common/Utils.js @@ -6,6 +6,7 @@ import ko from 'ko'; import {$win, $div, dropdownVisibility, data as GlobalsData} from 'Common/Globals'; import {ComposeType, EventKeyCode, SaveSettingsStep, FolderType} from 'Common/Enums'; import {Mime} from 'Common/Mime'; +import {jassl} from 'Common/Jassl'; import Autolinker from 'Autolinker'; @@ -22,7 +23,7 @@ const noop = () => {}; // eslint-disable-line no-empty-function const noopTrue = () => true; const noopFalse = () => false; -export {trim, inArray, isArray, isObject, isFunc, isUnd, isNull, has, bind, noop, noopTrue, noopFalse}; +export {trim, inArray, isArray, isObject, isFunc, isUnd, isNull, has, bind, noop, noopTrue, noopFalse, jassl}; /** * @param {Function} func @@ -490,7 +491,7 @@ export function killCtrlACtrlS(event) * @param {(Function|boolean|null)=} fCanExecute = true * @returns {Function} */ -export function createCommand(context, fExecute, fCanExecute = true) +export function createCommandLegacy(context, fExecute, fCanExecute = true) { let fResult = null; const fNonEmpty = (...args) => { @@ -516,6 +517,16 @@ export function createCommand(context, fExecute, fCanExecute = true) return fResult; } +/** + * @param {Function} fExecute + * @param {(Function|boolean|null)=} fCanExecute = true + * @returns {Function} + */ +export function createCommand(fExecute, fCanExecute = true) +{ + return createCommandLegacy(null, fExecute, fCanExecute); +} + /** * @param {string} theme * @returns {string} @@ -609,12 +620,13 @@ export function clearBqSwitcher(body) } /** - * @param {string} title + * @param {object} messageData * @param {Object} body * @param {boolean} isHtml * @param {boolean} print + * @returns {void} */ -export function previewMessage(title, body, isHtml, print) +export function previewMessage({title, subject, date, fromCreds, toCreds, toLabel}, body, isHtml, print) { const win = window.open(''), @@ -626,81 +638,16 @@ export function previewMessage(title, body, isHtml, print) const html = bodyClone ? bodyClone.html() : ''; - title = encodeHtml(title); - - doc.write(` - - - - - - ${title} - - -${html} -`); + doc.write(require('Html/PreviewMessage.html') + .replace('{{title}}', encodeHtml(title)) + .replace('{{subject}}', encodeHtml(subject)) + .replace('{{date}}', encodeHtml(date)) + .replace('{{fromCreds}}', encodeHtml(fromCreds)) + .replace('{{toCreds}}', encodeHtml(toCreds)) + .replace('{{toLabel}}', encodeHtml(toLabel)) + .replace('{{bodyClass}}', bodyClass) + .replace('{{html}}', html) + ); doc.close(); @@ -851,7 +798,6 @@ export function htmlToPlain(html) convertLinks = (...args) => (args && 1 < args.length ? trim(args[1]) : ''); text = html - .replace(/\u0002([\s\S]*)\u0002/gm, '\u200C$1\u200C') .replace(/]*><\/p>/gi, '') .replace(/]*>([\s\S\r\n\t]*)<\/pre>/gmi, convertPre) .replace(/[\s]+/gm, ' ') @@ -1003,7 +949,6 @@ export function plainToHtml(plain, findEmailAndLinksInText = false) .replace(/>/g, '>').replace(/') .replace(/[\s]*~~~\/blockquote~~~/g, '') - .replace(/\u200C([\s\S]*)\u200C/g, '\u0002$1\u0002') .replace(/\n/g, '
'); return findEmailAndLinksInText ? findEmailAndLinks(plain) : plain; @@ -1520,7 +1465,7 @@ export function mimeContentType(fileName) */ export function resizeAndCrop(url, value, fCallback) { - const img = new Image(); + const img = new window.Image(); img.onload = function() { let diff --git a/dev/Component/AbstractInput.js b/dev/Component/AbstractInput.js index 6de292a89..86067f235 100644 --- a/dev/Component/AbstractInput.js +++ b/dev/Component/AbstractInput.js @@ -29,15 +29,11 @@ class AbstractInput extends AbstractComponent this.classForTrigger = ko.observable(''); this.className = ko.computed(() => { - - var + const size = ko.unwrap(this.size), - suffixValue = this.trigger ? - ' ' + trim('settings-saved-trigger-input ' + this.classForTrigger()) : ''; - + suffixValue = this.trigger ? ' ' + trim('settings-saved-trigger-input ' + this.classForTrigger()) : ''; return (0 < size ? 'span' + size : '') + suffixValue; - - }, this); + }); if (!isUnd(params.width) && params.element) { diff --git a/dev/External/Opentip.js b/dev/External/Opentip.js index d6530746a..d47276068 100644 --- a/dev/External/Opentip.js +++ b/dev/External/Opentip.js @@ -1,7 +1,9 @@ -var - window = require('window'), - Opentip = window.Opentip; +import window from 'window'; + +const Opentip = window.Opentip || {}; + +Opentip.styles = Opentip.styles || {}; Opentip.styles.rainloop = { @@ -41,4 +43,4 @@ Opentip.styles.rainloopErrorTip = { 'className': 'rainloopErrorTip' }; -module.exports = Opentip; +export {Opentip, Opentip as default}; diff --git a/dev/External/ko.js b/dev/External/ko.js index c18c768bd..4e57f33f2 100644 --- a/dev/External/ko.js +++ b/dev/External/ko.js @@ -1,115 +1,113 @@ -var - window = require('window'), +import window from 'window'; +import _ from '_'; +import $ from '$'; +import Opentip from 'Opentip'; +import Pikaday from 'pikaday'; + +import {SaveSettingsStep, Magics} from 'Common/Enums'; + +const ko = window.ko, - _ = require('_'), - $ = require('$'), - Opentip = require('Opentip'), - Pikaday = require('pikaday'), - - fDisposalTooltipHelper = function(oElement) { - ko.utils.domNodeDisposal.addDisposeCallback(oElement, function() { - if (oElement && oElement.__opentip) + $win = $(window), + fDisposalTooltipHelper = (element) => { + ko.utils.domNodeDisposal.addDisposeCallback(element, () => { + if (element && element.__opentip) { - oElement.__opentip.deactivate(); + element.__opentip.deactivate(); } }); }; ko.bindingHandlers.updateWidth = { - init: function(oElement, fValueAccessor) { - var - $w = $(window), - $oEl = $(oElement), + init: (element, fValueAccessor) => { + const + $el = $(element), fValue = fValueAccessor(), - fInit = function() { - fValue($oEl.width()); - window.setTimeout(function() { - fValue($oEl.width()); - }, 500); + fInit = () => { + fValue($el.width()); + window.setTimeout(() => { + fValue($el.width()); + }, Magics.Time500ms); }; - $w.on('resize', fInit); + $win.on('resize', fInit); fInit(); - ko.utils.domNodeDisposal.addDisposeCallback(oElement, function() { - $w.off('resize', fInit); + ko.utils.domNodeDisposal.addDisposeCallback(element, () => { + $win.off('resize', fInit); }); } }; ko.bindingHandlers.editor = { - init: function(oElement, fValueAccessor) { + init: (element, fValueAccessor) => { - var - oEditor = null, + let editor = null; + + const fValue = fValueAccessor(), - - fUpdateEditorValue = function() { + HtmlEditor = require('Common/HtmlEditor').default, + fUpdateEditorValue = () => { if (fValue && fValue.__editor) { fValue.__editor.setHtmlOrPlain(fValue()); } }, - - fUpdateKoValue = function() { + fUpdateKoValue = () => { if (fValue && fValue.__editor) { fValue(fValue.__editor.getDataWithHtmlMark()); } }, - - fOnReady = function() { - fValue.__editor = oEditor; + fOnReady = () => { + fValue.__editor = editor; fUpdateEditorValue(); - }, - - HtmlEditor = require('Common/HtmlEditor').default; + }; if (ko.isObservable(fValue) && HtmlEditor) { - oEditor = new HtmlEditor(oElement, fUpdateKoValue, fOnReady, fUpdateKoValue); + editor = new HtmlEditor(element, fUpdateKoValue, fOnReady, fUpdateKoValue); fValue.__fetchEditorValue = fUpdateKoValue; fValue.subscribe(fUpdateEditorValue); -// ko.utils.domNodeDisposal.addDisposeCallback(oElement, function() { -// }); +// ko.utils.domNodeDisposal.addDisposeCallback(element, () => { +// }); } } }; ko.bindingHandlers.json = { - init: function(oElement, fValueAccessor) { - $(oElement).text(window.JSON.stringify(ko.unwrap(fValueAccessor()))); + init: (element, fValueAccessor) => { + $(element).text(window.JSON.stringify(ko.unwrap(fValueAccessor()))); }, - update: function(oElement, fValueAccessor) { - $(oElement).text(window.JSON.stringify(ko.unwrap(fValueAccessor()))); + update: (element, fValueAccessor) => { + $(element).text(window.JSON.stringify(ko.unwrap(fValueAccessor()))); } }; ko.bindingHandlers.scrollerShadows = { - init: function(oElement) { + init: (element) => { - var - iLimit = 8, - $oEl = $(oElement), - $win = $(window), - oCont = $oEl.find('[data-scroller-shadows-content]')[0] || null, - fFunc = _.throttle(function() { - $oEl - .toggleClass('scroller-shadow-top', iLimit < oCont.scrollTop) - .toggleClass('scroller-shadow-bottom', oCont.scrollTop + iLimit < oCont.scrollHeight - oCont.clientHeight); + const + limit = 8, + $el = $(element), + cont = $el.find('[data-scroller-shadows-content]')[0] || null, + fFunc = _.throttle(() => { + $el + .toggleClass('scroller-shadow-top', limit < cont.scrollTop) + .toggleClass('scroller-shadow-bottom', cont.scrollTop + limit < cont.scrollHeight - cont.clientHeight); }, 100); - if (oCont) + if (cont) { - $(oCont).on('scroll resize', fFunc); + $(cont).on('scroll resize', fFunc); $win.on('resize', fFunc); - ko.utils.domNodeDisposal.addDisposeCallback(oCont, function() { - $(oCont).off(); + ko.utils.domNodeDisposal.addDisposeCallback(cont, () => { + $(cont).off(); $win.off('resize', fFunc); }); } @@ -117,197 +115,217 @@ ko.bindingHandlers.scrollerShadows = { }; ko.bindingHandlers.pikaday = { - init: function(oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) { + init: (element, fValueAccessor, fAllBindingsAccessor, viewModel, bindingContext) => { - ko.bindingHandlers.textInput - .init.apply(oViewModel, Array.prototype.slice.call(arguments)); // eslint-disable-line prefer-rest-params + ko.bindingHandlers.textInput.init(element, fValueAccessor, fAllBindingsAccessor, viewModel, bindingContext); if (Pikaday) { - oElement.__pikaday = new Pikaday({ - field: oElement + element.__pikaday = new Pikaday({ + field: element }); } } }; -ko.bindingHandlers.tooltip = { - init: function(oElement, fValueAccessor) { +ko.bindingHandlers.visibleAnimated = { + init: (element, fValueAccessor) => { + const $el = $(element); + $el.addClass('rl-animated-visible'); + if (ko.unwrap(fValueAccessor())) { + $el.how(); + } else { + $el.hide(); + } + }, + update: (element, fValueAccessor) => { + const $el = $(element); + if (ko.unwrap(fValueAccessor())) { + $el.addClass('rl-animated-hidden').show(); + _.delay(() => { + $el.removeClass('rl-animated-hidden'); + }, 10); + } else { + $el.hide().removeClass('rl-animated-hidden'); + } + } +}; - var - sValue = '', - Translator = null, - $oEl = $(oElement), +ko.bindingHandlers.tooltip = { + init: (element, fValueAccessor) => { + + const + $el = $(element), fValue = fValueAccessor(), - bMobile = 'on' === ($oEl.data('tooltip-mobile') || 'off'), + isMobile = 'on' === ($el.data('tooltip-mobile') || 'off'), Globals = require('Common/Globals'); - if (!Globals.bMobileDevice || bMobile) + if (!Globals.bMobileDevice || isMobile) { - sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue); + const sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue); - oElement.__opentip = new Opentip(oElement, { + element.__opentip = new Opentip(element, { 'style': 'rainloopTip', - 'element': oElement, - 'tipJoint': $oEl.data('tooltip-join') || 'bottom' + 'element': element, + 'tipJoint': $el.data('tooltip-join') || 'bottom' }); - Globals.dropdownVisibility.subscribe(function(bV) { - if (bV) { - oElement.__opentip.hide(); + Globals.dropdownVisibility.subscribe((v) => { + if (v) { + element.__opentip.hide(); } }); if ('' === sValue) { - oElement.__opentip.hide(); - oElement.__opentip.deactivate(); - oElement.__opentip.setContent(''); + element.__opentip.hide(); + element.__opentip.deactivate(); + element.__opentip.setContent(''); } else { - oElement.__opentip.activate(); + element.__opentip.activate(); } - if ('on' === ($oEl.data('tooltip-i18n') || 'on')) + if ('on' === ($el.data('tooltip-i18n') || 'on')) { - Translator = require('Common/Translator'); + const Translator = require('Common/Translator'); - oElement.__opentip.setContent(Translator.i18n(sValue)); + element.__opentip.setContent(Translator.i18n(sValue)); - Translator.trigger.subscribe(function() { - oElement.__opentip.setContent(Translator.i18n(sValue)); + Translator.trigger.subscribe(() => { + element.__opentip.setContent(Translator.i18n(sValue)); }); - Globals.dropdownVisibility.subscribe(function() { - if (oElement && oElement.__opentip) + Globals.dropdownVisibility.subscribe(() => { + if (element && element.__opentip) { - oElement.__opentip.setContent(require('Common/Translator').i18n(sValue)); + element.__opentip.setContent(Translator.i18n(sValue)); } }); } else { - oElement.__opentip.setContent(sValue); + element.__opentip.setContent(sValue); } } }, - update: function(oElement, fValueAccessor) { + update: (element, fValueAccessor) => { - var - $oEl = $(oElement), + const + $el = $(element), fValue = fValueAccessor(), - bMobile = 'on' === ($oEl.data('tooltip-mobile') || 'off'), + isMobile = 'on' === ($el.data('tooltip-mobile') || 'off'), Globals = require('Common/Globals'); - if ((!Globals.bMobileDevice || bMobile) && oElement.__opentip) + if ((!Globals.bMobileDevice || isMobile) && element.__opentip) { - var sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue); + const sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue); if (sValue) { - oElement.__opentip.setContent('on' === ($oEl.data('tooltip-i18n') || 'on') ? + element.__opentip.setContent('on' === ($el.data('tooltip-i18n') || 'on') ? require('Common/Translator').i18n(sValue) : sValue); - oElement.__opentip.activate(); + element.__opentip.activate(); } else { - oElement.__opentip.hide(); - oElement.__opentip.deactivate(); - oElement.__opentip.setContent(''); + element.__opentip.hide(); + element.__opentip.deactivate(); + element.__opentip.setContent(''); } } } }; ko.bindingHandlers.tooltipErrorTip = { - init: function(oElement) { + init: function(element) { - var $oEl = $(oElement); + const $el = $(element); - oElement.__opentip = new Opentip(oElement, { - 'style': 'rainloopErrorTip', - 'hideOn': 'mouseout click', - 'element': oElement, - 'tipJoint': $oEl.data('tooltip-join') || 'top' + element.__opentip = new Opentip(element, { + style: 'rainloopErrorTip', + hideOn: 'mouseout click', + element: element, + tipJoint: $el.data('tooltip-join') || 'top' }); - oElement.__opentip.deactivate(); + element.__opentip.deactivate(); - $(window.document).on('click', function() { - if (oElement && oElement.__opentip) + $(window.document).on('click', () => { + if (element && element.__opentip) { - oElement.__opentip.hide(); + element.__opentip.hide(); } }); - fDisposalTooltipHelper(oElement); + fDisposalTooltipHelper(element); }, - update: function(oElement, fValueAccessor) { + update: (element, fValueAccessor) => { - var - $oEl = $(oElement), + const + $el = $(element), fValue = fValueAccessor(), - sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue), - oOpenTips = oElement.__opentip; + value = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue), + openTips = element.__opentip; - if (oOpenTips) + if (openTips) { - if ('' === sValue) + if ('' === value) { - oOpenTips.hide(); - oOpenTips.deactivate(); - oOpenTips.setContent(''); + openTips.hide(); + openTips.deactivate(); + openTips.setContent(''); } else { - _.delay(function() { - if ($oEl.is(':visible')) + _.delay(() => { + if ($el.is(':visible')) { - oOpenTips.setContent(sValue); - oOpenTips.activate(); - oOpenTips.show(); + openTips.setContent(value); + openTips.activate(); + openTips.show(); } else { - oOpenTips.hide(); - oOpenTips.deactivate(); - oOpenTips.setContent(''); + openTips.hide(); + openTips.deactivate(); + openTips.setContent(''); } - }, 100); + }, Magics.Time100ms); } } } }; ko.bindingHandlers.registrateBootstrapDropdown = { - init: function(oElement) { - var Globals = require('Common/Globals'); + init: (element) => { + const Globals = require('Common/Globals'); if (Globals && Globals.data.aBootstrapDropdowns) { - Globals.data.aBootstrapDropdowns.push($(oElement)); + Globals.data.aBootstrapDropdowns.push($(element)); - $(oElement).click(function() { + $(element).click(() => { require('Common/Utils').detectDropdownVisibility(); }); -// ko.utils.domNodeDisposal.addDisposeCallback(oElement, function() { -// }); +// ko.utils.domNodeDisposal.addDisposeCallback(element, () => { +// }); } } }; ko.bindingHandlers.openDropdownTrigger = { - update: function(oElement, fValueAccessor) { + update: (element, fValueAccessor) => { if (ko.unwrap(fValueAccessor())) { - var $oEl = $(oElement); - if (!$oEl.hasClass('open')) + const $el = $(element); + if (!$el.hasClass('open')) { - $oEl.find('.dropdown-toggle').dropdown('toggle'); + $el.find('.dropdown-toggle').dropdown('toggle'); } - $oEl.find('.dropdown-toggle').focus(); + $el.find('.dropdown-toggle').focus(); require('Common/Utils').detectDropdownVisibility(); fValueAccessor()(false); @@ -316,38 +334,38 @@ ko.bindingHandlers.openDropdownTrigger = { }; ko.bindingHandlers.dropdownCloser = { - init: function(oElement) { - $(oElement).closest('.dropdown').on('click', '.e-item', function() { - $(oElement).dropdown('toggle'); + init: (element) => { + $(element).closest('.dropdown').on('click', '.e-item', () => { + $(element).dropdown('toggle'); }); } }; ko.bindingHandlers.popover = { - init: function(oElement, fValueAccessor) { - $(oElement).popover(ko.unwrap(fValueAccessor())); + init: function(element, fValueAccessor) { + $(element).popover(ko.unwrap(fValueAccessor())); - ko.utils.domNodeDisposal.addDisposeCallback(oElement, function() { - $(oElement).popover('destroy'); + ko.utils.domNodeDisposal.addDisposeCallback(element, () => { + $(element).popover('destroy'); }); } }; ko.bindingHandlers.csstext = {}; -ko.bindingHandlers.csstext.init = ko.bindingHandlers.csstext.update = function(oElement, fValueAccessor) { - if (oElement && oElement.styleSheet && 'undefined' !== typeof oElement.styleSheet.cssText) +ko.bindingHandlers.csstext.init = ko.bindingHandlers.csstext.update = (element, fValueAccessor) => { + if (element && element.styleSheet && 'undefined' !== typeof element.styleSheet.cssText) { - oElement.styleSheet.cssText = ko.unwrap(fValueAccessor()); + element.styleSheet.cssText = ko.unwrap(fValueAccessor()); } else { - $(oElement).text(ko.unwrap(fValueAccessor())); + $(element).text(ko.unwrap(fValueAccessor())); } }; ko.bindingHandlers.resizecrop = { - init: function(oElement) { - $(oElement).addClass('resizecrop').resizecrop({ + init: (element) => { + $(element).addClass('resizecrop').resizecrop({ 'width': '100', 'height': '100', 'wrapperCSS': { @@ -355,9 +373,9 @@ ko.bindingHandlers.resizecrop = { } }); }, - update: function(oElement, fValueAccessor) { + update: (element, fValueAccessor) => { fValueAccessor()(); - $(oElement).resizecrop({ + $(element).resizecrop({ 'width': '100', 'height': '100' }); @@ -365,195 +383,191 @@ ko.bindingHandlers.resizecrop = { }; ko.bindingHandlers.onEnter = { - init: function(oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) { - $(oElement).on('keypress.koOnEnter', function(oEvent) { - if (oEvent && 13 === window.parseInt(oEvent.keyCode, 10)) + init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => { + $(element).on('keypress.koOnEnter', (event) => { + if (event && 13 === window.parseInt(event.keyCode, 10)) { - $(oElement).trigger('change'); - fValueAccessor().call(oViewModel); + $(element).trigger('change'); + fValueAccessor().call(viewModel); } }); - ko.utils.domNodeDisposal.addDisposeCallback(oElement, function() { - $(oElement).off('keypress.koOnEnter'); + ko.utils.domNodeDisposal.addDisposeCallback(element, () => { + $(element).off('keypress.koOnEnter'); }); } }; ko.bindingHandlers.onSpace = { - init: function(oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) { - $(oElement).on('keyup.koOnSpace', function(oEvent) { - if (oEvent && 32 === window.parseInt(oEvent.keyCode, 10)) + init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => { + $(element).on('keyup.koOnSpace', (event) => { + if (event && 32 === window.parseInt(event.keyCode, 10)) { - fValueAccessor().call(oViewModel, oEvent); + fValueAccessor().call(viewModel, event); } }); - ko.utils.domNodeDisposal.addDisposeCallback(oElement, function() { - $(oElement).off('keyup.koOnSpace'); + ko.utils.domNodeDisposal.addDisposeCallback(element, () => { + $(element).off('keyup.koOnSpace'); }); } }; ko.bindingHandlers.onTab = { - init: function(oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) { - $(oElement).on('keydown.koOnTab', function(oEvent) { - if (oEvent && 9 === window.parseInt(oEvent.keyCode, 10)) + init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => { + $(element).on('keydown.koOnTab', (event) => { + if (event && 9 === window.parseInt(event.keyCode, 10)) { - return fValueAccessor().call(oViewModel, !!oEvent.shiftKey); + return fValueAccessor().call(viewModel, !!event.shiftKey); } return true; }); - ko.utils.domNodeDisposal.addDisposeCallback(oElement, function() { - $(oElement).off('keydown.koOnTab'); + ko.utils.domNodeDisposal.addDisposeCallback(element, () => { + $(element).off('keydown.koOnTab'); }); } }; ko.bindingHandlers.onEsc = { - init: function(oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) { - $(oElement).on('keypress.koOnEsc', function(oEvent) { - if (oEvent && 27 === window.parseInt(oEvent.keyCode, 10)) + init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => { + $(element).on('keypress.koOnEsc', (event) => { + if (event && 27 === window.parseInt(event.keyCode, 10)) { - $(oElement).trigger('change'); - fValueAccessor().call(oViewModel); + $(element).trigger('change'); + fValueAccessor().call(viewModel); } }); - ko.utils.domNodeDisposal.addDisposeCallback(oElement, function() { - $(oElement).off('keypress.koOnEsc'); + ko.utils.domNodeDisposal.addDisposeCallback(element, () => { + $(element).off('keypress.koOnEsc'); }); } }; ko.bindingHandlers.clickOnTrue = { - update: function(oElement, fValueAccessor) { + update: (element, fValueAccessor) => { if (ko.unwrap(fValueAccessor())) { - $(oElement).click(); + $(element).click(); } } }; ko.bindingHandlers.modal = { - init: function(oElement, fValueAccessor) { + init: (element, fValueAccessor) => { - var + const Globals = require('Common/Globals'), Utils = require('Common/Utils'); - $(oElement) + $(element) .toggleClass('fade', !Globals.bMobileDevice) .modal({ 'keyboard': false, 'show': ko.unwrap(fValueAccessor()) }) .on('shown.koModal', Utils.windowResizeCallback) - .find('.close').on('click.koModal', function() { + .find('.close').on('click.koModal', () => { fValueAccessor()(false); }); - ko.utils.domNodeDisposal.addDisposeCallback(oElement, function() { - $(oElement) + ko.utils.domNodeDisposal.addDisposeCallback(element, () => { + $(element) .off('shown.koModal') .find('.close') .off('click.koModal'); }); }, - update: function(oElement, fValueAccessor) { + update: (element, fValueAccessor) => { - var Globals = require('Common/Globals'); + const Globals = require('Common/Globals'); - $(oElement).modal(ko.unwrap(fValueAccessor()) ? 'show' : 'hide'); + $(element).modal(ko.unwrap(fValueAccessor()) ? 'show' : 'hide'); if (Globals.$html.hasClass('rl-anim')) { Globals.$html.addClass('rl-modal-animation'); - _.delay(function() { + _.delay(() => { Globals.$html.removeClass('rl-modal-animation'); - }, 400); + }, Magics.Time500ms); } } }; ko.bindingHandlers.moment = { - init: function(oElement, fValueAccessor) { + init: (element, fValueAccessor) => { require('Common/Momentor').momentToNode( - $(oElement).addClass('moment').data('moment-time', ko.unwrap(fValueAccessor())) + $(element).addClass('moment').data('moment-time', ko.unwrap(fValueAccessor())) ); }, - update: function(oElement, fValueAccessor) { + update: (element, fValueAccessor) => { require('Common/Momentor').momentToNode( - $(oElement).data('moment-time', ko.unwrap(fValueAccessor())) + $(element).data('moment-time', ko.unwrap(fValueAccessor())) ); } }; ko.bindingHandlers.i18nInit = { - init: function(oElement) { - require('Common/Translator').i18nToNodes(oElement); + init: (element) => { + require('Common/Translator').i18nToNodes(element); } }; ko.bindingHandlers.translatorInit = { - init: function(oElement) { - require('Common/Translator').i18nToNodes(oElement); + init: (element) => { + require('Common/Translator').i18nToNodes(element); } }; ko.bindingHandlers.i18nUpdate = { - update: function(oElement, fValueAccessor) { + update: (element, fValueAccessor) => { ko.unwrap(fValueAccessor()); - require('Common/Translator').i18nToNodes(oElement); + require('Common/Translator').i18nToNodes(element); } }; ko.bindingHandlers.link = { - update: function(oElement, fValueAccessor) { - $(oElement).attr('href', ko.unwrap(fValueAccessor())); + update: function(element, fValueAccessor) { + $(element).attr('href', ko.unwrap(fValueAccessor())); } }; ko.bindingHandlers.title = { - update: function(oElement, fValueAccessor) { - $(oElement).attr('title', ko.unwrap(fValueAccessor())); + update: function(element, fValueAccessor) { + $(element).attr('title', ko.unwrap(fValueAccessor())); } }; ko.bindingHandlers.textF = { - init: function(oElement, fValueAccessor) { - $(oElement).text(ko.unwrap(fValueAccessor())); + init: function(element, fValueAccessor) { + $(element).text(ko.unwrap(fValueAccessor())); } }; ko.bindingHandlers.initDom = { - init: function(oElement, fValueAccessor) { - fValueAccessor()(oElement); + init: function(element, fValueAccessor) { + fValueAccessor()(element); } }; ko.bindingHandlers.initFixedTrigger = { - init: function(oElement, fValueAccessor) { - var - aValues = ko.unwrap(fValueAccessor()), - $oContainer = null, - $oElement = $(oElement), - oOffset = null, + init: (element, fValueAccessor) => { + const + values = ko.unwrap(fValueAccessor()), + $el = $(element), + top = values[1] || 0; - iTop = aValues[1] || 0; - - $oContainer = $(aValues[0] || null); - $oContainer = $oContainer[0] ? $oContainer : null; - - if ($oContainer) + let $container = $(values[0] || null); + $container = $container[0] ? $container : null; + if ($container) { - $(window).resize(function() { - oOffset = $oContainer.offset(); - if (oOffset && oOffset.top) + $win.resize(() => { + const offset = $container.offset(); + if (offset && offset.top) { - $oElement.css('top', oOffset.top + iTop); + $el.css('top', offset.top + top); } }); } @@ -561,62 +575,64 @@ ko.bindingHandlers.initFixedTrigger = { }; ko.bindingHandlers.initResizeTrigger = { - init: function(oElement, fValueAccessor) { - var aValues = ko.unwrap(fValueAccessor()); - $(oElement).css({ - 'height': aValues[1], - 'min-height': aValues[1] + init: (element, fValueAccessor) => { + const values = ko.unwrap(fValueAccessor()); + $(element).css({ + 'height': values[1], + 'min-height': values[1] }); }, - update: function(oElement, fValueAccessor) { + update: (oElement, fValueAccessor) => { - var + const Utils = require('Common/Utils'), Globals = require('Common/Globals'), - aValues = ko.unwrap(fValueAccessor()), - iValue = Utils.pInt(aValues[1]), - iSize = 0, - iOffset = $(oElement).offset().top; + values = ko.unwrap(fValueAccessor()); - if (0 < iOffset) + let + value = Utils.pInt(values[1]), + size = 0, + offset = $(oElement).offset().top; + + if (0 < offset) { - iOffset += Utils.pInt(aValues[2]); - iSize = Globals.$win.height() - iOffset; + offset += Utils.pInt(values[2]); + size = Globals.$win.height() - offset; - if (iValue < iSize) + if (value < size) { - iValue = iSize; + value = size; } $(oElement).css({ - 'height': iValue, - 'min-height': iValue + 'height': value, + 'min-height': value }); } } }; ko.bindingHandlers.appendDom = { - update: function(oElement, fValueAccessor) { - $(oElement).hide().empty().append(ko.unwrap(fValueAccessor())).show(); + update: (element, fValueAccessor) => { + $(element).hide().empty().append(ko.unwrap(fValueAccessor())).show(); } }; ko.bindingHandlers.draggable = { - init: function(oElement, fValueAccessor, fAllBindingsAccessor) { + init: (element, fValueAccessor, fAllBindingsAccessor) => { - var + const Globals = require('Common/Globals'), Utils = require('Common/Utils'); if (!Globals.bMobileDevice) { - var - iTriggerZone = 100, - iScrollSpeed = 3, + const + triggerZone = 100, + scrollSpeed = 3, fAllValueFunc = fAllBindingsAccessor(), - sDroppableSelector = fAllValueFunc && fAllValueFunc.droppableSelector ? fAllValueFunc.droppableSelector : '', - oConf = { + droppableSelector = fAllValueFunc && fAllValueFunc.droppableSelector ? fAllValueFunc.droppableSelector : '', + conf = { distance: 20, handle: '.dragHandle', cursorAt: {top: 22, left: 3}, @@ -624,25 +640,25 @@ ko.bindingHandlers.draggable = { scroll: true }; - if (sDroppableSelector) + if (droppableSelector) { - oConf.drag = function(oEvent) { + conf.drag = (event) => { - $(sDroppableSelector).each(function() { - var - $this = $(this), - oOffset = $this.offset(), - bottomPos = oOffset.top + $this.height(); + $(droppableSelector).each(function() { + const + $this = $(this), // eslint-disable-line no-invalid-this + offset = $this.offset(), + bottomPos = offset.top + $this.height(); window.clearInterval($this.data('timerScroll')); $this.data('timerScroll', false); - if (oEvent.pageX >= oOffset.left && oEvent.pageX <= oOffset.left + $this.width()) + if (event.pageX >= offset.left && event.pageX <= offset.left + $this.width()) { - if (oEvent.pageY >= bottomPos - iTriggerZone && oEvent.pageY <= bottomPos) + if (event.pageY >= bottomPos - triggerZone && event.pageY <= bottomPos) { - var moveUp = function() { - $this.scrollTop($this.scrollTop() + iScrollSpeed); + const moveUp = () => { + $this.scrollTop($this.scrollTop() + scrollSpeed); Utils.windowResize(); }; @@ -650,10 +666,10 @@ ko.bindingHandlers.draggable = { moveUp(); } - if (oEvent.pageY >= oOffset.top && oEvent.pageY <= oOffset.top + iTriggerZone) + if (event.pageY >= offset.top && event.pageY <= offset.top + triggerZone) { - var moveDown = function() { - $this.scrollTop($this.scrollTop() - iScrollSpeed); + const moveDown = () => { + $this.scrollTop($this.scrollTop() - scrollSpeed); Utils.windowResize(); }; @@ -664,24 +680,23 @@ ko.bindingHandlers.draggable = { }); }; - oConf.stop = function() { - $(sDroppableSelector).each(function() { - window.clearInterval($(this).data('timerScroll')); - $(this).data('timerScroll', false); + conf.stop = () => { + $(droppableSelector).each(function() { + const $this = $(this); // eslint-disable-line no-invalid-this + window.clearInterval($this.data('timerScroll')); + $this.data('timerScroll', false); }); }; } - oConf.helper = function(oEvent) { - return fValueAccessor()(oEvent && oEvent.target ? ko.dataFor(oEvent.target) : null); - }; + conf.helper = (event) => fValueAccessor()(event && event.target ? ko.dataFor(event.target) : null); - $(oElement).draggable(oConf).on('mousedown.koDraggable', function() { + $(element).draggable(conf).on('mousedown.koDraggable', () => { Utils.removeInFocus(); }); - ko.utils.domNodeDisposal.addDisposeCallback(oElement, function() { - $(oElement) + ko.utils.domNodeDisposal.addDisposeCallback(element, () => { + $(element) .off('mousedown.koDraggable') .draggable('destroy'); }); @@ -690,44 +705,44 @@ ko.bindingHandlers.draggable = { }; ko.bindingHandlers.droppable = { - init: function(oElement, fValueAccessor, fAllBindingsAccessor) { - var Globals = require('Common/Globals'); + init: (element, fValueAccessor, fAllBindingsAccessor) => { + const Globals = require('Common/Globals'); if (!Globals.bMobileDevice) { - var + const fValueFunc = fValueAccessor(), fAllValueFunc = fAllBindingsAccessor(), fOverCallback = fAllValueFunc && fAllValueFunc.droppableOver ? fAllValueFunc.droppableOver : null, fOutCallback = fAllValueFunc && fAllValueFunc.droppableOut ? fAllValueFunc.droppableOut : null, - oConf = { + conf = { tolerance: 'pointer', hoverClass: 'droppableHover' }; if (fValueFunc) { - oConf.drop = function(oEvent, oUi) { - fValueFunc(oEvent, oUi); + conf.drop = (event, ui) => { + fValueFunc(event, ui); }; if (fOverCallback) { - oConf.over = function(oEvent, oUi) { - fOverCallback(oEvent, oUi); + conf.over = (event, ui) => { + fOverCallback(event, ui); }; } if (fOutCallback) { - oConf.out = function(oEvent, oUi) { - fOutCallback(oEvent, oUi); + conf.out = (event, ui) => { + fOutCallback(event, ui); }; } - $(oElement).droppable(oConf); + $(element).droppable(conf); - ko.utils.domNodeDisposal.addDisposeCallback(oElement, function() { - $(oElement).droppable('destroy'); + ko.utils.domNodeDisposal.addDisposeCallback(element, () => { + $(element).droppable('destroy'); }); } } @@ -735,71 +750,71 @@ ko.bindingHandlers.droppable = { }; ko.bindingHandlers.nano = { - init: function(oElement) { + init: (element) => { - var + const Globals = require('Common/Globals'), Settings = require('Storage/Settings'); if (!Globals.bDisableNanoScroll && !Settings.appSettingsGet('useNativeScrollbars')) { - $(oElement) + $(element) .addClass('nano') .nanoScroller({ - 'iOSNativeScrolling': false, - 'preventPageScrolling': true + iOSNativeScrolling: false, + preventPageScrolling: true }); } } }; ko.bindingHandlers.saveTrigger = { - init: function(oElement) { + init: (element) => { - var $oEl = $(oElement); + const $el = $(element); - $oEl.data('save-trigger-type', $oEl.is('input[type=text],input[type=email],input[type=password],select,textarea') ? 'input' : 'custom'); + $el.data('save-trigger-type', $el.is('input[type=text],input[type=email],input[type=password],select,textarea') ? 'input' : 'custom'); - if ('custom' === $oEl.data('save-trigger-type')) + if ('custom' === $el.data('save-trigger-type')) { - $oEl.append( + $el.append( '  ' ).addClass('settings-saved-trigger'); } else { - $oEl.addClass('settings-saved-trigger-input'); + $el.addClass('settings-saved-trigger-input'); } }, - update: function(oElement, fValueAccessor) { - var - mValue = ko.unwrap(fValueAccessor()), - $oEl = $(oElement); + update: (element, fValueAccessor) => { + const + value = ko.unwrap(fValueAccessor()), + $el = $(element); - if ('custom' === $oEl.data('save-trigger-type')) + if ('custom' === $el.data('save-trigger-type')) { - switch (mValue.toString()) + switch (value.toString()) { case '1': - $oEl + $el .find('.animated,.error').hide().removeClass('visible') .end() .find('.success').show().addClass('visible'); break; case '0': - $oEl + $el .find('.animated,.success').hide().removeClass('visible') .end() .find('.error').show().addClass('visible'); break; case '-2': - $oEl + $el .find('.error,.success').hide().removeClass('visible') .end() .find('.animated').show().addClass('visible'); break; default: - $oEl + $el .find('.animated').hide() .end() .find('.error,.success').removeClass('visible'); @@ -808,19 +823,18 @@ ko.bindingHandlers.saveTrigger = { } else { - switch (mValue.toString()) + switch (value.toString()) { case '1': - $oEl.addClass('success').removeClass('error'); + $el.addClass('success').removeClass('error'); break; case '0': - $oEl.addClass('error').removeClass('success'); + $el.addClass('error').removeClass('success'); break; case '-2': -// $oEl; break; default: - $oEl.removeClass('error success'); + $el.removeClass('error success'); break; } } @@ -828,130 +842,79 @@ ko.bindingHandlers.saveTrigger = { }; ko.bindingHandlers.emailsTags = { - init: function(oElement, fValueAccessor, fAllBindingsAccessor) { + init: (element, fValueAccessor, fAllBindingsAccessor) => { - var + const Utils = require('Common/Utils'), EmailModel = require('Model/Email').default, - $oEl = $(oElement), + $el = $(element), fValue = fValueAccessor(), fAllBindings = fAllBindingsAccessor(), fAutoCompleteSource = fAllBindings.autoCompleteSource || null, - fFocusCallback = function(bValue) { + fFocusCallback = (value) => { if (fValue && fValue.focused) { - fValue.focused(!!bValue); + fValue.focused(!!value); } }; - $oEl.inputosaurus({ - 'parseOnBlur': true, - 'allowDragAndDrop': true, - 'focusCallback': fFocusCallback, - 'inputDelimiters': [',', ';', '\n'], - 'autoCompleteSource': fAutoCompleteSource, -// 'elementHook': function(oEl, oItem) { -// if (oEl && oItem) -// { -// oEl.addClass('pgp'); -// window.console.log(arguments); -// } -// }, - 'parseHook': function(aInput) { + $el.inputosaurus({ + parseOnBlur: true, + allowDragAndDrop: true, + focusCallback: fFocusCallback, + inputDelimiters: [',', ';', '\n'], + autoCompleteSource: fAutoCompleteSource, +// elementHook: (el, item) => { +// if (el && item) +// { +// el.addClass('pgp'); +// } +// }, + parseHook: (input) => _.map(input, (inputValue) => { + const value = Utils.trim(inputValue); + if ('' !== value) + { + const email = new EmailModel(); + email.mailsoParse(value); + return [email.toLine(false), email]; + } + return [value, null]; - return _.map(aInput, function(sInputValue) { - var value = Utils.trim(sInputValue); - if ('' !== value) - { - var email = new EmailModel(); - email.mailsoParse(value); - return [email.toLine(false), email]; - } - return [value, null]; - - }); - -// var aResult = []; -// -// _.each(aInput, function(sInputValue) { -// -// var -// aM = null, -// aValues = [], -// sValue = Utils.trim(sInputValue), -// oEmail = null -// ; -// -// if ('' !== sValue) -// { -// aM = sValue.match(/[@]/g); -// if (aM && 0 < aM.length) -// { -// sValue = sValue.replace(/[\r\n]+/g, '; ').replace(/[\s]+/g, ' '); -// aValues = EmailModel.splitHelper(sValue, ';'); -// -// _.each(aValues, function(sV) { -// -// oEmail = new EmailModel(); -// oEmail.mailsoParse(sV); -// -// if (oEmail.email) -// { -// aResult.push([oEmail.toLine(false), oEmail]); -// } -// else -// { -// aResult.push(['', null]); -// } -// }); -// } -// else -// { -// aResult.push([sInputValue, null]); -// } -// } -// else -// { -// aResult.push([sInputValue, null]); -// } -// }); -// -// return aResult; - }, - 'change': _.bind(function(oEvent) { - $oEl.data('EmailsTagsValue', oEvent.target.value); - fValue(oEvent.target.value); - }, this) + }), + 'change': (event) => { + $el.data('EmailsTagsValue', event.target.value); + fValue(event.target.value); + } }); if (fValue && fValue.focused && fValue.focused.subscribe) { - fValue.focused.subscribe(function(bValue) { - $oEl.inputosaurus(bValue ? 'focus' : 'blur'); + fValue.focused.subscribe((value) => { + $el.inputosaurus(value ? 'focus' : 'blur'); }); } }, - update: function(oElement, fValueAccessor) { + update: (element, fValueAccessor) => { - var - $oEl = $(oElement), + const + $oEl = $(element), fValue = fValueAccessor(), - sValue = ko.unwrap(fValue); + value = ko.unwrap(fValue); - if ($oEl.data('EmailsTagsValue') !== sValue) + if ($oEl.data('EmailsTagsValue') !== value) { - $oEl.val(sValue); - $oEl.data('EmailsTagsValue', sValue); + $oEl.val(value); + $oEl.data('EmailsTagsValue', value); $oEl.inputosaurus('refresh'); } } }; ko.bindingHandlers.command = { - init: function(oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) { - var - jqElement = $(oElement), + init: (element, fValueAccessor, fAllBindingsAccessor, viewModel, bindingContext) => { + const + jqElement = $(element), oCommand = fValueAccessor(); if (!oCommand || !oCommand.enabled || !oCommand.canExecute) @@ -961,295 +924,272 @@ ko.bindingHandlers.command = { jqElement.addClass('command'); ko.bindingHandlers[jqElement.is('form') ? 'submit' : 'click'] - .init.apply(oViewModel, Array.prototype.slice.call(arguments)); // eslint-disable-line prefer-rest-params + .init(element, fValueAccessor, fAllBindingsAccessor, viewModel, bindingContext); }, - update: function(oElement, fValueAccessor) { + update: (element, fValueAccessor) => { - var - jqElement = $(oElement), - oCommand = fValueAccessor(), - bResult = oCommand.enabled(); + const + jqElement = $(element), + command = fValueAccessor(); - jqElement.toggleClass('command-not-enabled', !bResult); + let result = command.enabled(); - if (bResult) + jqElement.toggleClass('command-not-enabled', !result); + + if (result) { - bResult = oCommand.canExecute(); - jqElement.toggleClass('command-can-not-be-execute', !bResult); + result = command.canExecute(); + jqElement.toggleClass('command-can-not-be-execute', !result); } - jqElement.toggleClass('command-disabled disable disabled', !bResult).toggleClass('no-disabled', !!bResult); + jqElement.toggleClass('command-disabled disable disabled', !result).toggleClass('no-disabled', !!result); if (jqElement.is('input') || jqElement.is('button')) { - jqElement.prop('disabled', !bResult); + jqElement.prop('disabled', !result); } } }; // extenders -ko.extenders.trimmer = function(oTarget) -{ - var +ko.extenders.trimmer = (target) => { + const Utils = require('Common/Utils'), - oResult = ko.computed({ - 'read': oTarget, - 'write': function(sNewValue) { - oTarget(Utils.trim(sNewValue.toString())); - }, - 'owner': this - }); - - oResult(oTarget()); - return oResult; -}; - -ko.extenders.posInterer = function(oTarget, iDefault) -{ - var - Utils = require('Common/Utils'), - oResult = ko.computed({ - 'read': oTarget, - 'write': function(sNewValue) { - var iNew = Utils.pInt(sNewValue.toString(), iDefault); - if (0 >= iNew) - { - iNew = iDefault; - } - - if (iNew === oTarget() && '' + iNew !== '' + sNewValue) - { - oTarget(iNew + 1); - } - - oTarget(iNew); + result = ko.computed({ + read: target, + write: (newValue) => { + target(Utils.trim(newValue.toString())); } }); - oResult(oTarget()); - return oResult; + result(target()); + return result; }; -ko.extenders.limitedList = function(oTarget, mList) -{ - var +ko.extenders.posInterer = (target, defaultVal) => { + const Utils = require('Common/Utils'), - oResult = ko.computed({ - 'read': oTarget, - 'write': function(sNewValue) { - - var - sCurrentValue = ko.unwrap(oTarget), - aList = ko.unwrap(mList); - - if (Utils.isNonEmptyArray(aList)) + result = ko.computed({ + read: target, + write: (newValue) => { + let val = Utils.pInt(newValue.toString(), defaultVal); + if (0 >= val) { - if (-1 < Utils.inArray(sNewValue, aList)) + val = defaultVal; + } + + if (val === target() && '' + val !== '' + newValue) + { + target(val + 1); + } + + target(val); + } + }); + + result(target()); + return result; +}; + +ko.extenders.limitedList = (target, limitedList) => { + const + Utils = require('Common/Utils'), + result = ko.computed({ + read: target, + write: (newValue) => { + + const + currentValue = ko.unwrap(target), + list = ko.unwrap(limitedList); + + if (Utils.isNonEmptyArray(list)) + { + if (-1 < Utils.inArray(newValue, list)) { - oTarget(sNewValue); + target(newValue); } - else if (-1 < Utils.inArray(sCurrentValue, aList)) + else if (-1 < Utils.inArray(currentValue, list)) { - oTarget(sCurrentValue + ' '); - oTarget(sCurrentValue); + target(currentValue + ' '); + target(currentValue); } else { - oTarget(aList[0] + ' '); - oTarget(aList[0]); + target(list[0] + ' '); + target(list[0]); } } else { - oTarget(''); + target(''); } } - }).extend({'notify': 'always'}); + }).extend({notify: 'always'}); - oResult(oTarget()); + result(target()); - if (!oResult.valueHasMutated) + if (!result.valueHasMutated) { - oResult.valueHasMutated = function() { - oTarget.valueHasMutated(); + result.valueHasMutated = () => { + target.valueHasMutated(); }; } - return oResult; + return result; }; -ko.extenders.reversible = function(oTarget) -{ - var mValue = oTarget(); +ko.extenders.reversible = (target) => { - oTarget.commit = function() - { - mValue = oTarget(); + let value = target(); + + target.commit = () => { + value = target(); }; - oTarget.reverse = function() - { - oTarget(mValue); + target.reverse = () => { + target(value); }; - oTarget.commitedValue = function() - { - return mValue; - }; - - return oTarget; + target.commitedValue = () => value; + return target; }; -ko.extenders.toggleSubscribe = function(oTarget, oOptions) -{ - oTarget.subscribe(oOptions[1], oOptions[0], 'beforeChange'); - oTarget.subscribe(oOptions[2], oOptions[0]); - - return oTarget; +ko.extenders.toggleSubscribe = (target, options) => { + target.subscribe(options[1], options[0], 'beforeChange'); + target.subscribe(options[2], options[0]); + return target; }; -ko.extenders.toggleSubscribeProperty = function(oTarget, oOptions) -{ - var sProp = oOptions[1]; +ko.extenders.toggleSubscribeProperty = (target, options) => { - if (sProp) + const prop = options[1]; + if (prop) { - oTarget.subscribe(function(oPrev) { - if (oPrev && oPrev[sProp]) + target.subscribe((prev) => { + if (prev && prev[prop]) { - oPrev[sProp](false); + prev[prop](false); } - }, oOptions[0], 'beforeChange'); + }, options[0], 'beforeChange'); - oTarget.subscribe(function(oNext) { - if (oNext && oNext[sProp]) + target.subscribe((next) => { + if (next && next[prop]) { - oNext[sProp](true); + next[prop](true); } - }, oOptions[0]); + }, options[0]); } - return oTarget; + return target; }; -ko.extenders.falseTimeout = function(oTarget, iOption) -{ - oTarget.iFalseTimeoutTimeout = 0; - oTarget.subscribe(function(bValue) { - if (bValue) +ko.extenders.falseTimeout = (target, option) => { + target.iFalseTimeoutTimeout = 0; + target.subscribe((value) => { + if (value) { - window.clearTimeout(oTarget.iFalseTimeoutTimeout); - oTarget.iFalseTimeoutTimeout = window.setTimeout(function() { - oTarget(false); - oTarget.iFalseTimeoutTimeout = 0; - }, require('Common/Utils').pInt(iOption)); + window.clearTimeout(target.iFalseTimeoutTimeout); + target.iFalseTimeoutTimeout = window.setTimeout(() => { + target(false); + target.iFalseTimeoutTimeout = 0; + }, require('Common/Utils').pInt(option)); } }); - return oTarget; + return target; }; -ko.extenders.specialThrottle = function(oTarget, iOption) -{ - oTarget.iSpecialThrottleTimeoutValue = require('Common/Utils').pInt(iOption); - if (0 < oTarget.iSpecialThrottleTimeoutValue) +ko.extenders.specialThrottle = (target, option) => { + target.iSpecialThrottleTimeoutValue = require('Common/Utils').pInt(option); + if (0 < target.iSpecialThrottleTimeoutValue) { - oTarget.iSpecialThrottleTimeout = 0; - oTarget.valueForRead = ko.observable(!!oTarget()).extend({'throttle': 10}); + target.iSpecialThrottleTimeout = 0; + target.valueForRead = ko.observable(!!target()).extend({throttle: 10}); return ko.computed({ - 'read': oTarget.valueForRead, - 'write': function(bValue) { + read: target.valueForRead, + write: (bValue) => { if (bValue) { - oTarget.valueForRead(bValue); + target.valueForRead(bValue); } else { - if (oTarget.valueForRead()) + if (target.valueForRead()) { - window.clearTimeout(oTarget.iSpecialThrottleTimeout); - oTarget.iSpecialThrottleTimeout = window.setTimeout(function() { - oTarget.valueForRead(false); - oTarget.iSpecialThrottleTimeout = 0; - }, oTarget.iSpecialThrottleTimeoutValue); + window.clearTimeout(target.iSpecialThrottleTimeout); + target.iSpecialThrottleTimeout = window.setTimeout(() => { + target.valueForRead(false); + target.iSpecialThrottleTimeout = 0; + }, target.iSpecialThrottleTimeoutValue); } else { - oTarget.valueForRead(bValue); + target.valueForRead(bValue); } } } }); } - return oTarget; + return target; }; -ko.extenders.idleTrigger = function(oTarget) -{ - var Enums = require('Common/Enums'); - oTarget.trigger = ko.observable(Enums.SaveSettingsStep.Idle); - return oTarget; +ko.extenders.idleTrigger = (target) => { + target.trigger = ko.observable(SaveSettingsStep.Idle); + return target; }; // functions -ko.observable.fn.idleTrigger = function() -{ +ko.observable.fn.idleTrigger = function() { return this.extend({'idleTrigger': true}); }; -ko.observable.fn.validateNone = function() -{ +ko.observable.fn.validateNone = function() { this.hasError = ko.observable(false); return this; }; -ko.observable.fn.validateEmail = function() -{ - var Utils = require('Common/Utils'); +ko.observable.fn.validateEmail = function() { this.hasError = ko.observable(false); - this.subscribe(function(sValue) { - sValue = Utils.trim(sValue); - this.hasError('' !== sValue && !(/^[^@\s]+@[^@\s]+$/.test(sValue))); - }, this); + this.subscribe((value) => { + this.hasError('' !== value && !(/^[^@\s]+@[^@\s]+$/.test(value))); + }); this.valueHasMutated(); return this; }; -ko.observable.fn.validateSimpleEmail = function() -{ - var Utils = require('Common/Utils'); +ko.observable.fn.validateSimpleEmail = function() { this.hasError = ko.observable(false); - this.subscribe(function(sValue) { - sValue = Utils.trim(sValue); - this.hasError('' !== sValue && !(/^.+@.+$/.test(sValue))); - }, this); + this.subscribe((value) => { + this.hasError('' !== value && !(/^.+@.+$/.test(value))); + }); this.valueHasMutated(); return this; }; -ko.observable.fn.deleteAccessHelper = function() -{ - this.extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [null, - function(oPrev) { - if (oPrev && oPrev.deleteAccess) +ko.observable.fn.deleteAccessHelper = function() { + this.extend({falseTimeout: 3000}).extend({toggleSubscribe: [ + null, + (prev) => { + if (prev && prev.deleteAccess) { - oPrev.deleteAccess(false); + prev.deleteAccess(false); } - }, function(oNext) { - if (oNext && oNext.deleteAccess) + }, + (next) => { + if (next && next.deleteAccess) { - oNext.deleteAccess(true); + next.deleteAccess(true); } } ]}); @@ -1257,17 +1197,15 @@ ko.observable.fn.deleteAccessHelper = function() return this; }; -ko.observable.fn.validateFunc = function(fFunc) -{ - var Utils = require('Common/Utils'); +ko.observable.fn.validateFunc = function(fFunc) { this.hasFuncError = ko.observable(false); - if (Utils.isFunc(fFunc)) + if (_.isFunction(fFunc)) { - this.subscribe(function(sValue) { - this.hasFuncError(!fFunc(sValue)); - }, this); + this.subscribe((value) => { + this.hasFuncError(!fFunc(value)); + }); this.valueHasMutated(); } diff --git a/dev/Helper/Apps/Admin.js b/dev/Helper/Apps/Admin.js new file mode 100644 index 000000000..81e807e30 --- /dev/null +++ b/dev/Helper/Apps/Admin.js @@ -0,0 +1,7 @@ + +/** + * @returns {AppAdmin} + */ +export function getApp() { + return require('App/Admin').default; +} diff --git a/dev/Helper/Apps/User.js b/dev/Helper/Apps/User.js new file mode 100644 index 000000000..7ace1c022 --- /dev/null +++ b/dev/Helper/Apps/User.js @@ -0,0 +1,7 @@ + +/** + * @returns {AppUser} + */ +export function getApp() { + return require('App/User').default; +} diff --git a/dev/Html/PreviewMessage.html b/dev/Html/PreviewMessage.html new file mode 100644 index 000000000..150f7668c --- /dev/null +++ b/dev/Html/PreviewMessage.html @@ -0,0 +1,114 @@ + + + + + + + {{title}} + + + +
+
{{subject}}
+
+
+
{{date}}
+
{{fromCreds}}
+
{{toLabel}}: {{toCreds}}
+
+
{{html}}
+ + \ No newline at end of file diff --git a/dev/Knoin/AbstractView.js b/dev/Knoin/AbstractView.js deleted file mode 100644 index d6511ba1e..000000000 --- a/dev/Knoin/AbstractView.js +++ /dev/null @@ -1,123 +0,0 @@ - -var - ko = require('ko'), - - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Globals = require('Common/Globals'); - -/** - * @constructor - * @param {string=} sPosition = '' - * @param {string=} sTemplate = '' - */ -function AbstractView(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.viewModelVisibility = ko.observable(false); - this.modalVisibility = ko.observable(false).extend({'rateLimit': 0}); - - this.viewModelName = ''; - this.viewModelNames = []; - this.viewModelDom = null; -} - -/** - * @type {boolean} - */ -AbstractView.prototype.bDisabeCloseOnEsc = false; - -/** - * @type {string} - */ -AbstractView.prototype.sPosition = ''; - -/** - * @type {string} - */ -AbstractView.prototype.sTemplate = ''; - -/** - * @type {string} - */ -AbstractView.prototype.sDefaultKeyScope = Enums.KeyState.None; - -/** - * @type {string} - */ -AbstractView.prototype.sCurrentKeyScope = Enums.KeyState.None; - -/** - * @type {string} - */ -AbstractView.prototype.viewModelName = ''; - -/** - * @type {Array} - */ -AbstractView.prototype.viewModelNames = []; - -/** - * @type {?} - */ -AbstractView.prototype.viewModelDom = null; - -/** - * @returns {string} - */ -AbstractView.prototype.viewModelTemplate = function() -{ - return this.sTemplate; -}; - -/** - * @returns {string} - */ -AbstractView.prototype.viewModelPosition = function() -{ - return this.sPosition; -}; - -AbstractView.prototype.cancelCommand = Utils.noop; -AbstractView.prototype.closeCommand = Utils.noop; - -AbstractView.prototype.storeAndSetKeyScope = function() -{ - this.sCurrentKeyScope = Globals.keyScope(); - Globals.keyScope(this.sDefaultKeyScope); -}; - -AbstractView.prototype.restoreKeyScope = function() -{ - Globals.keyScope(this.sCurrentKeyScope); -}; - -AbstractView.prototype.registerPopupKeyDown = function() -{ - var self = this; - - Globals.$win.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 = AbstractView; diff --git a/dev/Knoin/AbstractViewNext.js b/dev/Knoin/AbstractViewNext.js new file mode 100644 index 000000000..c3db46c2c --- /dev/null +++ b/dev/Knoin/AbstractViewNext.js @@ -0,0 +1,64 @@ + +import ko from 'ko'; + +import {delegateRun, inFocus} from 'Common/Utils'; +import {KeyState, EventKeyCode} from 'Common/Enums'; +import {$win, keyScope} from 'Common/Globals'; + +class AbstractViewNext +{ + constructor() { + this.bDisabeCloseOnEsc = false; + this.sDefaultKeyScope = KeyState.None; + this.sCurrentKeyScope = this.sDefaultKeyScope; + + this.viewModelVisibility = ko.observable(false); + this.modalVisibility = ko.observable(false).extend({rateLimit: 0}); + + this.viewModelName = ''; + this.viewModelNames = []; + this.viewModelDom = null; + } + + /** + * @returns {void} + */ + storeAndSetKeyScope() { + this.sCurrentKeyScope = keyScope(); + keyScope(this.sDefaultKeyScope); + } + + /** + * @returns {void} + */ + restoreKeyScope() { + keyScope(this.sCurrentKeyScope); + } + + /** + * @returns {void} + */ + registerPopupKeyDown() { + $win.on('keydown', (event) => { + if (event && this.modalVisibility && this.modalVisibility()) + { + if (!this.bDisabeCloseOnEsc && EventKeyCode.Esc === event.keyCode) + { + delegateRun(this, 'cancelCommand'); + return false; + } + else if (EventKeyCode.Backspace === event.keyCode && !inFocus()) + { + return false; + } + } + + return true; + }); + } + + cancelCommand() {} // eslint-disable-line no-empty-function + closeCommand() {} // eslint-disable-line no-empty-function +} + +export {AbstractViewNext, AbstractViewNext as default}; diff --git a/dev/Knoin/Knoin.js b/dev/Knoin/Knoin.js index b6c902d40..af0c18a06 100644 --- a/dev/Knoin/Knoin.js +++ b/dev/Knoin/Knoin.js @@ -9,7 +9,7 @@ import {runHook} from 'Common/Plugins'; import {$html, aViewModels as VIEW_MODELS, popupVisibilityNames} from 'Common/Globals'; import { - isFunc, isArray, isUnd, pString, log, + isArray, isUnd, pString, log, createCommand, delegateRun, isNonEmptyArray } from 'Common/Utils'; @@ -19,6 +19,13 @@ let const SCREENS = {}; +export const ViewType = { + Popup: 'Popups', + Left: 'Left', + Right: 'Right', + Center: 'Center' +}; + /** * @returns {void} */ @@ -28,40 +35,6 @@ export function hideLoading() $('#rl-loading').hide().remove(); } -/** - * @param {Object} context - * @returns {void} - */ -export function constructorEnd(context) -{ - if (isFunc(context.__constructor_end)) - { - context.__constructor_end(); - } -} - -/** - * @param {string|Array} name - * @param {Function} ViewModelClass - * @returns {void} - */ -export function extendAsViewModel(name, ViewModelClass) -{ - if (ViewModelClass) - { - if (isArray(name)) - { - ViewModelClass.__names = name; - } - else - { - ViewModelClass.__names = [name]; - } - - ViewModelClass.__name = ViewModelClass.__names[0]; - } -} - /** * @param {Function} SettingsViewModelClass * @param {string} template @@ -161,8 +134,8 @@ export function buildViewModel(ViewModelClass, vmScreen) let vmDom = null; const vm = new ViewModelClass(vmScreen), - position = vm.viewModelPosition(), - vmPlace = $('#rl-content #rl-' + position.toLowerCase()); + position = ViewModelClass.__type || '', + vmPlace = position ? $('#rl-content #rl-' + position.toLowerCase()) : null; ViewModelClass.__builded = true; ViewModelClass.__vm = vm; @@ -172,18 +145,20 @@ export function buildViewModel(ViewModelClass, vmScreen) vm.viewModelName = ViewModelClass.__name; vm.viewModelNames = ViewModelClass.__names; + vm.viewModelTemplateID = ViewModelClass.__templateID; + vm.viewModelPosition = ViewModelClass.__type; if (vmPlace && 1 === vmPlace.length) { - vmDom = $('
').addClass('rl-view-model').addClass('RL-' + vm.viewModelTemplate()).hide(); + vmDom = $('
').addClass('rl-view-model').addClass('RL-' + vm.viewModelTemplateID).hide(); vmDom.appendTo(vmPlace); vm.viewModelDom = vmDom; ViewModelClass.__dom = vmDom; - if ('Popups' === position) + if (ViewType.Popup === position) { - vm.cancelCommand = vm.closeCommand = createCommand(vm, () => { + vm.cancelCommand = vm.closeCommand = createCommand(() => { hideScreenPopup(ViewModelClass); }); @@ -229,11 +204,11 @@ export function buildViewModel(ViewModelClass, vmScreen) ko.applyBindingAccessorsToNode(vmDom[0], { translatorInit: true, - template: () => ({name: vm.viewModelTemplate()}) + template: () => ({name: vm.viewModelTemplateID}) }, vm); delegateRun(vm, 'onBuild', [vmDom]); - if (vm && 'Popups' === position) + if (vm && ViewType.Popup === position) { vm.registerPopupKeyDown(); } @@ -273,6 +248,23 @@ export function showScreenPopup(ViewModelClassToShow, params = []) } } +/** + * @param {Function} ViewModelClassToShow + * @returns {void} + */ +export function warmUpScreenPopup(ViewModelClassToShow) +{ + if (ViewModelClassToShow) + { + buildViewModel(ViewModelClassToShow); + + if (ViewModelClassToShow.__vm && ViewModelClassToShow.__dom) + { + delegateRun(ViewModelClassToShow.__vm, 'onWarmUp'); + } + } +} + /** * @param {Function} ViewModelClassToShow * @returns {boolean} @@ -345,7 +337,7 @@ export function screenOnRoute(screenName, subPart) if (isNonEmptyArray(currentScreen.viewModels())) { _.each(currentScreen.viewModels(), (ViewModelClass) => { - if (ViewModelClass.__vm && ViewModelClass.__dom && 'Popups' !== ViewModelClass.__vm.viewModelPosition()) + if (ViewModelClass.__vm && ViewModelClass.__dom && ViewType.Popup !== ViewModelClass.__vm.viewModelPosition) { ViewModelClass.__dom.hide(); ViewModelClass.__vm.viewModelVisibility(false); @@ -380,7 +372,7 @@ export function screenOnRoute(screenName, subPart) { _.each(currentScreen.viewModels(), (ViewModelClass) => { - if (ViewModelClass.__vm && ViewModelClass.__dom && 'Popups' !== ViewModelClass.__vm.viewModelPosition()) + if (ViewModelClass.__vm && ViewModelClass.__dom && ViewType.Popup !== ViewModelClass.__vm.viewModelPosition) { delegateRun(ViewModelClass.__vm, 'onBeforeShow'); @@ -486,3 +478,41 @@ export function setHash(hash, silence = false, replace = false) hasher.setHash(hash); } } + +/** + * @param {Object} params + * @returns {void} + */ +function viewDecorator({name, type, templateID}) +{ + return (target) => { + if (target) + { + if (name) + { + if (isArray(name)) + { + target.__names = name; + } + else + { + target.__names = [name]; + } + + target.__name = target.__names[0]; + } + + if (type) + { + target.__type = type; + } + + if (templateID) + { + target.__templateID = templateID; + } + } + }; +} + +export {viewDecorator, viewDecorator as view, viewDecorator as viewModel}; diff --git a/dev/Model/Email.js b/dev/Model/Email.js index 2f30d363f..126314be8 100644 --- a/dev/Model/Email.js +++ b/dev/Model/Email.js @@ -218,10 +218,10 @@ class EmailModel return false; } - var - substr = function(str, start, len) { + const + substr = (str, start, len) => { str = pString(str); - var end = str.length; + let end = str.length; if (0 > start) { @@ -233,7 +233,7 @@ class EmailModel return start >= str.length || 0 > start || start > end ? false : str.slice(start, end); }, - substrReplace = function(str, replace, start, length) { + substrReplace = (str, replace, start, length) => { str = pString(str); if (0 > start) { @@ -246,8 +246,9 @@ class EmailModel length = length + str.length - start; } return str.slice(0, start) + replace.substr(0, length) + replace.slice(length) + str.slice(start + length); - }, + }; + let $sName = '', $sEmail = '', $sComment = '', diff --git a/dev/Model/Filter.js b/dev/Model/Filter.js index a81cdd4d8..4aa6bff90 100644 --- a/dev/Model/Filter.js +++ b/dev/Model/Filter.js @@ -190,9 +190,7 @@ class FilterModel extends AbstractModel Enabled: this.enabled() ? '1' : '0', Name: this.name(), ConditionsType: this.conditionsType(), - Conditions: _.map(this.conditions(), function(oItem) { - return oItem.toJson(); - }), + Conditions: _.map(this.conditions(), (item) => item.toJson()), ActionValue: this.actionValue(), ActionValueSecond: this.actionValueSecond(), @@ -257,7 +255,8 @@ class FilterModel extends AbstractModel } cloneSelf() { - var filter = new FilterModel(); + + const filter = new FilterModel(); filter.id = this.id; diff --git a/dev/Model/FilterCondition.js b/dev/Model/FilterCondition.js index a731c7ea5..0d5067a07 100644 --- a/dev/Model/FilterCondition.js +++ b/dev/Model/FilterCondition.js @@ -19,30 +19,30 @@ class FilterConditionModel extends AbstractModel this.valueSecond = ko.observable(''); this.valueSecond.error = ko.observable(false); - this.template = ko.computed(function() { + this.template = ko.computed(() => { - var sTemplate = ''; + let template = ''; switch (this.field()) { case FilterConditionField.Size: - sTemplate = 'SettingsFiltersConditionSize'; + template = 'SettingsFiltersConditionSize'; break; case FilterConditionField.Header: - sTemplate = 'SettingsFiltersConditionMore'; + template = 'SettingsFiltersConditionMore'; break; default: - sTemplate = 'SettingsFiltersConditionDefault'; + template = 'SettingsFiltersConditionDefault'; break; } - return sTemplate; + return template; }, this); - this.field.subscribe(function() { + this.field.subscribe(() => { this.value(''); this.valueSecond(''); - }, this); + }); this.regDisposables([this.template]); } diff --git a/dev/Model/Folder.js b/dev/Model/Folder.js index 069b9fd43..6fa096c77 100644 --- a/dev/Model/Folder.js +++ b/dev/Model/Folder.js @@ -64,9 +64,9 @@ class FolderModel extends AbstractModel this.isInbox = ko.computed(() => FolderType.Inbox === this.type()); - this.hasSubScribedSubfolders = ko.computed(function() { - return !!_.find(this.subFolders(), (oFolder) => (oFolder.subScribed() || oFolder.hasSubScribedSubfolders()) && !oFolder.isSystemFolder()); - }, this); + this.hasSubScribedSubfolders = ko.computed( + () => !!_.find(this.subFolders(), (oFolder) => (oFolder.subScribed() || oFolder.hasSubScribedSubfolders()) && !oFolder.isSystemFolder()) + ); this.canBeEdited = ko.computed(() => FolderType.User === this.type() && this.existen && this.selectable); @@ -236,9 +236,9 @@ class FolderModel extends AbstractModel this.hasUnreadMessages = ko.computed(() => 0 < this.messageCountUnread() && '' !== this.printableUnreadCount()); - this.hasSubScribedUnreadMessagesSubfolders = ko.computed(function() { - return !!_.find(this.subFolders(), (folder) => folder.hasUnreadMessages() || folder.hasSubScribedUnreadMessagesSubfolders()); - }, this); + this.hasSubScribedUnreadMessagesSubfolders = ko.computed( + () => !!_.find(this.subFolders(), (folder) => folder.hasUnreadMessages() || folder.hasSubScribedUnreadMessagesSubfolders()) + ); // subscribe this.name.subscribe((value) => { diff --git a/dev/Model/Message.js b/dev/Model/Message.js index 66154a333..5045f3a1b 100644 --- a/dev/Model/Message.js +++ b/dev/Model/Message.js @@ -2,8 +2,11 @@ import _ from '_'; import $ from '$'; import ko from 'ko'; +import moment from 'moment'; +import classnames from 'classnames'; import {MessagePriority, SignedVerifyStatus} from 'Common/Enums'; +import {i18n} from 'Common/Translator'; import { pInt, inArray, isArray, isUnd, trim, @@ -455,73 +458,24 @@ class MessageModel extends AbstractModel * @return string */ lineAsCss() { - const result = []; - if (this.deleted()) - { - result.push('deleted'); - } - if (this.deletedMark()) - { - result.push('deleted-mark'); - } - if (this.selected()) - { - result.push('selected'); - } - if (this.checked()) - { - result.push('checked'); - } - if (this.flagged()) - { - result.push('flagged'); - } - if (this.unseen()) - { - result.push('unseen'); - } - if (this.answered()) - { - result.push('answered'); - } - if (this.forwarded()) - { - result.push('forwarded'); - } - if (this.focused()) - { - result.push('focused'); - } - if (this.isImportant()) - { - result.push('important'); - } - if (this.hasAttachments()) - { - result.push('withAttachments'); - } - if (this.newForAnimation()) - { - result.push('new'); - } - if ('' === this.subject()) - { - result.push('emptySubject'); - } -// if (1 < this.threadsLen()) -// { -// result.push('hasChildrenMessage'); -// } - if (this.hasUnseenSubMessage()) - { - result.push('hasUnseenSubMessage'); - } - if (this.hasFlaggedSubMessage()) - { - result.push('hasFlaggedSubMessage'); - } - - return result.join(' '); + return classnames({ + 'deleted': this.deleted(), + 'deleted-mark': this.deletedMark(), + 'selected': this.selected(), + 'checked': this.checked(), + 'flagged': this.flagged(), + 'unseen': this.unseen(), + 'answered': this.answered(), + 'forwarded': this.forwarded(), + 'focused': this.focused(), + 'important': this.isImportant(), + 'withAttachments': this.hasAttachments(), + 'new': this.newForAnimation(), + 'emptySubject': '' === this.subject(), + // 'hasChildrenMessage': 1 < this.threadsLen(), + 'hasUnseenSubMessage': this.hasUnseenSubMessage(), + 'hasFlaggedSubMessage': this.hasFlaggedSubMessage() + }); } /** @@ -680,7 +634,19 @@ class MessageModel extends AbstractModel */ viewPopupMessage(print = false) { this.showLazyExternalImagesInBody(); - previewMessage(this.subject(), this.body, this.isHtml(), print); + + const + timeStampInUTC = this.dateTimeStampInUTC() || 0, + m = 0 < timeStampInUTC ? moment.unix(timeStampInUTC) : null; + + previewMessage({ + title: this.subject(), + subject: this.subject(), + date: m ? m.format('LLL') : '', + fromCreds: this.fromToLine(false), + toLabel: i18n('MESSAGE/LABEL_TO'), + toCreds: this.toToLine(false) + }, this.body, this.isHtml(), print); } printMessage() { @@ -770,7 +736,7 @@ class MessageModel extends AbstractModel if (this.body) { $('.lazy.lazy-inited[data-original]', this.body).each(function() { - $(this).attr('src', $(this).attr('data-original')).removeAttr('data-original'); + $(this).attr('src', $(this).attr('data-original')).removeAttr('data-original'); // eslint-disable-line no-invalid-this }); } } @@ -781,26 +747,28 @@ class MessageModel extends AbstractModel this.hasImages(false); this.body.data('rl-has-images', false); - var sAttr = this.proxy ? 'data-x-additional-src' : 'data-x-src'; - $('[' + sAttr + ']', this.body).each(function() { - if (lazy && $(this).is('img')) + let attr = this.proxy ? 'data-x-additional-src' : 'data-x-src'; + $('[' + attr + ']', this.body).each(function() { + const $this = $(this); // eslint-disable-line no-invalid-this + if (lazy && $this.is('img')) { - $(this) + $this .addClass('lazy') - .attr('data-original', $(this).attr(sAttr)) - .removeAttr(sAttr); + .attr('data-original', $this.attr(attr)) + .removeAttr(attr); } else { - $(this).attr('src', $(this).attr(sAttr)).removeAttr(sAttr); + $this.attr('src', $this.attr(attr)).removeAttr(attr); } }); - sAttr = this.proxy ? 'data-x-additional-style-url' : 'data-x-style-url'; - $('[' + sAttr + ']', this.body).each(function() { - var sStyle = trim($(this).attr('style')); - sStyle = '' === sStyle ? '' : (';' === sStyle.substr(-1) ? sStyle + ' ' : sStyle + '; '); - $(this).attr('style', sStyle + $(this).attr(sAttr)).removeAttr(sAttr); + attr = this.proxy ? 'data-x-additional-style-url' : 'data-x-style-url'; + $('[' + attr + ']', this.body).each(function() { + const $this = $(this); // eslint-disable-line no-invalid-this + let style = trim($this.attr('style')); + style = '' === style ? '' : (';' === style.substr(-1) ? style + ' ' : style + '; '); + $this.attr('style', style + $this.attr(attr)).removeAttr(attr); }); if (lazy) @@ -824,43 +792,47 @@ class MessageModel extends AbstractModel { this.body.data('rl-init-internal-images', true); - var self = this; + const self = this; $('[data-x-src-cid]', this.body).each(function() { - const attachment = self.findAttachmentByCid($(this).attr('data-x-src-cid')); + const + $this = $(this), // eslint-disable-line no-invalid-this + attachment = self.findAttachmentByCid($this.attr('data-x-src-cid')); + if (attachment && attachment.download) { - if (lazy && $(this).is('img')) + if (lazy && $this.is('img')) { - $(this) + $this .addClass('lazy') .attr('data-original', attachment.linkPreview()); } else { - $(this).attr('src', attachment.linkPreview()); + $this.attr('src', attachment.linkPreview()); } } }); $('[data-x-src-location]', this.body).each(function() { - let attachment = self.findAttachmentByContentLocation($(this).attr('data-x-src-location')); + const $this = $(this); // eslint-disable-line no-invalid-this + let attachment = self.findAttachmentByContentLocation($this.attr('data-x-src-location')); if (!attachment) { - attachment = self.findAttachmentByCid($(this).attr('data-x-src-location')); + attachment = self.findAttachmentByCid($this.attr('data-x-src-location')); } if (attachment && attachment.download) { - if (lazy && $(this).is('img')) + if (lazy && $this.is('img')) { - $(this) + $this .addClass('lazy') .attr('data-original', attachment.linkPreview()); } else { - $(this).attr('src', attachment.linkPreview()); + $this.attr('src', attachment.linkPreview()); } } }); @@ -869,16 +841,19 @@ class MessageModel extends AbstractModel let style = '', name = ''; - const attachment = self.findAttachmentByCid($(this).attr('data-x-style-cid')); + + const + $this = $(this), // eslint-disable-line no-invalid-this + attachment = self.findAttachmentByCid($this.attr('data-x-style-cid')); if (attachment && attachment.linkPreview) { - name = $(this).attr('data-x-style-cid-name'); + name = $this.attr('data-x-style-cid-name'); if ('' !== name) { - style = trim($(this).attr('style')); + style = trim($this.attr('style')); style = '' === style ? '' : (';' === style.substr(-1) ? style + ' ' : style + '; '); - $(this).attr('style', style + name + ': url(\'' + attachment.linkPreview() + '\')'); + $this.attr('style', style + name + ': url(\'' + attachment.linkPreview() + '\')'); } } }); diff --git a/dev/Promises/AbstractAjax.js b/dev/Promises/AbstractAjax.js index c920cc532..2b4fa4ae0 100644 --- a/dev/Promises/AbstractAjax.js +++ b/dev/Promises/AbstractAjax.js @@ -1,223 +1,213 @@ -var - $ = require('$'), - _ = require('_'), - Promise = require('Promise'), +import $ from '$'; +import Promise from 'Promise'; - Consts = require('Common/Consts'), - Enums = require('Common/Enums'), - Globals = require('Common/Globals'), - Utils = require('Common/Utils'), - Links = require('Common/Links'), - Plugins = require('Common/Plugins'), +import {ajax} from 'Common/Links'; +import {microtime, isUnd, isNormal, pString, pInt, inArray} from 'Common/Utils'; +import {DEFAULT_AJAX_TIMEOUT, TOKEN_ERROR_LIMIT, AJAX_ERROR_LIMIT} from 'Common/Consts'; +import {StorageResultType, Notification} from 'Common/Enums'; +import {data as GlobalsData} from 'Common/Globals'; +import * as Plugins from 'Common/Plugins'; +import * as Settings from 'Storage/Settings'; - Settings = require('Storage/Settings'), +import {AbstractBasicPromises} from 'Promises/AbstractBasic'; - AbstractBasicPromises = require('Promises/AbstractBasic'); - -/** -* @constructor -*/ -function AbstractAjaxPromises() +class AbstractAjaxPromises extends AbstractBasicPromises { - AbstractBasicPromises.call(this); - - this.clear(); -} - -_.extend(AbstractAjaxPromises.prototype, AbstractBasicPromises.prototype); - -AbstractAjaxPromises.prototype.oRequests = {}; - -AbstractAjaxPromises.prototype.clear = function() -{ - this.oRequests = {}; -}; - -AbstractAjaxPromises.prototype.abort = function(sAction, bClearOnly) -{ - if (this.oRequests[sAction]) - { - if (!bClearOnly && this.oRequests[sAction].abort) - { - this.oRequests[sAction].__aborted__ = true; - this.oRequests[sAction].abort(); - } - - this.oRequests[sAction] = null; - delete this.oRequests[sAction]; + constructor() { + super(); + this.oRequests = {}; + this.clear(); } - return this; -}; + clear() { + this.oRequests = {}; + } -AbstractAjaxPromises.prototype.ajaxRequest = function(sAction, bPost, iTimeOut, oParameters, sAdditionalGetString, fTrigger) -{ - var self = this; - return new Promise(function(resolve, reject) { - - var iStart = Utils.microtime(); - - iTimeOut = Utils.isNormal(iTimeOut) ? iTimeOut : Consts.DEFAULT_AJAX_TIMEOUT; - sAdditionalGetString = Utils.isUnd(sAdditionalGetString) ? '' : Utils.pString(sAdditionalGetString); - - if (bPost) + abort(sAction, bClearOnly) { + if (this.oRequests[sAction]) { - oParameters.XToken = Settings.appSettingsGet('token'); + if (!bClearOnly && this.oRequests[sAction].abort) + { + this.oRequests[sAction].__aborted__ = true; + this.oRequests[sAction].abort(); + } + + this.oRequests[sAction] = null; + delete this.oRequests[sAction]; } - Plugins.runHook('ajax-default-request', [sAction, oParameters, sAdditionalGetString]); + return this; + } - self.setTrigger(fTrigger, true); + ajaxRequest(action, isPost, timeOut, params, additionalGetString, fTrigger) { - var oH = $.ajax({ - type: bPost ? 'POST' : 'GET', - url: Links.ajax(sAdditionalGetString), - async: true, - dataType: 'json', - data: bPost ? (oParameters || {}) : {}, - timeout: iTimeOut, - global: true - }).always(function(oData, sTextStatus) { + return new Promise((resolve, reject) => { - var - bCached = false, - oErrorData = null; + const start = microtime(); - if (oData && oData.Time) + timeOut = isNormal(timeOut) ? timeOut : DEFAULT_AJAX_TIMEOUT; + additionalGetString = isUnd(additionalGetString) ? '' : pString(additionalGetString); + + if (isPost) { - bCached = Utils.pInt(oData.Time) > Utils.microtime() - iStart; + params.XToken = Settings.appSettingsGet('token'); } - // backward capability - var sType = ''; - switch (true) - { - case 'success' === sTextStatus && oData && oData.Result && sAction === oData.Action: - sType = Enums.StorageResultType.Success; - break; - case 'abort' === sTextStatus && (!oData || !oData.__aborted__): - sType = Enums.StorageResultType.Abort; - break; - default: - sType = Enums.StorageResultType.Error; - break; - } + Plugins.runHook('ajax-default-request', [action, params, additionalGetString]); - Plugins.runHook('ajax-default-response', [sAction, - Enums.StorageResultType.Success === sType ? oData : null, sType, bCached, oParameters]); + this.setTrigger(fTrigger, true); - if ('success' === sTextStatus) - { - if (oData && oData.Result && sAction === oData.Action) + const oH = $.ajax({ + type: isPost ? 'POST' : 'GET', + url: ajax(additionalGetString), + async: true, + dataType: 'json', + data: isPost ? (params || {}) : {}, + timeout: timeOut, + global: true + }).always((data, textStatus) => { + + let + isCached = false, + errorData = null; + + if (data && data.Time) { - oData.__cached__ = bCached; - resolve(oData); + isCached = pInt(data.Time) > microtime() - start; } - else if (oData && oData.Action) + + // backward capability + let type = ''; + switch (true) { - oErrorData = oData; - reject(oData.ErrorCode ? oData.ErrorCode : Enums.Notification.AjaxFalse); + case 'success' === textStatus && data && data.Result && action === data.Action: + type = StorageResultType.Success; + break; + case 'abort' === textStatus && (!data || !data.__aborted__): + type = StorageResultType.Abort; + break; + default: + type = StorageResultType.Error; + break; + } + + Plugins.runHook('ajax-default-response', [ + action, StorageResultType.Success === type ? data : null, type, isCached, params + ]); + + if ('success' === textStatus) + { + if (data && data.Result && action === data.Action) + { + data.__cached__ = isCached; + resolve(data); + } + else if (data && data.Action) + { + errorData = data; + reject(data.ErrorCode ? data.ErrorCode : Notification.AjaxFalse); + } + else + { + errorData = data; + reject(Notification.AjaxParse); + } + } + else if ('timeout' === textStatus) + { + errorData = data; + reject(Notification.AjaxTimeout); + } + else if ('abort' === textStatus) + { + if (!data || !data.__aborted__) + { + reject(Notification.AjaxAbort); + } } else { - oErrorData = oData; - reject(Enums.Notification.AjaxParse); - } - } - else if ('timeout' === sTextStatus) - { - oErrorData = oData; - reject(Enums.Notification.AjaxTimeout); - } - else if ('abort' === sTextStatus) - { - if (!oData || !oData.__aborted__) - { - reject(Enums.Notification.AjaxAbort); - } - } - else - { - oErrorData = oData; - reject(Enums.Notification.AjaxParse); - } - - if (self.oRequests[sAction]) - { - self.oRequests[sAction] = null; - delete self.oRequests[sAction]; - } - - self.setTrigger(fTrigger, false); - - if (oErrorData) - { - if (-1 < Utils.inArray(oErrorData.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.data.iAjaxErrorCount += 1; + errorData = data; + reject(Notification.AjaxParse); } - if (Enums.Notification.InvalidToken === oErrorData.ErrorCode) + if (this.oRequests[action]) { - Globals.data.iTokenErrorCount += 1; + this.oRequests[action] = null; + delete this.oRequests[action]; } - if (Consts.TOKEN_ERROR_LIMIT < Globals.data.iTokenErrorCount) + this.setTrigger(fTrigger, false); + + if (errorData) { - if (Globals.data.__APP__ && Globals.data.__APP__.loginAndLogoutReload) + if (-1 < inArray(errorData.ErrorCode, [ + Notification.AuthError, Notification.AccessError, + Notification.ConnectionError, Notification.DomainNotAllowed, Notification.AccountNotAllowed, + Notification.MailServerError, Notification.UnknownNotification, Notification.UnknownError + ])) { - Globals.data.__APP__.loginAndLogoutReload(false, true); + GlobalsData.iAjaxErrorCount += 1; + } + + if (Notification.InvalidToken === errorData.ErrorCode) + { + GlobalsData.iTokenErrorCount += 1; + } + + if (TOKEN_ERROR_LIMIT < GlobalsData.iTokenErrorCount) + { + if (GlobalsData.__APP__ && GlobalsData.__APP__.loginAndLogoutReload) + { + GlobalsData.__APP__.loginAndLogoutReload(false, true); + } + } + + if (errorData.ClearAuth || errorData.Logout || AJAX_ERROR_LIMIT < GlobalsData.iAjaxErrorCount) + { + if (GlobalsData.__APP__ && GlobalsData.__APP__.clearClientSideToken) + { + GlobalsData.__APP__.clearClientSideToken(); + } + + if (GlobalsData.__APP__ && !errorData.ClearAuth && GlobalsData.__APP__.loginAndLogoutReload) + { + GlobalsData.__APP__.loginAndLogoutReload(false, true); + } } } - if (oErrorData.ClearAuth || oErrorData.Logout || Consts.AJAX_ERROR_LIMIT < Globals.data.iAjaxErrorCount) + }); + + if (oH) + { + if (this.oRequests[action]) { - if (Globals.data.__APP__ && Globals.data.__APP__.clearClientSideToken) - { - Globals.data.__APP__.clearClientSideToken(); - } - - if (Globals.data.__APP__ && !oErrorData.ClearAuth && Globals.data.__APP__.loginAndLogoutReload) - { - Globals.data.__APP__.loginAndLogoutReload(false, true); - } + this.oRequests[action] = null; + delete this.oRequests[action]; } - } + this.oRequests[action] = oH; + } }); + } - if (oH) - { - if (self.oRequests[sAction]) - { - self.oRequests[sAction] = null; - delete self.oRequests[sAction]; - } + getRequest(sAction, fTrigger, sAdditionalGetString, iTimeOut) { - self.oRequests[sAction] = oH; - } - }); -}; + sAdditionalGetString = isUnd(sAdditionalGetString) ? '' : pString(sAdditionalGetString); + sAdditionalGetString = sAction + '/' + sAdditionalGetString; -AbstractAjaxPromises.prototype.getRequest = function(sAction, fTrigger, sAdditionalGetString, iTimeOut) -{ - sAdditionalGetString = Utils.isUnd(sAdditionalGetString) ? '' : Utils.pString(sAdditionalGetString); - sAdditionalGetString = sAction + '/' + sAdditionalGetString; + return this.ajaxRequest(sAction, false, iTimeOut, null, sAdditionalGetString, fTrigger); + } - return this.ajaxRequest(sAction, false, iTimeOut, null, sAdditionalGetString, fTrigger); -}; + postRequest(action, fTrigger, params, timeOut) { -AbstractAjaxPromises.prototype.postRequest = function(action, fTrigger, params, timeOut) -{ - params = params || {}; - params.Action = action; + params = params || {}; + params.Action = action; - return this.ajaxRequest(action, true, timeOut, params, '', fTrigger); -}; + return this.ajaxRequest(action, true, timeOut, params, '', fTrigger); + } +} -module.exports = AbstractAjaxPromises; +export {AbstractAjaxPromises, AbstractAjaxPromises as default}; diff --git a/dev/Promises/AbstractBasic.js b/dev/Promises/AbstractBasic.js index 6d1fb5715..57a87b296 100644 --- a/dev/Promises/AbstractBasic.js +++ b/dev/Promises/AbstractBasic.js @@ -1,45 +1,39 @@ -var - _ = require('_'), - Promise = require('Promise'), +import _ from '_'; +import Promise from 'Promise'; +import {isArray} from 'Common/Utils'; - Utils = require('Common/Utils'); - -/** -* @constructor -*/ -function AbstractBasicPromises() +class AbstractBasicPromises { - this.oPromisesStack = {}; + constructor() { + this.oPromisesStack = {}; + } + + func(fFunc) { + fFunc(); + return this; + } + + fastResolve(mData) { + return Promise.resolve(mData); + } + + fastReject(mData) { + return Promise.reject(mData); + } + + setTrigger(trigger, value) { + if (trigger) + { + value = !!value; + _.each(isArray(trigger) ? trigger : [trigger], (fTrigger) => { + if (fTrigger) + { + fTrigger(value); + } + }); + } + } } -AbstractBasicPromises.prototype.func = function(fFunc) -{ - fFunc(); - return this; -}; - -AbstractBasicPromises.prototype.fastResolve = function(mData) -{ - return Promise.resolve(mData); -}; - -AbstractBasicPromises.prototype.fastReject = function(mData) -{ - return Promise.reject(mData); -}; - -AbstractBasicPromises.prototype.setTrigger = function(mTrigger, bValue) -{ - if (mTrigger) - { - _.each(Utils.isArray(mTrigger) ? mTrigger : [mTrigger], function(fTrigger) { - if (fTrigger) - { - fTrigger(!!bValue); - } - }); - } -}; - -module.exports = AbstractBasicPromises; +export {AbstractBasicPromises, AbstractBasicPromises as default}; diff --git a/dev/Promises/User/Ajax.js b/dev/Promises/User/Ajax.js index ef627d0fe..a8b9b7a06 100644 --- a/dev/Promises/User/Ajax.js +++ b/dev/Promises/User/Ajax.js @@ -1,78 +1,64 @@ -var - window = require('window'), - _ = require('_'), +import window from 'window'; - PromisesPopulator = require('Promises/User/Populator'), - AbstractAjaxPromises = require('Promises/AbstractAjax'); +import PromisesPopulator from 'Promises/User/Populator'; +import {AbstractAjaxPromises} from 'Promises/AbstractAjax'; -/** - * @constructor - * @extends AbstractAjaxPromises - */ -function UserAjaxUserPromises() +class UserAjaxUserPromises extends AbstractAjaxPromises { - AbstractAjaxPromises.call(this); -} + constructor() { + super(); -_.extend(UserAjaxUserPromises.prototype, AbstractAjaxPromises.prototype); + this.foldersTimeout = 0; + } -UserAjaxUserPromises.prototype.foldersReload = function(fTrigger) -{ - return this.abort('Folders') - .postRequest('Folders', fTrigger).then(function(oData) { - PromisesPopulator.foldersList(oData.Result); - PromisesPopulator.foldersAdditionalParameters(oData.Result); + foldersReload(fTrigger) { + return this.abort('Folders').postRequest('Folders', fTrigger).then((data) => { + PromisesPopulator.foldersList(data.Result); + PromisesPopulator.foldersAdditionalParameters(data.Result); return true; }); -}; + } -UserAjaxUserPromises.prototype.foldersTimeout = 0; -UserAjaxUserPromises.prototype.foldersReloadWithTimeout = function(fTrigger) -{ - this.setTrigger(fTrigger, true); + foldersReloadWithTimeout(fTrigger) { + this.setTrigger(fTrigger, true); - var self = this; - window.clearTimeout(this.foldersTimeout); - this.foldersTimeout = window.setTimeout(function() { - self.foldersReload(fTrigger); - }, 500); -}; + window.clearTimeout(this.foldersTimeout); + this.foldersTimeout = window.setTimeout(() => { + this.foldersReload(fTrigger); + }, 500); + } -UserAjaxUserPromises.prototype.folderDelete = function(sFolderFullNameRaw, fTrigger) -{ - return this.postRequest('FolderDelete', fTrigger, { - 'Folder': sFolderFullNameRaw - }); -}; + folderDelete(sFolderFullNameRaw, fTrigger) { + return this.postRequest('FolderDelete', fTrigger, { + 'Folder': sFolderFullNameRaw + }); + } -UserAjaxUserPromises.prototype.folderCreate = function(sNewFolderName, sParentName, fTrigger) -{ - return this.postRequest('FolderCreate', fTrigger, { - 'Folder': sNewFolderName, - 'Parent': sParentName - }); -}; + folderCreate(sNewFolderName, sParentName, fTrigger) { + return this.postRequest('FolderCreate', fTrigger, { + 'Folder': sNewFolderName, + 'Parent': sParentName + }); + } -UserAjaxUserPromises.prototype.folderRename = function(sPrevFolderFullNameRaw, sNewFolderName, fTrigger) -{ - return this.postRequest('FolderRename', fTrigger, { - 'Folder': sPrevFolderFullNameRaw, - 'NewFolderName': sNewFolderName - }); -}; + folderRename(sPrevFolderFullNameRaw, sNewFolderName, fTrigger) { + return this.postRequest('FolderRename', fTrigger, { + 'Folder': sPrevFolderFullNameRaw, + 'NewFolderName': sNewFolderName + }); + } -UserAjaxUserPromises.prototype.attachmentsActions = function(sAction, aHashes, fTrigger) -{ - return this.postRequest('AttachmentsActions', fTrigger, { - 'Do': sAction, - 'Hashes': aHashes - }); -}; + attachmentsActions(sAction, aHashes, fTrigger) { + return this.postRequest('AttachmentsActions', fTrigger, { + 'Do': sAction, + 'Hashes': aHashes + }); + } -UserAjaxUserPromises.prototype.welcomeClose = function() -{ - return this.postRequest('WelcomeClose'); -}; + welcomeClose() { + return this.postRequest('WelcomeClose'); + } +} module.exports = new UserAjaxUserPromises(); diff --git a/dev/Promises/User/Populator.js b/dev/Promises/User/Populator.js index 92970f6dc..55a9840af 100644 --- a/dev/Promises/User/Populator.js +++ b/dev/Promises/User/Populator.js @@ -1,197 +1,183 @@ -var - _ = require('_'), +import _ from '_'; - Consts = require('Common/Consts'), - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Cache = require('Common/Cache'), +import {UNUSED_OPTION_VALUE} from 'Common/Consts'; +import {isArray, isNormal, pInt, isUnd, noop} from 'Common/Utils'; +import {ClientSideKeyName, ServerFolderType} from 'Common/Enums'; +import * as Cache from 'Common/Cache'; - AppStore = require('Stores/User/App'), - FolderStore = require('Stores/User/Folder'), +import * as Settings from 'Storage/Settings'; +import * as Local from 'Storage/Client'; - Settings = require('Storage/Settings'), - Local = require('Storage/Client'), +import AppStore from 'Stores/User/App'; +import FolderStore from 'Stores/User/Folder'; - FolderModel = require('Model/Folder').default, +import {FolderModel} from 'Model/Folder'; +import {AbstractBasicPromises} from 'Promises/AbstractBasic'; - AbstractBasicPromises = require('Promises/AbstractBasic'); - -/** - * @constructor - */ -function PromisesUserPopulator() +class PromisesUserPopulator extends AbstractBasicPromises { - AbstractBasicPromises.call(this); -} + /** + * @param {string} sFullNameHash + * @param {Array?} expandedFolders + * @returns {boolean} + */ + isFolderExpanded(sFullNameHash, expandedFolders) { + return expandedFolders && isArray(expandedFolders) && -1 !== _.indexOf(expandedFolders, sFullNameHash); + } -_.extend(PromisesUserPopulator.prototype, AbstractBasicPromises.prototype); + /** + * @param {string} sFolderFullNameRaw + * @returns {string} + */ + normalizeFolder(sFolderFullNameRaw) { + return ('' === sFolderFullNameRaw || UNUSED_OPTION_VALUE === sFolderFullNameRaw || + null !== Cache.getFolderFromCacheList(sFolderFullNameRaw)) ? sFolderFullNameRaw : ''; + } -/** - * @param {string} sFullNameHash - * @param {Array?} expandedFolders - * @returns {boolean} - */ -PromisesUserPopulator.prototype.isFolderExpanded = function(sFullNameHash, expandedFolders) -{ - return expandedFolders && Utils.isArray(expandedFolders) && -1 !== _.indexOf(expandedFolders, sFullNameHash); -}; + /** + * @param {string} sNamespace + * @param {Array} aFolders + * @param {Array?} expandedFolders + * @returns {Array} + */ + folderResponseParseRec(sNamespace, aFolders, expandedFolders) { -/** - * @param {string} sFolderFullNameRaw - * @returns {string} - */ -PromisesUserPopulator.prototype.normalizeFolder = function(sFolderFullNameRaw) -{ - return ('' === sFolderFullNameRaw || Consts.UNUSED_OPTION_VALUE === sFolderFullNameRaw || - null !== Cache.getFolderFromCacheList(sFolderFullNameRaw)) ? sFolderFullNameRaw : ''; -}; + const + bDisplaySpecSetting = FolderStore.displaySpecSetting(), + aList = []; -/** - * @param {string} sNamespace - * @param {Array} aFolders - * @param {Array?} expandedFolders - * @returns {Array} - */ -PromisesUserPopulator.prototype.folderResponseParseRec = function(sNamespace, aFolders, expandedFolders) -{ - var - self = this, - bDisplaySpecSetting = FolderStore.displaySpecSetting(), - aList = []; - - _.each(aFolders, function(oFolder) { - if (oFolder) - { - var oCacheFolder = Cache.getFolderFromCacheList(oFolder.FullNameRaw); - if (!oCacheFolder) + _.each(aFolders, (oFolder) => { + if (oFolder) { - oCacheFolder = FolderModel.newInstanceFromJson(oFolder); + let oCacheFolder = Cache.getFolderFromCacheList(oFolder.FullNameRaw); + if (!oCacheFolder) + { + oCacheFolder = FolderModel.newInstanceFromJson(oFolder); + if (oCacheFolder) + { + Cache.setFolderToCacheList(oFolder.FullNameRaw, oCacheFolder); + Cache.setFolderFullNameRaw(oCacheFolder.fullNameHash, oFolder.FullNameRaw, oCacheFolder); + } + } + if (oCacheFolder) { - Cache.setFolderToCacheList(oFolder.FullNameRaw, oCacheFolder); - Cache.setFolderFullNameRaw(oCacheFolder.fullNameHash, oFolder.FullNameRaw, oCacheFolder); + if (bDisplaySpecSetting) + { + oCacheFolder.checkable(!!oFolder.Checkable); + } + else + { + oCacheFolder.checkable(true); + } + + oCacheFolder.collapsed(!this.isFolderExpanded(oCacheFolder.fullNameHash, expandedFolders)); + + if (oFolder.Extended) + { + if (oFolder.Extended.Hash) + { + Cache.setFolderHash(oCacheFolder.fullNameRaw, oFolder.Extended.Hash); + } + + if (isNormal(oFolder.Extended.MessageCount)) + { + oCacheFolder.messageCountAll(oFolder.Extended.MessageCount); + } + + if (isNormal(oFolder.Extended.MessageUnseenCount)) + { + oCacheFolder.messageCountUnread(oFolder.Extended.MessageUnseenCount); + } + } + + if (oFolder.SubFolders && 'Collection/FolderCollection' === oFolder.SubFolders['@Object'] && + oFolder.SubFolders['@Collection'] && isArray(oFolder.SubFolders['@Collection'])) + { + oCacheFolder.subFolders( + this.folderResponseParseRec(sNamespace, oFolder.SubFolders['@Collection'], expandedFolders)); + } + + aList.push(oCacheFolder); } } + }); - if (oCacheFolder) + return aList; + } + + foldersList(oData) { + if (oData && 'Collection/FolderCollection' === oData['@Object'] && + oData['@Collection'] && isArray(oData['@Collection'])) + { + const + expandedFolders = Local.get(ClientSideKeyName.ExpandedFolders), + cnt = pInt(oData.CountRec); + + let limit = pInt(Settings.appSettingsGet('folderSpecLimit')); + limit = 100 < limit ? 100 : (10 > limit ? 10 : limit); + + FolderStore.displaySpecSetting(0 >= cnt || limit < cnt); + + FolderStore.folderList(this.folderResponseParseRec( + isUnd(oData.Namespace) ? '' : oData.Namespace, oData['@Collection'], expandedFolders)); // @todo optimization required + } + } + + foldersAdditionalParameters(oData) { + if (oData && oData && 'Collection/FolderCollection' === oData['@Object'] && + oData['@Collection'] && isArray(oData['@Collection'])) + { + if (!isUnd(oData.Namespace)) { - if (bDisplaySpecSetting) - { - oCacheFolder.checkable(!!oFolder.Checkable); - } - else - { - oCacheFolder.checkable(true); - } - - oCacheFolder.collapsed(!self.isFolderExpanded(oCacheFolder.fullNameHash, expandedFolders)); - - if (oFolder.Extended) - { - if (oFolder.Extended.Hash) - { - Cache.setFolderHash(oCacheFolder.fullNameRaw, oFolder.Extended.Hash); - } - - if (Utils.isNormal(oFolder.Extended.MessageCount)) - { - oCacheFolder.messageCountAll(oFolder.Extended.MessageCount); - } - - if (Utils.isNormal(oFolder.Extended.MessageUnseenCount)) - { - oCacheFolder.messageCountUnread(oFolder.Extended.MessageUnseenCount); - } - } - - if (oFolder.SubFolders && 'Collection/FolderCollection' === oFolder.SubFolders['@Object'] && - oFolder.SubFolders['@Collection'] && Utils.isArray(oFolder.SubFolders['@Collection'])) - { - oCacheFolder.subFolders( - self.folderResponseParseRec(sNamespace, oFolder.SubFolders['@Collection'], expandedFolders)); - } - - aList.push(oCacheFolder); + FolderStore.namespace = oData.Namespace; } + + AppStore.threadsAllowed(!!Settings.appSettingsGet('useImapThread') && oData.IsThreadsSupported && true); + + FolderStore.folderList.optimized(!!oData.Optimized); + + let update = false; + + if (oData.SystemFolders && '' === '' + + Settings.settingsGet('SentFolder') + + Settings.settingsGet('DraftFolder') + + Settings.settingsGet('SpamFolder') + + Settings.settingsGet('TrashFolder') + + Settings.settingsGet('ArchiveFolder') + + Settings.settingsGet('NullFolder')) + { + Settings.settingsSet('SentFolder', oData.SystemFolders[ServerFolderType.SENT] || null); + Settings.settingsSet('DraftFolder', oData.SystemFolders[ServerFolderType.DRAFTS] || null); + Settings.settingsSet('SpamFolder', oData.SystemFolders[ServerFolderType.JUNK] || null); + Settings.settingsSet('TrashFolder', oData.SystemFolders[ServerFolderType.TRASH] || null); + Settings.settingsSet('ArchiveFolder', oData.SystemFolders[ServerFolderType.ALL] || null); + + update = true; + } + + FolderStore.sentFolder(this.normalizeFolder(Settings.settingsGet('SentFolder'))); + FolderStore.draftFolder(this.normalizeFolder(Settings.settingsGet('DraftFolder'))); + FolderStore.spamFolder(this.normalizeFolder(Settings.settingsGet('SpamFolder'))); + FolderStore.trashFolder(this.normalizeFolder(Settings.settingsGet('TrashFolder'))); + FolderStore.archiveFolder(this.normalizeFolder(Settings.settingsGet('ArchiveFolder'))); + + if (update) + { + require('Remote/User/Ajax').saveSystemFolders(noop, { + SentFolder: FolderStore.sentFolder(), + DraftFolder: FolderStore.draftFolder(), + SpamFolder: FolderStore.spamFolder(), + TrashFolder: FolderStore.trashFolder(), + ArchiveFolder: FolderStore.archiveFolder(), + NullFolder: 'NullFolder' + }); + } + + Local.set(ClientSideKeyName.FoldersLashHash, oData.FoldersHash); } - }); - - return aList; -}; - -PromisesUserPopulator.prototype.foldersList = function(oData) -{ - if (oData && 'Collection/FolderCollection' === oData['@Object'] && - oData['@Collection'] && Utils.isArray(oData['@Collection'])) - { - var - expandedFolders = Local.get(Enums.ClientSideKeyName.ExpandedFolders), - iLimit = Utils.pInt(Settings.appSettingsGet('folderSpecLimit')), - iC = Utils.pInt(oData.CountRec); - - iLimit = 100 < iLimit ? 100 : (10 > iLimit ? 10 : iLimit); - - FolderStore.displaySpecSetting(0 >= iC || iLimit < iC); - - FolderStore.folderList(this.folderResponseParseRec( - Utils.isUnd(oData.Namespace) ? '' : oData.Namespace, oData['@Collection'], expandedFolders)); // @todo optimization required } -}; - -PromisesUserPopulator.prototype.foldersAdditionalParameters = function(oData) -{ - if (oData && oData && 'Collection/FolderCollection' === oData['@Object'] && - oData['@Collection'] && Utils.isArray(oData['@Collection'])) - { - if (!Utils.isUnd(oData.Namespace)) - { - FolderStore.namespace = oData.Namespace; - } - - AppStore.threadsAllowed(!!Settings.appSettingsGet('useImapThread') && oData.IsThreadsSupported && true); - - FolderStore.folderList.optimized(!!oData.Optimized); - - var bUpdate = false; - - if (oData.SystemFolders && '' === '' + - Settings.settingsGet('SentFolder') + - Settings.settingsGet('DraftFolder') + - Settings.settingsGet('SpamFolder') + - Settings.settingsGet('TrashFolder') + - Settings.settingsGet('ArchiveFolder') + - Settings.settingsGet('NullFolder')) - { - Settings.settingsSet('SentFolder', oData.SystemFolders[Enums.ServerFolderType.SENT] || null); - Settings.settingsSet('DraftFolder', oData.SystemFolders[Enums.ServerFolderType.DRAFTS] || null); - Settings.settingsSet('SpamFolder', oData.SystemFolders[Enums.ServerFolderType.JUNK] || null); - Settings.settingsSet('TrashFolder', oData.SystemFolders[Enums.ServerFolderType.TRASH] || null); - Settings.settingsSet('ArchiveFolder', oData.SystemFolders[Enums.ServerFolderType.ALL] || null); - - bUpdate = true; - } - - FolderStore.sentFolder(this.normalizeFolder(Settings.settingsGet('SentFolder'))); - FolderStore.draftFolder(this.normalizeFolder(Settings.settingsGet('DraftFolder'))); - FolderStore.spamFolder(this.normalizeFolder(Settings.settingsGet('SpamFolder'))); - FolderStore.trashFolder(this.normalizeFolder(Settings.settingsGet('TrashFolder'))); - FolderStore.archiveFolder(this.normalizeFolder(Settings.settingsGet('ArchiveFolder'))); - - if (bUpdate) - { - require('Remote/User/Ajax').saveSystemFolders(Utils.noop, { - SentFolder: FolderStore.sentFolder(), - DraftFolder: FolderStore.draftFolder(), - SpamFolder: FolderStore.spamFolder(), - TrashFolder: FolderStore.trashFolder(), - ArchiveFolder: FolderStore.archiveFolder(), - NullFolder: 'NullFolder' - }); - } - - Local.set(Enums.ClientSideKeyName.FoldersLashHash, oData.FoldersHash); - } -}; +} module.exports = new PromisesUserPopulator(); diff --git a/dev/Remote/AbstractAjax.js b/dev/Remote/AbstractAjax.js index 9888a2dd5..0fcbd6bc6 100644 --- a/dev/Remote/AbstractAjax.js +++ b/dev/Remote/AbstractAjax.js @@ -1,301 +1,286 @@ -var - window = require('window'), - _ = require('_'), - $ = require('$'), +import window from 'window'; +import _ from '_'; +import $ from '$'; - Consts = require('Common/Consts'), - Enums = require('Common/Enums'), - Globals = require('Common/Globals'), - Utils = require('Common/Utils'), - Plugins = require('Common/Plugins'), - Links = require('Common/Links'), +import {TOKEN_ERROR_LIMIT, AJAX_ERROR_LIMIT, DEFAULT_AJAX_TIMEOUT} from 'Common/Consts'; +import {StorageResultType, Notification} from 'Common/Enums'; +import {inArray, pInt, pString, isUnd} from 'Common/Utils'; +import {data as GlobalsData} from 'Common/Globals'; +import {ajax} from 'Common/Links'; +import {runHook} from 'Common/Plugins'; - Settings = require('Storage/Settings'); +import * as Settings from 'Storage/Settings'; -/** -* @constructor -*/ -function AbstractAjaxRemote() +class AbstractAjaxRemote { - this.oRequests = {}; -} + constructor() { + this.oRequests = {}; + } -AbstractAjaxRemote.prototype.oRequests = {}; - -/** - * @param {?Function} fCallback - * @param {string} sRequestAction - * @param {string} sType - * @param {?AjaxJsonDefaultResponse} oData - * @param {boolean} bCached - * @param {*=} oRequestParameters - */ -AbstractAjaxRemote.prototype.defaultResponse = function(fCallback, sRequestAction, sType, oData, bCached, oRequestParameters) -{ - var - fCall = function() { - if (Enums.StorageResultType.Success !== sType && Globals.data.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 - ])) + /** + * @param {?Function} fCallback + * @param {string} sRequestAction + * @param {string} sType + * @param {?AjaxJsonDefaultResponse} oData + * @param {boolean} bCached + * @param {*=} oRequestParameters + */ + defaultResponse(fCallback, sRequestAction, sType, oData, bCached, oRequestParameters) { + const + fCall = () => { + if (StorageResultType.Success !== sType && GlobalsData.bUnload) { - Globals.data.iAjaxErrorCount += 1; + sType = StorageResultType.Unload; } - if (oData && Enums.Notification.InvalidToken === oData.ErrorCode) + if (StorageResultType.Success === sType && oData && !oData.Result) { - Globals.data.iTokenErrorCount += 1; - } - - if (Consts.TOKEN_ERROR_LIMIT < Globals.data.iTokenErrorCount) - { - if (Globals.data.__APP__ && Globals.data.__APP__.loginAndLogoutReload) + if (oData && -1 < inArray(oData.ErrorCode, [ + Notification.AuthError, Notification.AccessError, + Notification.ConnectionError, Notification.DomainNotAllowed, Notification.AccountNotAllowed, + Notification.MailServerError, Notification.UnknownNotification, Notification.UnknownError + ])) { - Globals.data.__APP__.loginAndLogoutReload(false, true); + GlobalsData.iAjaxErrorCount += 1; } - } - if (oData.ClearAuth || oData.Logout || Consts.AJAX_ERROR_LIMIT < Globals.data.iAjaxErrorCount) - { - if (Globals.data.__APP__ && Globals.data.__APP__.clearClientSideToken) + if (oData && Notification.InvalidToken === oData.ErrorCode) { - Globals.data.__APP__.clearClientSideToken(); + GlobalsData.iTokenErrorCount += 1; + } - if (!oData.ClearAuth && Globals.data.__APP__.loginAndLogoutReload) + if (TOKEN_ERROR_LIMIT < GlobalsData.iTokenErrorCount) + { + if (GlobalsData.__APP__ && GlobalsData.__APP__.loginAndLogoutReload) { - Globals.data.__APP__.loginAndLogoutReload(false, true); + GlobalsData.__APP__.loginAndLogoutReload(false, true); + } + } + + if (oData.ClearAuth || oData.Logout || AJAX_ERROR_LIMIT < GlobalsData.iAjaxErrorCount) + { + if (GlobalsData.__APP__ && GlobalsData.__APP__.clearClientSideToken) + { + GlobalsData.__APP__.clearClientSideToken(); + + if (!oData.ClearAuth && GlobalsData.__APP__.loginAndLogoutReload) + { + GlobalsData.__APP__.loginAndLogoutReload(false, true); + } } } } - } - else if (Enums.StorageResultType.Success === sType && oData && oData.Result) - { - Globals.data.iAjaxErrorCount = 0; - Globals.data.iTokenErrorCount = 0; - } - - Plugins.runHook('ajax-default-response', [sRequestAction, Enums.StorageResultType.Success === sType ? oData : null, sType, bCached, oRequestParameters]); - - if (fCallback) - { - 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 = [] - * @returns {jQuery.jqXHR} - */ -AbstractAjaxRemote.prototype.ajaxRequest = function(fResultCallback, oParameters, iTimeOut, sGetAdd, aAbortActions) -{ - var - self = this, - bPost = '' === sGetAdd, - oHeaders = {}, - iStart = (new window.Date()).getTime(), - 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) + else if (StorageResultType.Success === sType && oData && oData.Result) { - self.oRequests[sActionToAbort].abort(); + GlobalsData.iAjaxErrorCount = 0; + GlobalsData.iTokenErrorCount = 0; } - self.oRequests[sActionToAbort] = null; + + runHook('ajax-default-response', [sRequestAction, StorageResultType.Success === sType ? oData : null, sType, bCached, oRequestParameters]); + + if (fCallback) + { + fCallback( + sType, + StorageResultType.Success === sType ? oData : null, + bCached, + sRequestAction, + oRequestParameters + ); + } + }; + + switch (sType) + { + case 'success': + sType = StorageResultType.Success; + break; + case 'abort': + sType = StorageResultType.Abort; + break; + default: + sType = StorageResultType.Error; + break; + } + + if (StorageResultType.Error === sType) + { + _.delay(fCall, 300); + } + else + { + fCall(); + } + } + + /** + * @param {?Function} fResultCallback + * @param {Object} oParameters + * @param {?number=} iTimeOut = 20000 + * @param {string=} sGetAdd = '' + * @param {Array=} aAbortActions = [] + * @returns {jQuery.jqXHR} + */ + ajaxRequest(fResultCallback, params, iTimeOut = 20000, sGetAdd = '', abortActions = []) { + const + isPost = '' === sGetAdd, + headers = {}, + start = (new window.Date()).getTime(); + + let + action = ''; + + params = params || {}; + action = params.Action || ''; + + if (action && 0 < abortActions.length) + { + _.each(abortActions, (actionToAbort) => { + if (this.oRequests[actionToAbort]) + { + this.oRequests[actionToAbort].__aborted = true; + if (this.oRequests[actionToAbort].abort) + { + this.oRequests[actionToAbort].abort(); + } + this.oRequests[actionToAbort] = null; + } + }); + } + + if (isPost) + { + params.XToken = Settings.appSettingsGet('token'); + } + + const oDefAjax = $.ajax({ + type: isPost ? 'POST' : 'GET', + url: ajax(sGetAdd), + async: true, + dataType: 'json', + data: isPost ? params : {}, + headers: headers, + timeout: iTimeOut, + global: true + }); + + oDefAjax.always((oData, sType) => { + + let cached = false; + if (oData && oData.Time) + { + cached = pInt(oData.Time) > (new window.Date()).getTime() - start; } + + if (action && this.oRequests[action]) + { + if (this.oRequests[action].__aborted) + { + sType = 'abort'; + } + + this.oRequests[action] = null; + } + + this.defaultResponse(fResultCallback, action, sType, oData, cached, params); + }); + + if (action && 0 < abortActions.length && -1 < inArray(action, abortActions)) + { + if (this.oRequests[action]) + { + this.oRequests[action].__aborted = true; + if (this.oRequests[action].abort) + { + this.oRequests[action].abort(); + } + this.oRequests[action] = null; + } + + this.oRequests[action] = oDefAjax; + } + + return oDefAjax; + } + + /** + * @param {?Function} fCallback + * @param {string} sAction + * @param {Object=} oParameters + * @param {?number=} iTimeout + * @param {string=} sGetAdd = '' + * @param {Array=} aAbortActions = [] + */ + defaultRequest(fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions) { + oParameters = oParameters || {}; + oParameters.Action = sAction; + + sGetAdd = pString(sGetAdd); + + runHook('ajax-default-request', [sAction, oParameters, sGetAdd]); + + return this.ajaxRequest(fCallback, oParameters, + isUnd(iTimeout) ? DEFAULT_AJAX_TIMEOUT : pInt(iTimeout), sGetAdd, aAbortActions); + } + + /** + * @param {?Function} fCallback + */ + noop(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 + */ + jsError(fCallback, sMessage, sFileName, iLineNo, sLocation, sHtmlCapa, iTime) { + this.defaultRequest(fCallback, 'JsError', { + 'Message': sMessage, + 'FileName': sFileName, + 'LineNo': iLineNo, + 'Location': sLocation, + 'HtmlCapa': sHtmlCapa, + 'TimeOnPage': iTime }); } - if (bPost) - { - oParameters.XToken = Settings.appSettingsGet('token'); + /** + * @param {?Function} fCallback + * @param {string} sType + * @param {Array=} mData = null + * @param {boolean=} bIsError = false + */ + jsInfo(fCallback, sType, mData, bIsError = false) { + this.defaultRequest(fCallback, 'JsInfo', { + 'Type': sType, + 'Data': mData, + 'IsError': bIsError ? '1' : '0' + }); } - var oDefAjax = $.ajax({ - type: bPost ? 'POST' : 'GET', - url: Links.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; + /** + * @param {?Function} fCallback + */ + getPublicKey(fCallback) { + this.defaultRequest(fCallback, 'GetPublicKey'); } - return oDefAjax; -}; + /** + * @param {?Function} fCallback + * @param {string} sVersion + */ + jsVersion(fCallback, sVersion) { + this.defaultRequest(fCallback, 'Version', { + 'Version': sVersion + }); + } +} -/** - * @param {?Function} fCallback - * @param {string} sAction - * @param {Object=} oParameters - * @param {?number=} iTimeout - * @param {string=} sGetAdd = '' - * @param {Array=} aAbortActions = [] - */ -AbstractAjaxRemote.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]); - - return this.ajaxRequest(fCallback, oParameters, - Utils.isUnd(iTimeout) ? Consts.DEFAULT_AJAX_TIMEOUT : Utils.pInt(iTimeout), sGetAdd, aAbortActions); -}; - -/** - * @param {?Function} fCallback - */ -AbstractAjaxRemote.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 - */ -AbstractAjaxRemote.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 - */ -AbstractAjaxRemote.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 - */ -AbstractAjaxRemote.prototype.getPublicKey = function(fCallback) -{ - this.defaultRequest(fCallback, 'GetPublicKey'); -}; - -/** - * @param {?Function} fCallback - * @param {string} sVersion - */ -AbstractAjaxRemote.prototype.jsVersion = function(fCallback, sVersion) -{ - this.defaultRequest(fCallback, 'Version', { - 'Version': sVersion - }); -}; - -module.exports = AbstractAjaxRemote; +export {AbstractAjaxRemote, AbstractAjaxRemote as default}; diff --git a/dev/Remote/Admin/Ajax.js b/dev/Remote/Admin/Ajax.js index 62d57b573..86b4649cd 100644 --- a/dev/Remote/Admin/Ajax.js +++ b/dev/Remote/Admin/Ajax.js @@ -1,316 +1,282 @@ -var - _ = require('_'), +import {AbstractAjaxRemote} from 'Remote/AbstractAjax'; - Utils = require('Common/Utils'), - - AbstractAjaxRemote = require('Remote/AbstractAjax'); - -/** - * @constructor - * @extends AbstractAjaxRemote - */ -function RemoteAdminAjax() +class RemoteAdminAjax extends AbstractAjaxRemote { - AbstractAjaxRemote.call(this); + constructor() { + super(); - this.oRequests = {}; + this.oRequests = {}; + } + + /** + * @param {?Function} fCallback + * @param {string} sLogin + * @param {string} sPassword + */ + adminLogin(fCallback, sLogin, sPassword) { + this.defaultRequest(fCallback, 'AdminLogin', { + 'Login': sLogin, + 'Password': sPassword + }); + } + + /** + * @param {?Function} fCallback + */ + adminLogout(fCallback) { + this.defaultRequest(fCallback, 'AdminLogout'); + } + + /** + * @param {?Function} fCallback + * @param {?} oData + */ + saveAdminConfig(fCallback, oData) { + this.defaultRequest(fCallback, 'AdminSettingsUpdate', oData); + } + + /** + * @param {string} key + * @param {?Function} valueFn + * @param {?Function} fn + */ + saveAdminConfigHelper(key, valueFn, fn) { + return (value) => { + const data = {}; + data[key] = valueFn ? valueFn(value) : value; + this.saveAdminConfig(fn || null, data); + }; + } + + /** + * @param {?Function} fCallback + * @param {boolean=} bIncludeAliases = true + */ + domainList(fCallback, bIncludeAliases = true) { + this.defaultRequest(fCallback, 'AdminDomainList', { + 'IncludeAliases': bIncludeAliases ? '1' : '0' + }); + } + + /** + * @param {?Function} fCallback + */ + pluginList(fCallback) { + this.defaultRequest(fCallback, 'AdminPluginList'); + } + + /** + * @param {?Function} fCallback + */ + packagesList(fCallback) { + this.defaultRequest(fCallback, 'AdminPackagesList'); + } + + /** + * @param {?Function} fCallback + */ + coreData(fCallback) { + this.defaultRequest(fCallback, 'AdminCoreData'); + } + + /** + * @param {?Function} fCallback + */ + updateCoreData(fCallback) { + this.defaultRequest(fCallback, 'AdminUpdateCoreData', {}, 90000); + } + + /** + * @param {?Function} fCallback + * @param {Object} oPackage + */ + packageInstall(fCallback, oPackage) { + this.defaultRequest(fCallback, 'AdminPackageInstall', { + 'Id': oPackage.id, + 'Type': oPackage.type, + 'File': oPackage.file + }, 60000); + } + + /** + * @param {?Function} fCallback + * @param {Object} oPackage + */ + packageDelete(fCallback, oPackage) { + this.defaultRequest(fCallback, 'AdminPackageDelete', { + 'Id': oPackage.id + }); + } + + /** + * @param {?Function} fCallback + * @param {string} sName + */ + domain(fCallback, sName) { + this.defaultRequest(fCallback, 'AdminDomainLoad', { + 'Name': sName + }); + } + + /** + * @param {?Function} fCallback + * @param {string} sName + */ + plugin(fCallback, sName) { + this.defaultRequest(fCallback, 'AdminPluginLoad', { + 'Name': sName + }); + } + + /** + * @param {?Function} fCallback + * @param {string} sName + */ + domainDelete(fCallback, sName) { + this.defaultRequest(fCallback, 'AdminDomainDelete', { + 'Name': sName + }); + } + + /** + * @param {?Function} fCallback + * @param {string} sName + * @param {boolean} bDisabled + */ + domainDisable(fCallback, sName, bDisabled) { + return this.defaultRequest(fCallback, 'AdminDomainDisable', { + Name: sName, + Disabled: bDisabled ? '1' : '0' + }); + } + + /** + * @param {?Function} fCallback + * @param {Object} oConfig + */ + pluginSettingsUpdate(fCallback, oConfig) { + return this.defaultRequest(fCallback, 'AdminPluginSettingsUpdate', oConfig); + } + + /** + * @param {?Function} fCallback + * @param {boolean} bForce + */ + licensing(fCallback, bForce) { + return this.defaultRequest(fCallback, 'AdminLicensing', { + Force: bForce ? '1' : '0' + }); + } + + /** + * @param {?Function} fCallback + * @param {string} sDomain + * @param {string} sKey + */ + licensingActivate(fCallback, sDomain, sKey) { + return this.defaultRequest(fCallback, 'AdminLicensingActivate', { + Domain: sDomain, + Key: sKey + }); + } + + /** + * @param {?Function} fCallback + * @param {string} sName + * @param {boolean} bDisabled + */ + pluginDisable(fCallback, sName, bDisabled) { + return this.defaultRequest(fCallback, 'AdminPluginDisable', { + Name: sName, + Disabled: bDisabled ? '1' : '0' + }); + } + + createDomainAlias(fCallback, sName, sAlias) { + this.defaultRequest(fCallback, 'AdminDomainAliasSave', { + Name: sName, + Alias: sAlias + }); + } + + createOrUpdateDomain(fCallback, + bCreate, sName, + sIncHost, iIncPort, sIncSecure, bIncShortLogin, + bUseSieve, sSieveAllowRaw, sSieveHost, iSievePort, sSieveSecure, + sOutHost, iOutPort, sOutSecure, bOutShortLogin, bOutAuth, bOutPhpMail, + sWhiteList + ) { + this.defaultRequest(fCallback, 'AdminDomainSave', { + 'Create': bCreate ? '1' : '0', + 'Name': sName, + + 'IncHost': sIncHost, + 'IncPort': iIncPort, + 'IncSecure': sIncSecure, + 'IncShortLogin': bIncShortLogin ? '1' : '0', + + 'UseSieve': bUseSieve ? '1' : '0', + 'SieveAllowRaw': sSieveAllowRaw ? '1' : '0', + 'SieveHost': sSieveHost, + 'SievePort': iSievePort, + 'SieveSecure': sSieveSecure, + + 'OutHost': sOutHost, + 'OutPort': iOutPort, + 'OutSecure': sOutSecure, + 'OutShortLogin': bOutShortLogin ? '1' : '0', + 'OutAuth': bOutAuth ? '1' : '0', + 'OutUsePhpMail': bOutPhpMail ? '1' : '0', + + 'WhiteList': sWhiteList + }); + } + + testConnectionForDomain(fCallback, sName, + sIncHost, iIncPort, sIncSecure, + bUseSieve, sSieveHost, iSievePort, sSieveSecure, + sOutHost, iOutPort, sOutSecure, bOutAuth, bOutPhpMail + ) { + this.defaultRequest(fCallback, 'AdminDomainTest', { + 'Name': sName, + 'IncHost': sIncHost, + 'IncPort': iIncPort, + 'IncSecure': sIncSecure, + 'UseSieve': bUseSieve ? '1' : '0', + 'SieveHost': sSieveHost, + 'SievePort': iSievePort, + 'SieveSecure': sSieveSecure, + 'OutHost': sOutHost, + 'OutPort': iOutPort, + 'OutSecure': sOutSecure, + 'OutAuth': bOutAuth ? '1' : '0', + 'OutUsePhpMail': bOutPhpMail ? '1' : '0' + }); + } + + /** + * @param {?Function} fCallback + * @param {?} oData + */ + testContacts(fCallback, oData) { + this.defaultRequest(fCallback, 'AdminContactsTest', oData); + } + + /** + * @param {?Function} fCallback + * @param {?} oData + */ + saveNewAdminPassword(fCallback, oData) { + this.defaultRequest(fCallback, 'AdminPasswordUpdate', oData); + } + + /** + * @param {?Function} fCallback + */ + adminPing(fCallback) { + this.defaultRequest(fCallback, 'AdminPing'); + } } -_.extend(RemoteAdminAjax.prototype, AbstractAjaxRemote.prototype); - -/** - * @param {?Function} fCallback - * @param {string} sLogin - * @param {string} sPassword - */ -RemoteAdminAjax.prototype.adminLogin = function(fCallback, sLogin, sPassword) -{ - this.defaultRequest(fCallback, 'AdminLogin', { - 'Login': sLogin, - 'Password': sPassword - }); -}; - -/** - * @param {?Function} fCallback - */ -RemoteAdminAjax.prototype.adminLogout = function(fCallback) -{ - this.defaultRequest(fCallback, 'AdminLogout'); -}; - -/** - * @param {?Function} fCallback - * @param {?} oData - */ -RemoteAdminAjax.prototype.saveAdminConfig = function(fCallback, oData) -{ - this.defaultRequest(fCallback, 'AdminSettingsUpdate', oData); -}; - -/** - * @param {string} key - * @param {?Function} valueFn - * @param {?Function} fn - */ -RemoteAdminAjax.prototype.saveAdminConfigHelper = function(key, valueFn, fn) -{ - var self = this; - return function(value) { - var data = {}; - data[key] = valueFn ? valueFn(value) : value; - self.saveAdminConfig(fn || null, data); - }; -}; - -/** - * @param {?Function} fCallback - * @param {boolean=} bIncludeAliases = true - */ -RemoteAdminAjax.prototype.domainList = function(fCallback, bIncludeAliases) -{ - bIncludeAliases = Utils.isUnd(bIncludeAliases) ? true : bIncludeAliases; - this.defaultRequest(fCallback, 'AdminDomainList', { - 'IncludeAliases': bIncludeAliases ? '1' : '0' - }); -}; - -/** - * @param {?Function} fCallback - */ -RemoteAdminAjax.prototype.pluginList = function(fCallback) -{ - this.defaultRequest(fCallback, 'AdminPluginList'); -}; - -/** - * @param {?Function} fCallback - */ -RemoteAdminAjax.prototype.packagesList = function(fCallback) -{ - this.defaultRequest(fCallback, 'AdminPackagesList'); -}; - -/** - * @param {?Function} fCallback - */ -RemoteAdminAjax.prototype.coreData = function(fCallback) -{ - this.defaultRequest(fCallback, 'AdminCoreData'); -}; - -/** - * @param {?Function} fCallback - */ -RemoteAdminAjax.prototype.updateCoreData = function(fCallback) -{ - this.defaultRequest(fCallback, 'AdminUpdateCoreData', {}, 90000); -}; - -/** - * @param {?Function} fCallback - * @param {Object} oPackage - */ -RemoteAdminAjax.prototype.packageInstall = function(fCallback, oPackage) -{ - this.defaultRequest(fCallback, 'AdminPackageInstall', { - 'Id': oPackage.id, - 'Type': oPackage.type, - 'File': oPackage.file - }, 60000); -}; - -/** - * @param {?Function} fCallback - * @param {Object} oPackage - */ -RemoteAdminAjax.prototype.packageDelete = function(fCallback, oPackage) -{ - this.defaultRequest(fCallback, 'AdminPackageDelete', { - 'Id': oPackage.id - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sName - */ -RemoteAdminAjax.prototype.domain = function(fCallback, sName) -{ - this.defaultRequest(fCallback, 'AdminDomainLoad', { - 'Name': sName - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sName - */ -RemoteAdminAjax.prototype.plugin = function(fCallback, sName) -{ - this.defaultRequest(fCallback, 'AdminPluginLoad', { - 'Name': sName - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sName - */ -RemoteAdminAjax.prototype.domainDelete = function(fCallback, sName) -{ - this.defaultRequest(fCallback, 'AdminDomainDelete', { - 'Name': sName - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sName - * @param {boolean} bDisabled - */ -RemoteAdminAjax.prototype.domainDisable = function(fCallback, sName, bDisabled) -{ - return this.defaultRequest(fCallback, 'AdminDomainDisable', { - Name: sName, - Disabled: bDisabled ? '1' : '0' - }); -}; - -/** - * @param {?Function} fCallback - * @param {Object} oConfig - */ -RemoteAdminAjax.prototype.pluginSettingsUpdate = function(fCallback, oConfig) -{ - return this.defaultRequest(fCallback, 'AdminPluginSettingsUpdate', oConfig); -}; - -/** - * @param {?Function} fCallback - * @param {boolean} bForce - */ -RemoteAdminAjax.prototype.licensing = function(fCallback, bForce) -{ - return this.defaultRequest(fCallback, 'AdminLicensing', { - Force: bForce ? '1' : '0' - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sDomain - * @param {string} sKey - */ -RemoteAdminAjax.prototype.licensingActivate = function(fCallback, sDomain, sKey) -{ - return this.defaultRequest(fCallback, 'AdminLicensingActivate', { - Domain: sDomain, - Key: sKey - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sName - * @param {boolean} bDisabled - */ -RemoteAdminAjax.prototype.pluginDisable = function(fCallback, sName, bDisabled) -{ - return this.defaultRequest(fCallback, 'AdminPluginDisable', { - Name: sName, - Disabled: bDisabled ? '1' : '0' - }); -}; - -RemoteAdminAjax.prototype.createDomainAlias = function(fCallback, sName, sAlias) -{ - this.defaultRequest(fCallback, 'AdminDomainAliasSave', { - Name: sName, - Alias: sAlias - }); -}; - -RemoteAdminAjax.prototype.createOrUpdateDomain = function(fCallback, - bCreate, sName, - sIncHost, iIncPort, sIncSecure, bIncShortLogin, - bUseSieve, sSieveAllowRaw, sSieveHost, iSievePort, sSieveSecure, - sOutHost, iOutPort, sOutSecure, bOutShortLogin, bOutAuth, bOutPhpMail, - sWhiteList) -{ - this.defaultRequest(fCallback, 'AdminDomainSave', { - 'Create': bCreate ? '1' : '0', - 'Name': sName, - - 'IncHost': sIncHost, - 'IncPort': iIncPort, - 'IncSecure': sIncSecure, - 'IncShortLogin': bIncShortLogin ? '1' : '0', - - 'UseSieve': bUseSieve ? '1' : '0', - 'SieveAllowRaw': sSieveAllowRaw ? '1' : '0', - 'SieveHost': sSieveHost, - 'SievePort': iSievePort, - 'SieveSecure': sSieveSecure, - - 'OutHost': sOutHost, - 'OutPort': iOutPort, - 'OutSecure': sOutSecure, - 'OutShortLogin': bOutShortLogin ? '1' : '0', - 'OutAuth': bOutAuth ? '1' : '0', - 'OutUsePhpMail': bOutPhpMail ? '1' : '0', - - 'WhiteList': sWhiteList - }); -}; - -RemoteAdminAjax.prototype.testConnectionForDomain = function(fCallback, sName, - sIncHost, iIncPort, sIncSecure, - bUseSieve, sSieveHost, iSievePort, sSieveSecure, - sOutHost, iOutPort, sOutSecure, bOutAuth, bOutPhpMail) -{ - this.defaultRequest(fCallback, 'AdminDomainTest', { - 'Name': sName, - 'IncHost': sIncHost, - 'IncPort': iIncPort, - 'IncSecure': sIncSecure, - 'UseSieve': bUseSieve ? '1' : '0', - 'SieveHost': sSieveHost, - 'SievePort': iSievePort, - 'SieveSecure': sSieveSecure, - 'OutHost': sOutHost, - 'OutPort': iOutPort, - 'OutSecure': sOutSecure, - 'OutAuth': bOutAuth ? '1' : '0', - 'OutUsePhpMail': bOutPhpMail ? '1' : '0' - }); -}; - -/** - * @param {?Function} fCallback - * @param {?} oData - */ -RemoteAdminAjax.prototype.testContacts = function(fCallback, oData) -{ - this.defaultRequest(fCallback, 'AdminContactsTest', oData); -}; - -/** - * @param {?Function} fCallback - * @param {?} oData - */ -RemoteAdminAjax.prototype.saveNewAdminPassword = function(fCallback, oData) -{ - this.defaultRequest(fCallback, 'AdminPasswordUpdate', oData); -}; - -/** - * @param {?Function} fCallback - */ -RemoteAdminAjax.prototype.adminPing = function(fCallback) -{ - this.defaultRequest(fCallback, 'AdminPing'); -}; - module.exports = new RemoteAdminAjax(); diff --git a/dev/Remote/User/Ajax.js b/dev/Remote/User/Ajax.js index e84381041..3d37cc8ba 100644 --- a/dev/Remote/User/Ajax.js +++ b/dev/Remote/User/Ajax.js @@ -1,918 +1,857 @@ -var - _ = require('_'), +import _ from '_'; - Utils = require('Common/Utils'), - Consts = require('Common/Consts'), - Base64 = require('Common/Base64'), +import {pString, pInt, isArray, trim, boolToAjax} from 'Common/Utils'; - Cache = require('Common/Cache'), - Links = require('Common/Links'), +import { + CONTACTS_SYNC_AJAX_TIMEOUT, + DEFAULT_AJAX_TIMEOUT, + SEARCH_AJAX_TIMEOUT, + SAVE_MESSAGE_AJAX_TIMEOUT, + SEND_MESSAGE_AJAX_TIMEOUT +} from 'Common/Consts'; - Settings = require('Storage/Settings'), +import { + getFolderHash, + getFolderInboxName, + getFolderUidNext, + getFolderFromCacheList, + getMessageFlagsFromCache +} from 'Common/Cache'; - AppStore = require('Stores/User/App'), - SettingsStore = require('Stores/User/Settings'), +import {subQueryPrefix} from 'Common/Links'; +import * as Base64 from 'Common/Base64'; +import * as Settings from 'Storage/Settings'; - AbstractAjaxRemote = require('Remote/AbstractAjax'); +import AppStore from 'Stores/User/App'; +import SettingsStore from 'Stores/User/Settings'; -/** - * @constructor - * @extends AbstractRemoteStorage - */ -function RemoteUserAjax() +import {getApp} from 'Helper/Apps/User'; + +import {AbstractAjaxRemote} from 'Remote/AbstractAjax'; + +class RemoteUserAjax extends AbstractAjaxRemote { - AbstractAjaxRemote.call(this); - - this.oRequests = {}; -} - -_.extend(RemoteUserAjax.prototype, AbstractAjaxRemote.prototype); - -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.folders = function(fCallback) -{ - this.defaultRequest(fCallback, 'Folders', { - 'SentFolder': Settings.settingsGet('SentFolder'), - 'DraftFolder': Settings.settingsGet('DraftFolder'), - 'SpamFolder': Settings.settingsGet('SpamFolder'), - 'TrashFolder': Settings.settingsGet('TrashFolder'), - 'ArchiveFolder': Settings.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 - */ -RemoteUserAjax.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 - */ -RemoteUserAjax.prototype.getTwoFactor = function(fCallback) -{ - this.defaultRequest(fCallback, 'GetTwoFactorInfo'); -}; - -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.createTwoFactor = function(fCallback) -{ - this.defaultRequest(fCallback, 'CreateTwoFactorSecret'); -}; - -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.clearTwoFactor = function(fCallback) -{ - this.defaultRequest(fCallback, 'ClearTwoFactorInfo'); -}; - -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.showTwoFactorSecret = function(fCallback) -{ - this.defaultRequest(fCallback, 'ShowTwoFactorSecret'); -}; - -/** - * @param {?Function} fCallback - * @param {string} sCode - */ -RemoteUserAjax.prototype.testTwoFactor = function(fCallback, sCode) -{ - this.defaultRequest(fCallback, 'TestTwoFactorInfo', { - 'Code': sCode - }); -}; - -/** - * @param {?Function} fCallback - * @param {boolean} bEnable - */ -RemoteUserAjax.prototype.enableTwoFactor = function(fCallback, bEnable) -{ - this.defaultRequest(fCallback, 'EnableTwoFactor', { - 'Enable': bEnable ? '1' : '0' - }); -}; - -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.clearTwoFactorInfo = function(fCallback) -{ - this.defaultRequest(fCallback, 'ClearTwoFactorInfo'); -}; - -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.contactsSync = function(fCallback) -{ - this.defaultRequest(fCallback, 'ContactsSync', null, Consts.CONTACTS_SYNC_AJAX_TIMEOUT); -}; - -/** - * @param {?Function} fCallback - * @param {boolean} bEnable - * @param {string} sUrl - * @param {string} sUser - * @param {string} sPassword - */ -RemoteUserAjax.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} sPassword - * @param {boolean=} bNew - */ -RemoteUserAjax.prototype.accountSetup = function(fCallback, sEmail, sPassword, bNew) -{ - bNew = Utils.isUnd(bNew) ? true : !!bNew; - - this.defaultRequest(fCallback, 'AccountSetup', { - 'Email': sEmail, - 'Password': sPassword, - 'New': bNew ? '1' : '0' - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sEmailToDelete - */ -RemoteUserAjax.prototype.accountDelete = function(fCallback, sEmailToDelete) -{ - this.defaultRequest(fCallback, 'AccountDelete', { - 'EmailToDelete': sEmailToDelete - }); -}; - -/** - * @param {?Function} fCallback - * @param {Array} aAccounts - * @param {Array} aIdentities - */ -RemoteUserAjax.prototype.accountsAndIdentitiesSortOrder = function(fCallback, aAccounts, aIdentities) -{ - this.defaultRequest(fCallback, 'AccountsAndIdentitiesSortOrder', { - 'Accounts': aAccounts, - 'Identities': aIdentities - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sId - * @param {string} sEmail - * @param {string} sName - * @param {string} sReplyTo - * @param {string} sBcc - * @param {string} sSignature - * @param {boolean} bSignatureInsertBefore - */ -RemoteUserAjax.prototype.identityUpdate = function(fCallback, sId, sEmail, sName, sReplyTo, sBcc, - sSignature, bSignatureInsertBefore) -{ - this.defaultRequest(fCallback, 'IdentityUpdate', { - 'Id': sId, - 'Email': sEmail, - 'Name': sName, - 'ReplyTo': sReplyTo, - 'Bcc': sBcc, - 'Signature': sSignature, - 'SignatureInsertBefore': bSignatureInsertBefore ? '1' : '0' - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sIdToDelete - */ -RemoteUserAjax.prototype.identityDelete = function(fCallback, sIdToDelete) -{ - this.defaultRequest(fCallback, 'IdentityDelete', { - 'IdToDelete': sIdToDelete - }); -}; - -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.accountsAndIdentities = function(fCallback) -{ - this.defaultRequest(fCallback, 'AccountsAndIdentities'); -}; - -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.accountsCounts = function(fCallback) -{ - this.defaultRequest(fCallback, 'AccountsCounts'); -}; - -/** - * @param {?Function} fCallback - * @param {Array} aFilters - * @param {string} sRaw - * @param {boolean} bRawIsActive - */ -RemoteUserAjax.prototype.filtersSave = function(fCallback, aFilters, sRaw, bRawIsActive) -{ - this.defaultRequest(fCallback, 'FiltersSave', { - 'Raw': sRaw, - 'RawIsActive': bRawIsActive ? '1' : '0', - 'Filters': _.map(aFilters, function(oItem) { - return oItem.toJson(); - }) - }); -}; - -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.filtersGet = function(fCallback) -{ - this.defaultRequest(fCallback, 'Filters', {}); -}; - -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.templates = function(fCallback) -{ - this.defaultRequest(fCallback, 'Templates', {}); -}; - -/** - * @param {Function} fCallback - * @param {string} sID - */ -RemoteUserAjax.prototype.templateGetById = function(fCallback, sID) -{ - this.defaultRequest(fCallback, 'TemplateGetByID', { - 'ID': sID - }); -}; - -/** - * @param {Function} fCallback - * @param {string} sID - */ -RemoteUserAjax.prototype.templateDelete = function(fCallback, sID) -{ - this.defaultRequest(fCallback, 'TemplateDelete', { - 'IdToDelete': sID - }); -}; - -/** - * @param {Function} fCallback - * @param {string} sID - * @param {string} sName - * @param {string} sBody - */ -RemoteUserAjax.prototype.templateSetup = function(fCallback, sID, sName, sBody) -{ - this.defaultRequest(fCallback, 'TemplateSetup', { - 'ID': sID, - 'Name': sName, - 'Body': sBody - }); -}; - -/** - * @param {Function} fCallback - * @param {string} sFolderFullNameRaw - * @param {number=} iOffset = 0 - * @param {number=} iLimit = 20 - * @param {string=} sSearch = '' - * @param {string=} sThreadUid = '' - * @param {boolean=} bSilent = false - */ -RemoteUserAjax.prototype.messageList = function(fCallback, sFolderFullNameRaw, iOffset, iLimit, sSearch, sThreadUid, bSilent) -{ - sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw); - - var - sFolderHash = Cache.getFolderHash(sFolderFullNameRaw), - bUseThreads = AppStore.threadsAllowed() && SettingsStore.useThreads(), - sInboxUidNext = Cache.getFolderInboxName() === sFolderFullNameRaw ? Cache.getFolderUidNext(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); - sThreadUid = Utils.pString(sThreadUid); - - if ('' !== sFolderHash && ('' === sSearch || -1 === sSearch.indexOf('is:'))) - { - return this.defaultRequest(fCallback, 'MessageList', {}, - '' === sSearch ? Consts.DEFAULT_AJAX_TIMEOUT : Consts.SEARCH_AJAX_TIMEOUT, - 'MessageList/' + Links.subQueryPrefix() + '/' + Base64.urlsafe_encode([ - sFolderFullNameRaw, - iOffset, - iLimit, - sSearch, - AppStore.projectHash(), - sFolderHash, - sInboxUidNext, - bUseThreads ? '1' : '0', - bUseThreads ? sThreadUid : '' - ].join(String.fromCharCode(0))), bSilent ? [] : ['MessageList']); + constructor() { + super(); + this.oRequests = {}; } - return this.defaultRequest(fCallback, 'MessageList', { - Folder: sFolderFullNameRaw, - Offset: iOffset, - Limit: iLimit, - Search: sSearch, - UidNext: sInboxUidNext, - UseThreads: bUseThreads ? '1' : '0', - ThreadUid: bUseThreads ? sThreadUid : '' - }, '' === sSearch ? Consts.DEFAULT_AJAX_TIMEOUT : Consts.SEARCH_AJAX_TIMEOUT, - '', bSilent ? [] : ['MessageList']); -}; - -/** - * @param {?Function} fCallback - * @param {Array} aDownloads - */ -RemoteUserAjax.prototype.messageUploadAttachments = function(fCallback, aDownloads) -{ - this.defaultRequest(fCallback, 'MessageUploadAttachments', { - 'Attachments': aDownloads - }, 999000); -}; - -/** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - * @param {number} iUid - * @returns {boolean} - */ -RemoteUserAjax.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/' + Links.subQueryPrefix() + '/' + Base64.urlsafe_encode([ - sFolderFullNameRaw, - iUid, - AppStore.projectHash(), - AppStore.threadsAllowed() && SettingsStore.useThreads() ? '1' : '0' - ].join(String.fromCharCode(0))), ['Message']); - - return true; + /** + * @param {?Function} fCallback + */ + folders(fCallback) { + this.defaultRequest(fCallback, 'Folders', { + 'SentFolder': Settings.settingsGet('SentFolder'), + 'DraftFolder': Settings.settingsGet('DraftFolder'), + 'SpamFolder': Settings.settingsGet('SpamFolder'), + 'TrashFolder': Settings.settingsGet('TrashFolder'), + 'ArchiveFolder': Settings.settingsGet('ArchiveFolder') + }, null, '', ['Folders']); } - return false; -}; - -/** - * @param {?Function} fCallback - * @param {Array} aExternals - */ -RemoteUserAjax.prototype.composeUploadExternals = function(fCallback, aExternals) -{ - this.defaultRequest(fCallback, 'ComposeUploadExternals', { - 'Externals': aExternals - }, 999000); -}; - -/** - * @param {?Function} fCallback - * @param {string} sUrl - * @param {string} sAccessToken - */ -RemoteUserAjax.prototype.composeUploadDrive = function(fCallback, sUrl, sAccessToken) -{ - this.defaultRequest(fCallback, 'ComposeUploadDrive', { - 'AccessToken': sAccessToken, - 'Url': sUrl - }, 999000); -}; - -/** - * @param {?Function} fCallback - * @param {string} sFolder - * @param {Array=} aList = [] - */ -RemoteUserAjax.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); - } - }); - } + /** + * @param {?Function} fCallback + * @param {string} sEmail + * @param {string} sLogin + * @param {string} sPassword + * @param {boolean} bSignMe + * @param {string=} sLanguage + * @param {string=} sAdditionalCode + * @param {boolean=} bAdditionalCodeSignMe + */ + login(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' }); + } - if (0 < aUids.length) + /** + * @param {?Function} fCallback + */ + getTwoFactor(fCallback) { + this.defaultRequest(fCallback, 'GetTwoFactorInfo'); + } + + /** + * @param {?Function} fCallback + */ + createTwoFactor(fCallback) { + this.defaultRequest(fCallback, 'CreateTwoFactorSecret'); + } + + /** + * @param {?Function} fCallback + */ + clearTwoFactor(fCallback) { + this.defaultRequest(fCallback, 'ClearTwoFactorInfo'); + } + + /** + * @param {?Function} fCallback + */ + showTwoFactorSecret(fCallback) { + this.defaultRequest(fCallback, 'ShowTwoFactorSecret'); + } + + /** + * @param {?Function} fCallback + * @param {string} sCode + */ + testTwoFactor(fCallback, sCode) { + this.defaultRequest(fCallback, 'TestTwoFactorInfo', { + 'Code': sCode + }); + } + + /** + * @param {?Function} fCallback + * @param {boolean} bEnable + */ + enableTwoFactor(fCallback, bEnable) { + this.defaultRequest(fCallback, 'EnableTwoFactor', { + 'Enable': bEnable ? '1' : '0' + }); + } + + /** + * @param {?Function} fCallback + */ + clearTwoFactorInfo(fCallback) { + this.defaultRequest(fCallback, 'ClearTwoFactorInfo'); + } + + /** + * @param {?Function} fCallback + */ + contactsSync(fCallback) { + this.defaultRequest(fCallback, 'ContactsSync', null, CONTACTS_SYNC_AJAX_TIMEOUT); + } + + /** + * @param {?Function} fCallback + * @param {boolean} bEnable + * @param {string} sUrl + * @param {string} sUser + * @param {string} sPassword + */ + saveContactsSyncData(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} sPassword + * @param {boolean=} bNew + */ + accountSetup(fCallback, sEmail, sPassword, bNew = true) { + this.defaultRequest(fCallback, 'AccountSetup', { + 'Email': sEmail, + 'Password': sPassword, + 'New': bNew ? '1' : '0' + }); + } + + /** + * @param {?Function} fCallback + * @param {string} sEmailToDelete + */ + accountDelete(fCallback, sEmailToDelete) { + this.defaultRequest(fCallback, 'AccountDelete', { + 'EmailToDelete': sEmailToDelete + }); + } + + /** + * @param {?Function} fCallback + * @param {Array} aAccounts + * @param {Array} aIdentities + */ + accountsAndIdentitiesSortOrder(fCallback, aAccounts, aIdentities) { + this.defaultRequest(fCallback, 'AccountsAndIdentitiesSortOrder', { + 'Accounts': aAccounts, + 'Identities': aIdentities + }); + } + + /** + * @param {?Function} fCallback + * @param {string} sId + * @param {string} sEmail + * @param {string} sName + * @param {string} sReplyTo + * @param {string} sBcc + * @param {string} sSignature + * @param {boolean} bSignatureInsertBefore + */ + identityUpdate(fCallback, sId, sEmail, sName, sReplyTo, sBcc, sSignature, bSignatureInsertBefore) { + this.defaultRequest(fCallback, 'IdentityUpdate', { + 'Id': sId, + 'Email': sEmail, + 'Name': sName, + 'ReplyTo': sReplyTo, + 'Bcc': sBcc, + 'Signature': sSignature, + 'SignatureInsertBefore': bSignatureInsertBefore ? '1' : '0' + }); + } + + /** + * @param {?Function} fCallback + * @param {string} sIdToDelete + */ + identityDelete(fCallback, sIdToDelete) { + this.defaultRequest(fCallback, 'IdentityDelete', { + 'IdToDelete': sIdToDelete + }); + } + + /** + * @param {?Function} fCallback + */ + accountsAndIdentities(fCallback) { + this.defaultRequest(fCallback, 'AccountsAndIdentities'); + } + + /** + * @param {?Function} fCallback + */ + accountsCounts(fCallback) { + this.defaultRequest(fCallback, 'AccountsCounts'); + } + + /** + * @param {?Function} fCallback + * @param {Array} filters + * @param {string} raw + * @param {boolean} isRawIsActive + */ + filtersSave(fCallback, filters, raw, isRawIsActive) { + this.defaultRequest(fCallback, 'FiltersSave', { + 'Raw': raw, + 'RawIsActive': boolToAjax(isRawIsActive), + 'Filters': _.map(filters, (item) => item.toJson()) + }); + } + + /** + * @param {?Function} fCallback + */ + filtersGet(fCallback) { + this.defaultRequest(fCallback, 'Filters', {}); + } + + /** + * @param {?Function} fCallback + */ + templates(fCallback) { + this.defaultRequest(fCallback, 'Templates', {}); + } + + /** + * @param {Function} fCallback + * @param {string} sID + */ + templateGetById(fCallback, sID) { + this.defaultRequest(fCallback, 'TemplateGetByID', { + 'ID': sID + }); + } + + /** + * @param {Function} fCallback + * @param {string} sID + */ + templateDelete(fCallback, sID) { + this.defaultRequest(fCallback, 'TemplateDelete', { + 'IdToDelete': sID + }); + } + + /** + * @param {Function} fCallback + * @param {string} sID + * @param {string} sName + * @param {string} sBody + */ + templateSetup(fCallback, sID, sName, sBody) { + this.defaultRequest(fCallback, 'TemplateSetup', { + 'ID': sID, + 'Name': sName, + 'Body': sBody + }); + } + + /** + * @param {Function} fCallback + * @param {string} sFolderFullNameRaw + * @param {number=} iOffset = 0 + * @param {number=} iLimit = 20 + * @param {string=} sSearch = '' + * @param {string=} sThreadUid = '' + * @param {boolean=} bSilent = false + */ + messageList(fCallback, sFolderFullNameRaw, iOffset = 0, iLimit = 20, sSearch = '', sThreadUid = '', bSilent = false) { + + sFolderFullNameRaw = pString(sFolderFullNameRaw); + + const + folderHash = getFolderHash(sFolderFullNameRaw), + useThreads = AppStore.threadsAllowed() && SettingsStore.useThreads(), + inboxUidNext = getFolderInboxName() === sFolderFullNameRaw ? getFolderUidNext(sFolderFullNameRaw) : ''; + + if ('' !== folderHash && ('' === sSearch || -1 === sSearch.indexOf('is:'))) { - bRequest = true; + return this.defaultRequest(fCallback, 'MessageList', {}, + '' === sSearch ? DEFAULT_AJAX_TIMEOUT : SEARCH_AJAX_TIMEOUT, + 'MessageList/' + subQueryPrefix() + '/' + Base64.urlsafe_encode([ + sFolderFullNameRaw, + iOffset, + iLimit, + sSearch, + AppStore.projectHash(), + folderHash, + inboxUidNext, + useThreads ? '1' : '0', + useThreads ? sThreadUid : '' + ].join(String.fromCharCode(0))), bSilent ? [] : ['MessageList']); + } + + return this.defaultRequest(fCallback, 'MessageList', { + Folder: sFolderFullNameRaw, + Offset: iOffset, + Limit: iLimit, + Search: sSearch, + UidNext: inboxUidNext, + UseThreads: useThreads ? '1' : '0', + ThreadUid: useThreads ? sThreadUid : '' + }, '' === sSearch ? DEFAULT_AJAX_TIMEOUT : SEARCH_AJAX_TIMEOUT, + '', bSilent ? [] : ['MessageList']); + } + + /** + * @param {?Function} fCallback + * @param {Array} aDownloads + */ + messageUploadAttachments(fCallback, aDownloads) { + this.defaultRequest(fCallback, 'MessageUploadAttachments', { + 'Attachments': aDownloads + }, 999000); + } + + /** + * @param {?Function} fCallback + * @param {string} sFolderFullNameRaw + * @param {number} iUid + * @returns {boolean} + */ + message(fCallback, sFolderFullNameRaw, iUid) { + + sFolderFullNameRaw = pString(sFolderFullNameRaw); + iUid = pInt(iUid); + + if (getFolderFromCacheList(sFolderFullNameRaw) && 0 < iUid) + { + this.defaultRequest(fCallback, 'Message', {}, null, + 'Message/' + subQueryPrefix() + '/' + Base64.urlsafe_encode([ + sFolderFullNameRaw, + iUid, + AppStore.projectHash(), + AppStore.threadsAllowed() && SettingsStore.useThreads() ? '1' : '0' + ].join(String.fromCharCode(0))), ['Message']); + + return true; + } + + return false; + } + + /** + * @param {?Function} fCallback + * @param {Array} aExternals + */ + composeUploadExternals(fCallback, aExternals) { + this.defaultRequest(fCallback, 'ComposeUploadExternals', { + 'Externals': aExternals + }, 999000); + } + + /** + * @param {?Function} fCallback + * @param {string} sUrl + * @param {string} sAccessToken + */ + composeUploadDrive(fCallback, sUrl, sAccessToken) { + this.defaultRequest(fCallback, 'ComposeUploadDrive', { + 'AccessToken': sAccessToken, + 'Url': sUrl + }, 999000); + } + + /** + * @param {?Function} fCallback + * @param {string} folder + * @param {Array=} list = [] + */ + folderInformation(fCallback, folder, list = []) { + + let request = true; + const uids = []; + + if (isArray(list) && 0 < list.length) + { + request = false; + _.each(list, (messageListItem) => { + if (!getMessageFlagsFromCache(messageListItem.folderFullNameRaw, messageListItem.uid)) + { + uids.push(messageListItem.uid); + } + + if (0 < messageListItem.threads().length) + { + _.each(messageListItem.threads(), (uid) => { + if (!getMessageFlagsFromCache(messageListItem.folderFullNameRaw, uid)) + { + uids.push(uid); + } + }); + } + }); + + if (0 < uids.length) + { + request = true; + } + } + + if (request) + { + this.defaultRequest(fCallback, 'FolderInformation', { + 'Folder': folder, + 'FlagsUids': isArray(uids) ? uids.join(',') : '', + 'UidNext': getFolderInboxName() === folder ? getFolderUidNext(folder) : '' + }); + } + else if (SettingsStore.useThreads()) + { + getApp().reloadFlagsCurrentMessageListAndMessageFromCache(); } } - if (bRequest) - { - this.defaultRequest(fCallback, 'FolderInformation', { - 'Folder': sFolder, - 'FlagsUids': Utils.isArray(aUids) ? aUids.join(',') : '', - 'UidNext': Cache.getFolderInboxName() === sFolder ? Cache.getFolderUidNext(sFolder) : '' + /** + * @param {?Function} fCallback + * @param {Array} aFolders + */ + folderInformationMultiply(fCallback, aFolders) { + this.defaultRequest(fCallback, 'FolderInformationMultiply', { + 'Folders': aFolders }); } - else if (SettingsStore.useThreads()) - { - require('App/User').default.reloadFlagsCurrentMessageListAndMessageFromCache(); + + /** + * @param {?Function} fCallback + */ + logout(fCallback) { + this.defaultRequest(fCallback, 'Logout'); } -}; -/** - * @param {?Function} fCallback - * @param {Array} aFolders - */ -RemoteUserAjax.prototype.folderInformationMultiply = function(fCallback, aFolders) -{ - this.defaultRequest(fCallback, 'FolderInformationMultiply', { - 'Folders': aFolders - }); -}; + /** + * @param {?Function} fCallback + * @param {string} sFolderFullNameRaw + * @param {Array} aUids + * @param {boolean} bSetFlagged + */ + messageSetFlagged(fCallback, sFolderFullNameRaw, aUids, bSetFlagged) { + this.defaultRequest(fCallback, 'MessageSetFlagged', { + 'Folder': sFolderFullNameRaw, + 'Uids': aUids.join(','), + 'SetAction': bSetFlagged ? '1' : '0' + }); + } -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.logout = function(fCallback) -{ - this.defaultRequest(fCallback, 'Logout'); -}; + /** + * @param {?Function} fCallback + * @param {string} sFolderFullNameRaw + * @param {Array} aUids + * @param {boolean} bSetSeen + */ + messageSetSeen(fCallback, sFolderFullNameRaw, aUids, bSetSeen) { + this.defaultRequest(fCallback, 'MessageSetSeen', { + 'Folder': sFolderFullNameRaw, + 'Uids': aUids.join(','), + 'SetAction': bSetSeen ? '1' : '0' + }); + } -/** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - * @param {Array} aUids - * @param {boolean} bSetFlagged - */ -RemoteUserAjax.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 {boolean} bSetSeen + */ + messageSetSeenToAll(fCallback, sFolderFullNameRaw, bSetSeen) { + this.defaultRequest(fCallback, 'MessageSetSeenToAll', { + 'Folder': sFolderFullNameRaw, + 'SetAction': bSetSeen ? '1' : '0' + }); + } -/** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - * @param {Array} aUids - * @param {boolean} bSetSeen - */ -RemoteUserAjax.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} sIdentityID + * @param {string} sMessageFolder + * @param {string} sMessageUid + * @param {string} sDraftFolder + * @param {string} sTo + * @param {string} sCc + * @param {string} sBcc + * @param {string} sReplyTo + * @param {string} sSubject + * @param {boolean} bTextIsHtml + * @param {string} sText + * @param {Array} aAttachments + * @param {(Array|null)} aDraftInfo + * @param {string} sInReplyTo + * @param {string} sReferences + * @param {boolean} bMarkAsImportant + */ + saveMessage(fCallback, sIdentityID, sMessageFolder, sMessageUid, sDraftFolder, + sTo, sCc, sBcc, sReplyTo, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences, bMarkAsImportant) { -/** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - * @param {boolean} bSetSeen - */ -RemoteUserAjax.prototype.messageSetSeenToAll = function(fCallback, sFolderFullNameRaw, bSetSeen) -{ - this.defaultRequest(fCallback, 'MessageSetSeenToAll', { - 'Folder': sFolderFullNameRaw, - 'SetAction': bSetSeen ? '1' : '0' - }); -}; + this.defaultRequest(fCallback, 'SaveMessage', { + 'IdentityID': sIdentityID, + 'MessageFolder': sMessageFolder, + 'MessageUid': sMessageUid, + 'DraftFolder': sDraftFolder, + 'To': sTo, + 'Cc': sCc, + 'Bcc': sBcc, + 'ReplyTo': sReplyTo, + 'Subject': sSubject, + 'TextIsHtml': bTextIsHtml ? '1' : '0', + 'Text': sText, + 'DraftInfo': aDraftInfo, + 'InReplyTo': sInReplyTo, + 'References': sReferences, + 'MarkAsImportant': bMarkAsImportant ? '1' : '0', + 'Attachments': aAttachments + }, SAVE_MESSAGE_AJAX_TIMEOUT); + } -/** - * @param {?Function} fCallback - * @param {string} sIdentityID - * @param {string} sMessageFolder - * @param {string} sMessageUid - * @param {string} sDraftFolder - * @param {string} sTo - * @param {string} sCc - * @param {string} sBcc - * @param {string} sReplyTo - * @param {string} sSubject - * @param {boolean} bTextIsHtml - * @param {string} sText - * @param {Array} aAttachments - * @param {(Array|null)} aDraftInfo - * @param {string} sInReplyTo - * @param {string} sReferences - * @param {boolean} bMarkAsImportant - */ -RemoteUserAjax.prototype.saveMessage = function(fCallback, sIdentityID, sMessageFolder, sMessageUid, sDraftFolder, - sTo, sCc, sBcc, sReplyTo, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences, bMarkAsImportant) -{ - this.defaultRequest(fCallback, 'SaveMessage', { - 'IdentityID': sIdentityID, - 'MessageFolder': sMessageFolder, - 'MessageUid': sMessageUid, - 'DraftFolder': sDraftFolder, - 'To': sTo, - 'Cc': sCc, - 'Bcc': sBcc, - 'ReplyTo': sReplyTo, - 'Subject': sSubject, - 'TextIsHtml': bTextIsHtml ? '1' : '0', - 'Text': sText, - 'DraftInfo': aDraftInfo, - 'InReplyTo': sInReplyTo, - 'References': sReferences, - 'MarkAsImportant': bMarkAsImportant ? '1' : '0', - 'Attachments': aAttachments - }, Consts.SAVE_MESSAGE_AJAX_TIMEOUT); -}; + /** + * @param {?Function} fCallback + * @param {string} sMessageFolder + * @param {string} sMessageUid + * @param {string} sReadReceipt + * @param {string} sSubject + * @param {string} sText + */ + sendReadReceiptMessage(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} sReadReceipt - * @param {string} sSubject - * @param {string} sText - */ -RemoteUserAjax.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} sIdentityID + * @param {string} sMessageFolder + * @param {string} sMessageUid + * @param {string} sSentFolder + * @param {string} sTo + * @param {string} sCc + * @param {string} sBcc + * @param {string} sReplyTo + * @param {string} sSubject + * @param {boolean} bTextIsHtml + * @param {string} sText + * @param {Array} aAttachments + * @param {(Array|null)} aDraftInfo + * @param {string} sInReplyTo + * @param {string} sReferences + * @param {boolean} bRequestDsn + * @param {boolean} bRequestReadReceipt + * @param {boolean} bMarkAsImportant + */ + sendMessage(fCallback, sIdentityID, sMessageFolder, sMessageUid, sSentFolder, + sTo, sCc, sBcc, sReplyTo, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences, + bRequestDsn, bRequestReadReceipt, bMarkAsImportant) { -/** - * @param {?Function} fCallback - * @param {string} sIdentityID - * @param {string} sMessageFolder - * @param {string} sMessageUid - * @param {string} sSentFolder - * @param {string} sTo - * @param {string} sCc - * @param {string} sBcc - * @param {string} sReplyTo - * @param {string} sSubject - * @param {boolean} bTextIsHtml - * @param {string} sText - * @param {Array} aAttachments - * @param {(Array|null)} aDraftInfo - * @param {string} sInReplyTo - * @param {string} sReferences - * @param {boolean} bRequestDsn - * @param {boolean} bRequestReadReceipt - * @param {boolean} bMarkAsImportant - */ -RemoteUserAjax.prototype.sendMessage = function(fCallback, sIdentityID, sMessageFolder, sMessageUid, sSentFolder, - sTo, sCc, sBcc, sReplyTo, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences, - bRequestDsn, bRequestReadReceipt, bMarkAsImportant) -{ - this.defaultRequest(fCallback, 'SendMessage', { - 'IdentityID': sIdentityID, - 'MessageFolder': sMessageFolder, - 'MessageUid': sMessageUid, - 'SentFolder': sSentFolder, - 'To': sTo, - 'Cc': sCc, - 'Bcc': sBcc, - 'ReplyTo': sReplyTo, - 'Subject': sSubject, - 'TextIsHtml': bTextIsHtml ? '1' : '0', - 'Text': sText, - 'DraftInfo': aDraftInfo, - 'InReplyTo': sInReplyTo, - 'References': sReferences, - 'Dsn': bRequestDsn ? '1' : '0', - 'ReadReceiptRequest': bRequestReadReceipt ? '1' : '0', - 'MarkAsImportant': bMarkAsImportant ? '1' : '0', - 'Attachments': aAttachments - }, Consts.SEND_MESSAGE_AJAX_TIMEOUT); -}; + this.defaultRequest(fCallback, 'SendMessage', { + 'IdentityID': sIdentityID, + 'MessageFolder': sMessageFolder, + 'MessageUid': sMessageUid, + 'SentFolder': sSentFolder, + 'To': sTo, + 'Cc': sCc, + 'Bcc': sBcc, + 'ReplyTo': sReplyTo, + 'Subject': sSubject, + 'TextIsHtml': bTextIsHtml ? '1' : '0', + 'Text': sText, + 'DraftInfo': aDraftInfo, + 'InReplyTo': sInReplyTo, + 'References': sReferences, + 'Dsn': bRequestDsn ? '1' : '0', + 'ReadReceiptRequest': bRequestReadReceipt ? '1' : '0', + 'MarkAsImportant': bMarkAsImportant ? '1' : '0', + 'Attachments': aAttachments + }, SEND_MESSAGE_AJAX_TIMEOUT); + } -/** - * @param {?Function} fCallback - * @param {Object} oData - */ -RemoteUserAjax.prototype.saveSystemFolders = function(fCallback, oData) -{ - this.defaultRequest(fCallback, 'SystemFoldersUpdate', oData); -}; + /** + * @param {?Function} fCallback + * @param {Object} oData + */ + saveSystemFolders(fCallback, oData) { + this.defaultRequest(fCallback, 'SystemFoldersUpdate', oData); + } -/** - * @param {?Function} fCallback - * @param {Object} oData - */ -RemoteUserAjax.prototype.saveSettings = function(fCallback, oData) -{ - this.defaultRequest(fCallback, 'SettingsUpdate', oData); -}; + /** + * @param {?Function} fCallback + * @param {Object} oData + */ + saveSettings(fCallback, oData) { + this.defaultRequest(fCallback, 'SettingsUpdate', oData); + } -/** - * @param {string} key - * @param {?Function} valueFn - * @param {?Function} fn - */ -RemoteUserAjax.prototype.saveSettingsHelper = function(key, valueFn, fn) -{ - var self = this; - return function(value) { - var data = {}; - data[key] = valueFn ? valueFn(value) : value; - self.saveSettings(fn || null, data); - }; -}; + /** + * @param {string} key + * @param {?Function} valueFn + * @param {?Function} fn + */ + saveSettingsHelper(key, valueFn, fn) { + return (value) => { + this.saveSettings(fn || null, { + [key]: valueFn ? valueFn(value) : value + }); + }; + } -/** - * @param {?Function} fCallback - * @param {string} sPrevPassword - * @param {string} sNewPassword - */ -RemoteUserAjax.prototype.changePassword = function(fCallback, sPrevPassword, sNewPassword) -{ - this.defaultRequest(fCallback, 'ChangePassword', { - 'PrevPassword': sPrevPassword, - 'NewPassword': sNewPassword - }); -}; + /** + * @param {?Function} fCallback + * @param {string} prevPassword + * @param {string} newPassword + */ + changePassword(fCallback, prevPassword, newPassword) { + this.defaultRequest(fCallback, 'ChangePassword', { + 'PrevPassword': prevPassword, + 'NewPassword': newPassword + }); + } -/** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - */ -RemoteUserAjax.prototype.folderClear = function(fCallback, sFolderFullNameRaw) -{ - this.defaultRequest(fCallback, 'FolderClear', { - 'Folder': sFolderFullNameRaw - }); -}; + /** + * @param {?Function} fCallback + * @param {string} sFolderFullNameRaw + */ + folderClear(fCallback, sFolderFullNameRaw) { + this.defaultRequest(fCallback, 'FolderClear', { + 'Folder': sFolderFullNameRaw + }); + } -/** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - * @param {boolean} bSubscribe - */ -RemoteUserAjax.prototype.folderSetSubscribe = function(fCallback, sFolderFullNameRaw, bSubscribe) -{ - this.defaultRequest(fCallback, 'FolderSubscribe', { - 'Folder': sFolderFullNameRaw, - 'Subscribe': bSubscribe ? '1' : '0' - }); -}; + /** + * @param {?Function} fCallback + * @param {string} sFolderFullNameRaw + * @param {boolean} bSubscribe + */ + folderSetSubscribe(fCallback, sFolderFullNameRaw, bSubscribe) { + this.defaultRequest(fCallback, 'FolderSubscribe', { + 'Folder': sFolderFullNameRaw, + 'Subscribe': bSubscribe ? '1' : '0' + }); + } -/** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - * @param {boolean} bCheckable - */ -RemoteUserAjax.prototype.folderSetCheckable = function(fCallback, sFolderFullNameRaw, bCheckable) -{ - this.defaultRequest(fCallback, 'FolderCheckable', { - 'Folder': sFolderFullNameRaw, - 'Checkable': bCheckable ? '1' : '0' - }); -}; + /** + * @param {?Function} fCallback + * @param {string} sFolderFullNameRaw + * @param {boolean} bCheckable + */ + folderSetCheckable(fCallback, sFolderFullNameRaw, bCheckable) { + this.defaultRequest(fCallback, 'FolderCheckable', { + 'Folder': sFolderFullNameRaw, + 'Checkable': bCheckable ? '1' : '0' + }); + } -/** - * @param {?Function} fCallback - * @param {string} sFolder - * @param {string} sToFolder - * @param {Array} aUids - * @param {string=} sLearning - * @param {boolean=} bMarkAsRead - */ -RemoteUserAjax.prototype.messagesMove = function(fCallback, sFolder, sToFolder, aUids, sLearning, bMarkAsRead) -{ - this.defaultRequest(fCallback, 'MessageMove', { - 'FromFolder': sFolder, - 'ToFolder': sToFolder, - 'Uids': aUids.join(','), - 'MarkAsRead': bMarkAsRead ? '1' : '0', - 'Learning': sLearning || '' - }, null, '', ['MessageList']); -}; + /** + * @param {?Function} fCallback + * @param {string} sFolder + * @param {string} sToFolder + * @param {Array} aUids + * @param {string=} sLearning + * @param {boolean=} bMarkAsRead + */ + messagesMove(fCallback, sFolder, sToFolder, aUids, sLearning, bMarkAsRead) { + this.defaultRequest(fCallback, 'MessageMove', { + 'FromFolder': sFolder, + 'ToFolder': sToFolder, + 'Uids': aUids.join(','), + 'MarkAsRead': bMarkAsRead ? '1' : '0', + 'Learning': sLearning || '' + }, null, '', ['MessageList']); + } -/** - * @param {?Function} fCallback - * @param {string} sFolder - * @param {string} sToFolder - * @param {Array} aUids - */ -RemoteUserAjax.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 {string} sToFolder + * @param {Array} aUids + */ + messagesCopy(fCallback, sFolder, sToFolder, aUids) { + this.defaultRequest(fCallback, 'MessageCopy', { + 'FromFolder': sFolder, + 'ToFolder': sToFolder, + 'Uids': aUids.join(',') + }); + } -/** - * @param {?Function} fCallback - * @param {string} sFolder - * @param {Array} aUids - */ -RemoteUserAjax.prototype.messagesDelete = function(fCallback, sFolder, aUids) -{ - this.defaultRequest(fCallback, 'MessageDelete', { - 'Folder': sFolder, - 'Uids': aUids.join(',') - }, null, '', ['MessageList']); -}; + /** + * @param {?Function} fCallback + * @param {string} sFolder + * @param {Array} aUids + */ + messagesDelete(fCallback, sFolder, aUids) { + this.defaultRequest(fCallback, 'MessageDelete', { + 'Folder': sFolder, + 'Uids': aUids.join(',') + }, null, '', ['MessageList']); + } -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.appDelayStart = function(fCallback) -{ - this.defaultRequest(fCallback, 'AppDelayStart'); -}; + /** + * @param {?Function} fCallback + */ + appDelayStart(fCallback) { + this.defaultRequest(fCallback, 'AppDelayStart'); + } -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.quota = function(fCallback) -{ - this.defaultRequest(fCallback, 'Quota'); -}; + /** + * @param {?Function} fCallback + */ + quota(fCallback) { + this.defaultRequest(fCallback, 'Quota'); + } -/** - * @param {?Function} fCallback - * @param {number} iOffset - * @param {number} iLimit - * @param {string} sSearch - */ -RemoteUserAjax.prototype.contacts = function(fCallback, iOffset, iLimit, sSearch) -{ - this.defaultRequest(fCallback, 'Contacts', { - 'Offset': iOffset, - 'Limit': iLimit, - 'Search': sSearch - }, null, '', ['Contacts']); -}; + /** + * @param {?Function} fCallback + * @param {number} iOffset + * @param {number} iLimit + * @param {string} sSearch + */ + contacts(fCallback, iOffset, iLimit, sSearch) { + this.defaultRequest(fCallback, 'Contacts', { + 'Offset': iOffset, + 'Limit': iLimit, + 'Search': sSearch + }, null, '', ['Contacts']); + } -/** - * @param {?Function} fCallback - * @param {string} sRequestUid - * @param {string} sUid - * @param {Array} aProperties - */ -RemoteUserAjax.prototype.contactSave = function(fCallback, sRequestUid, sUid, aProperties) -{ - this.defaultRequest(fCallback, 'ContactSave', { - 'RequestUid': sRequestUid, - 'Uid': Utils.trim(sUid), - 'Properties': aProperties - }); -}; + /** + * @param {?Function} fCallback + * @param {string} sRequestUid + * @param {string} sUid + * @param {Array} aProperties + */ + contactSave(fCallback, sRequestUid, sUid, aProperties) { + this.defaultRequest(fCallback, 'ContactSave', { + 'RequestUid': sRequestUid, + 'Uid': trim(sUid), + 'Properties': aProperties + }); + } -/** - * @param {?Function} fCallback - * @param {Array} aUids - */ -RemoteUserAjax.prototype.contactsDelete = function(fCallback, aUids) -{ - this.defaultRequest(fCallback, 'ContactsDelete', { - 'Uids': aUids.join(',') - }); -}; + /** + * @param {?Function} fCallback + * @param {Array} aUids + */ + contactsDelete(fCallback, aUids) { + this.defaultRequest(fCallback, 'ContactsDelete', { + 'Uids': aUids.join(',') + }); + } -/** - * @param {?Function} fCallback - * @param {string} sQuery - * @param {number} iPage - */ -RemoteUserAjax.prototype.suggestions = function(fCallback, sQuery, iPage) -{ - this.defaultRequest(fCallback, 'Suggestions', { - 'Query': sQuery, - 'Page': iPage - }, null, '', ['Suggestions']); -}; + /** + * @param {?Function} fCallback + * @param {string} sQuery + * @param {number} iPage + */ + suggestions(fCallback, sQuery, iPage) { + this.defaultRequest(fCallback, 'Suggestions', { + 'Query': sQuery, + 'Page': iPage + }, null, '', ['Suggestions']); + } -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.clearUserBackground = function(fCallback) -{ - this.defaultRequest(fCallback, 'ClearUserBackground'); -}; + /** + * @param {?Function} fCallback + */ + clearUserBackground(fCallback) { + this.defaultRequest(fCallback, 'ClearUserBackground'); + } -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.facebookUser = function(fCallback) -{ - this.defaultRequest(fCallback, 'SocialFacebookUserInformation'); -}; + /** + * @param {?Function} fCallback + */ + facebookUser(fCallback) { + this.defaultRequest(fCallback, 'SocialFacebookUserInformation'); + } -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.facebookDisconnect = function(fCallback) -{ - this.defaultRequest(fCallback, 'SocialFacebookDisconnect'); -}; + /** + * @param {?Function} fCallback + */ + facebookDisconnect(fCallback) { + this.defaultRequest(fCallback, 'SocialFacebookDisconnect'); + } -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.twitterUser = function(fCallback) -{ - this.defaultRequest(fCallback, 'SocialTwitterUserInformation'); -}; + /** + * @param {?Function} fCallback + */ + twitterUser(fCallback) { + this.defaultRequest(fCallback, 'SocialTwitterUserInformation'); + } -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.twitterDisconnect = function(fCallback) -{ - this.defaultRequest(fCallback, 'SocialTwitterDisconnect'); -}; + /** + * @param {?Function} fCallback + */ + twitterDisconnect(fCallback) { + this.defaultRequest(fCallback, 'SocialTwitterDisconnect'); + } -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.googleUser = function(fCallback) -{ - this.defaultRequest(fCallback, 'SocialGoogleUserInformation'); -}; + /** + * @param {?Function} fCallback + */ + googleUser(fCallback) { + this.defaultRequest(fCallback, 'SocialGoogleUserInformation'); + } -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.googleDisconnect = function(fCallback) -{ - this.defaultRequest(fCallback, 'SocialGoogleDisconnect'); -}; + /** + * @param {?Function} fCallback + */ + googleDisconnect(fCallback) { + this.defaultRequest(fCallback, 'SocialGoogleDisconnect'); + } -/** - * @param {?Function} fCallback - */ -RemoteUserAjax.prototype.socialUsers = function(fCallback) -{ - this.defaultRequest(fCallback, 'SocialUsers'); -}; + /** + * @param {?Function} fCallback + */ + socialUsers(fCallback) { + this.defaultRequest(fCallback, 'SocialUsers'); + } +} module.exports = new RemoteUserAjax(); diff --git a/dev/Screen/AbstractSettings.js b/dev/Screen/AbstractSettings.js index 83deca522..e875bcab5 100644 --- a/dev/Screen/AbstractSettings.js +++ b/dev/Screen/AbstractSettings.js @@ -37,16 +37,15 @@ class AbstractSettingsScreen extends AbstractScreen } } - onRoute(sSubName) { - var - self = this, - oSettingsScreen = null, + onRoute(subName) { + let + settingsScreen = null, RoutedSettingsViewModel = null, - oViewModelPlace = null, - oViewModelDom = null; + viewModelPlace = null, + viewModelDom = null; RoutedSettingsViewModel = _.find(VIEW_MODELS.settings, - (SettingsViewModel) => SettingsViewModel && SettingsViewModel.__rlSettingsData && sSubName === SettingsViewModel.__rlSettingsData.Route + (SettingsViewModel) => SettingsViewModel && SettingsViewModel.__rlSettingsData && subName === SettingsViewModel.__rlSettingsData.Route ); if (RoutedSettingsViewModel) @@ -67,32 +66,32 @@ class AbstractSettingsScreen extends AbstractScreen { if (RoutedSettingsViewModel.__builded && RoutedSettingsViewModel.__vm) { - oSettingsScreen = RoutedSettingsViewModel.__vm; + settingsScreen = RoutedSettingsViewModel.__vm; } else { - oViewModelPlace = this.oViewModelPlace; - if (oViewModelPlace && 1 === oViewModelPlace.length) + viewModelPlace = this.oViewModelPlace; + if (viewModelPlace && 1 === viewModelPlace.length) { - oSettingsScreen = new RoutedSettingsViewModel(); + settingsScreen = new RoutedSettingsViewModel(); - oViewModelDom = $('
').addClass('rl-settings-view-model').hide(); - oViewModelDom.appendTo(oViewModelPlace); + viewModelDom = $('
').addClass('rl-settings-view-model').hide(); + viewModelDom.appendTo(viewModelPlace); - oSettingsScreen.viewModelDom = oViewModelDom; + settingsScreen.viewModelDom = viewModelDom; - oSettingsScreen.__rlSettingsData = RoutedSettingsViewModel.__rlSettingsData; + settingsScreen.__rlSettingsData = RoutedSettingsViewModel.__rlSettingsData; - RoutedSettingsViewModel.__dom = oViewModelDom; + RoutedSettingsViewModel.__dom = viewModelDom; RoutedSettingsViewModel.__builded = true; - RoutedSettingsViewModel.__vm = oSettingsScreen; + RoutedSettingsViewModel.__vm = settingsScreen; - ko.applyBindingAccessorsToNode(oViewModelDom[0], { + ko.applyBindingAccessorsToNode(viewModelDom[0], { translatorInit: true, template: () => ({name: RoutedSettingsViewModel.__rlSettingsData.Template}) - }, oSettingsScreen); + }, settingsScreen); - delegateRun(oSettingsScreen, 'onBuild', [oViewModelDom]); + delegateRun(settingsScreen, 'onBuild', [viewModelDom]); } else { @@ -100,29 +99,29 @@ class AbstractSettingsScreen extends AbstractScreen } } - if (oSettingsScreen) + if (settingsScreen) { - _.defer(function() { + _.defer(() => { // hide - if (self.oCurrentSubScreen) + if (this.oCurrentSubScreen) { - delegateRun(self.oCurrentSubScreen, 'onHide'); - self.oCurrentSubScreen.viewModelDom.hide(); + delegateRun(this.oCurrentSubScreen, 'onHide'); + this.oCurrentSubScreen.viewModelDom.hide(); } // -- - self.oCurrentSubScreen = oSettingsScreen; + this.oCurrentSubScreen = settingsScreen; // show - if (self.oCurrentSubScreen) + if (this.oCurrentSubScreen) { - delegateRun(self.oCurrentSubScreen, 'onBeforeShow'); - self.oCurrentSubScreen.viewModelDom.show(); - delegateRun(self.oCurrentSubScreen, 'onShow'); - delegateRun(self.oCurrentSubScreen, 'onShowWithDelay', [], 200); + delegateRun(this.oCurrentSubScreen, 'onBeforeShow'); + this.oCurrentSubScreen.viewModelDom.show(); + delegateRun(this.oCurrentSubScreen, 'onShow'); + delegateRun(this.oCurrentSubScreen, 'onShowWithDelay', [], 200); - _.each(self.menu(), (oItem) => { - oItem.selected(oSettingsScreen && oSettingsScreen.__rlSettingsData && oItem.route === oSettingsScreen.__rlSettingsData.Route); + _.each(this.menu(), (item) => { + item.selected(settingsScreen && settingsScreen.__rlSettingsData && item.route === settingsScreen.__rlSettingsData.Route); }); $('#rl-content .b-settings .b-content .content').scrollTop(0); @@ -166,22 +165,23 @@ class AbstractSettingsScreen extends AbstractScreen } routes() { - var + const DefaultViewModel = _.find(VIEW_MODELS.settings, - (SettingsViewModel) => SettingsViewModel && SettingsViewModel.__rlSettingsData && SettingsViewModel.__rlSettingsData.IsDefault), + (SettingsViewModel) => SettingsViewModel && SettingsViewModel.__rlSettingsData && SettingsViewModel.__rlSettingsData.IsDefault + ), defaultRoute = DefaultViewModel && DefaultViewModel.__rlSettingsData ? DefaultViewModel.__rlSettingsData.Route : 'general', - oRules = { + rules = { subname: /^(.*)$/, - normalize_: (oRequest, oVals) => { - oVals.subname = isUnd(oVals.subname) ? defaultRoute : pString(oVals.subname); - return [oVals.subname]; + normalize_: (rquest, vals) => { + vals.subname = isUnd(vals.subname) ? defaultRoute : pString(vals.subname); + return [vals.subname]; } }; return [ - ['{subname}/', oRules], - ['{subname}', oRules], - ['', oRules] + ['{subname}/', rules], + ['{subname}', rules], + ['', rules] ]; } } diff --git a/dev/Screen/Admin/Login.js b/dev/Screen/Admin/Login.js index 11252825e..b7b836b3a 100644 --- a/dev/Screen/Admin/Login.js +++ b/dev/Screen/Admin/Login.js @@ -1,17 +1,20 @@ import {AbstractScreen} from 'Knoin/AbstractScreen'; -import App from 'App/Admin'; + +import {getApp} from 'Helper/Apps/Admin'; + +import {LoginAdminView} from 'View/Admin/Login'; class LoginAdminScreen extends AbstractScreen { constructor() { super('login', [ - require('View/Admin/Login') + LoginAdminView ]); } onShow() { - App.setWindowTitle(''); + getApp().setWindowTitle(''); } } diff --git a/dev/Screen/Admin/Settings.js b/dev/Screen/Admin/Settings.js index 2f27056c0..fba18a707 100644 --- a/dev/Screen/Admin/Settings.js +++ b/dev/Screen/Admin/Settings.js @@ -1,9 +1,10 @@ +/* global RL_COMMUNITY */ + import {addSettingsViewModel} from 'Knoin/Knoin'; import {runSettingsViewModelHooks} from 'Common/Plugins'; import {AbstractSettingsScreen} from 'Screen/AbstractSettings'; -import App from 'App/Admin'; import {GeneralAdminSettings} from 'Settings/Admin/General'; import {LoginAdminSettings} from 'Settings/Admin/Login'; @@ -15,12 +16,17 @@ import {PluginsAdminSettings} from 'Settings/Admin/Plugins'; import {PackagesAdminSettings} from 'Settings/Admin/Packages'; import {AboutAdminSettings} from 'Settings/Admin/About'; +import {getApp} from 'Helper/Apps/Admin'; + +import {MenuSettingsAdminView} from 'View/Admin/Settings/Menu'; +import {PaneSettingsAdminView} from 'View/Admin/Settings/Pane'; + class SettingsAdminScreen extends AbstractSettingsScreen { constructor() { super([ - require('View/Admin/Settings/Menu'), - require('View/Admin/Settings/Pane') + MenuSettingsAdminView, + PaneSettingsAdminView ]); } @@ -81,7 +87,7 @@ class SettingsAdminScreen extends AbstractSettingsScreen } onShow() { - App.setWindowTitle(''); + getApp().setWindowTitle(''); } } diff --git a/dev/Screen/User/About.js b/dev/Screen/User/About.js index c4fc88ad7..b46672048 100644 --- a/dev/Screen/User/About.js +++ b/dev/Screen/User/About.js @@ -1,17 +1,18 @@ import {AbstractScreen} from 'Knoin/AbstractScreen'; -import App from 'App/User'; + +import {AboutUserView} from 'View/User/About'; + +import {getApp} from 'Helper/Apps/User'; class AboutUserScreen extends AbstractScreen { constructor() { - super('about', [ - require('View/User/About') - ]); + super('about', [AboutUserView]); } onShow() { - App.setWindowTitle('RainLoop'); + getApp().setWindowTitle('RainLoop'); } } diff --git a/dev/Screen/User/Login.js b/dev/Screen/User/Login.js index c17edbc4d..3091865f1 100644 --- a/dev/Screen/User/Login.js +++ b/dev/Screen/User/Login.js @@ -1,17 +1,18 @@ import {AbstractScreen} from 'Knoin/AbstractScreen'; -import App from 'App/User'; + +import {LoginUserView} from 'View/User/Login'; + +import {getApp} from 'Helper/Apps/User'; class LoginUserScreen extends AbstractScreen { constructor() { - super('login', [ - require('View/User/Login') - ]); + super('login', [LoginUserView]); } onShow() { - App.setWindowTitle(''); + getApp().setWindowTitle(''); } } diff --git a/dev/Screen/User/MailBox.js b/dev/Screen/User/MailBox.js index ba2ccd460..1d10a32e9 100644 --- a/dev/Screen/User/MailBox.js +++ b/dev/Screen/User/MailBox.js @@ -16,17 +16,25 @@ import SettingsStore from 'Stores/User/Settings'; import FolderStore from 'Stores/User/Folder'; import MessageStore from 'Stores/User/Message'; +import {SystemDropDownMailBoxUserView} from 'View/User/MailBox/SystemDropDown'; +import {FolderListMailBoxUserView} from 'View/User/MailBox/FolderList'; +import {MessageListMailBoxUserView} from 'View/User/MailBox/MessageList'; +import {MessageViewMailBoxUserView} from 'View/User/MailBox/MessageView'; + +import {getApp} from 'Helper/Apps/User'; + +import {warmUpScreenPopup} from 'Knoin/Knoin'; + import {AbstractScreen} from 'Knoin/AbstractScreen'; -import App from 'App/User'; class MailBoxUserScreen extends AbstractScreen { constructor() { super('mailbox', [ - require('View/User/MailBox/SystemDropDown'), - require('View/User/MailBox/FolderList'), - require('View/User/MailBox/MessageList'), - require('View/User/MailBox/MessageView') + SystemDropDownMailBoxUserView, + FolderListMailBoxUserView, + MessageListMailBoxUserView, + MessageViewMailBoxUserView ]); } @@ -42,7 +50,7 @@ class MailBoxUserScreen extends AbstractScreen foldersInboxUnreadCount = 0; } - App.setWindowTitle(('' === email ? '' : '' + (0 < foldersInboxUnreadCount ? '(' + foldersInboxUnreadCount + ') ' : ' ') + email + ' - ') + i18n('TITLES/MAILBOX')); + getApp().setWindowTitle(('' === email ? '' : '' + (0 < foldersInboxUnreadCount ? '(' + foldersInboxUnreadCount + ') ' : ' ') + email + ' - ') + i18n('TITLES/MAILBOX')); } /** @@ -73,6 +81,7 @@ class MailBoxUserScreen extends AbstractScreen * @param {string} folderHash * @param {number} page * @param {string} search + * @returns {void} */ onRoute(folderHash, page, search) { let threadUid = folderHash.replace(/^(.+)~([\d]+)$/, '$2'); @@ -91,7 +100,7 @@ class MailBoxUserScreen extends AbstractScreen MessageStore.messageListSearch(search); MessageStore.messageListThreadUid(threadUid); - App.reloadMessageList(); + getApp().reloadMessageList(); } } @@ -104,9 +113,8 @@ class MailBoxUserScreen extends AbstractScreen MessageStore.messageList.subscribe(windowResizeCallback); MessageStore.message.subscribe(windowResizeCallback); - _.delay(() => { - SettingsStore.layout.valueHasMutated(); - }, Magics.Time50ms); + _.delay(() => SettingsStore.layout.valueHasMutated(), Magics.Time50ms); + _.delay(() => warmUpScreenPopup(require('View/Popup/Compose')), Magics.Time500ms); Events.sub('mailbox.inbox-unread-count', (count) => { FolderStore.foldersInboxUnreadCount(count); @@ -130,7 +138,7 @@ class MailBoxUserScreen extends AbstractScreen if (!bMobileDevice && !Settings.appSettingsGet('mobile')) { _.defer(() => { - App.initHorizontalLayoutResizer(ClientSideKeyName.MessageListSize); + getApp().initHorizontalLayoutResizer(ClientSideKeyName.MessageListSize); }); } } @@ -139,7 +147,7 @@ class MailBoxUserScreen extends AbstractScreen * @returns {Array} */ routes() { - var + const inboxFolderName = getFolderInboxName(), fNormS = (request, vals) => { vals[0] = pString(vals[0]); diff --git a/dev/Screen/User/Settings.js b/dev/Screen/User/Settings.js index 2b6809b68..046a555fc 100644 --- a/dev/Screen/User/Settings.js +++ b/dev/Screen/User/Settings.js @@ -11,7 +11,6 @@ import * as Settings from 'Storage/Settings'; import {addSettingsViewModel} from 'Knoin/Knoin'; import {AbstractSettingsScreen} from 'Screen/AbstractSettings'; -import App from 'App/User'; import {GeneralUserSettings} from 'Settings/User/General'; import {ContactsUserSettings} from 'Settings/User/Contacts'; @@ -25,13 +24,19 @@ import {FoldersUserSettings} from 'Settings/User/Folders'; import {ThemesUserSettings} from 'Settings/User/Themes'; import {OpenPgpUserSettings} from 'Settings/User/OpenPgp'; +import {SystemDropDownSettingsUserView} from 'View/User/Settings/SystemDropDown'; +import {MenuSettingsUserView} from 'View/User/Settings/Menu'; +import {PaneSettingsUserView} from 'View/User/Settings/Pane'; + +import {getApp} from 'Helper/Apps/User'; + class SettingsUserScreen extends AbstractSettingsScreen { constructor() { super([ - require('View/User/Settings/SystemDropDown'), - require('View/User/Settings/Menu'), - require('View/User/Settings/Pane') + SystemDropDownSettingsUserView, + MenuSettingsUserView, + PaneSettingsUserView ]); initOnStartOrLangChange(() => { @@ -144,7 +149,7 @@ class SettingsUserScreen extends AbstractSettingsScreen setSettingsTitle() { const sEmail = AccountStore.email(); - App.setWindowTitle(('' === sEmail ? '' : sEmail + ' - ') + this.sSettingsTitle); + getApp().setWindowTitle(('' === sEmail ? '' : sEmail + ' - ') + this.sSettingsTitle); } } diff --git a/dev/Settings/.gitignore b/dev/Settings/.gitignore deleted file mode 100644 index d686bd062..000000000 --- a/dev/Settings/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/Admin/Prem/** -/Admin/_Prem/** \ No newline at end of file diff --git a/dev/Settings/Admin/About.js b/dev/Settings/Admin/About.js index 192f66d88..0807bc7d5 100644 --- a/dev/Settings/Admin/About.js +++ b/dev/Settings/Admin/About.js @@ -1,11 +1,15 @@ +/* global RL_COMMUNITY */ + import ko from 'ko'; import {i18n, trigger as translatorTrigger} from 'Common/Translator'; import {appSettingsGet, settingsGet} from 'Storage/Settings'; -import CoreStore from 'Stores/Admin/Core'; import AppStore from 'Stores/Admin/App'; +import CoreStore from 'Stores/Admin/Core'; + +import {getApp} from 'Helper/Apps/Admin'; class AboutAdminSettings { @@ -71,14 +75,14 @@ class AboutAdminSettings onBuild() { if (this.access() && !this.community) { - require('App/Admin').default.reloadCoreData(); + getApp().reloadCoreData(); } } updateCoreData() { if (!this.coreUpdating() && !this.community) { - require('App/Admin').default.updateCoreData(); + getApp().updateCoreData(); } } } diff --git a/dev/Settings/Admin/Branding.js b/dev/Settings/Admin/Branding.js index d7b361442..8f99c50c0 100644 --- a/dev/Settings/Admin/Branding.js +++ b/dev/Settings/Admin/Branding.js @@ -1,4 +1,6 @@ +/* global RL_COMMUNITY */ + import _ from '_'; import ko from 'ko'; diff --git a/dev/Settings/Admin/Contacts.js b/dev/Settings/Admin/Contacts.js index fe43b8923..fcef9f416 100644 --- a/dev/Settings/Admin/Contacts.js +++ b/dev/Settings/Admin/Contacts.js @@ -91,11 +91,11 @@ class ContactsAdminSettings } }).extend({notify: 'always'}); - this.contactsType.subscribe(function() { + this.contactsType.subscribe(() => { this.testContactsSuccess(false); this.testContactsError(false); this.testContactsErrorMessage(''); - }, this); + }); this.pdoDsn = ko.observable(settingsGet('ContactsPdoDsn')); this.pdoUser = ko.observable(settingsGet('ContactsPdoUser')); @@ -111,7 +111,7 @@ class ContactsAdminSettings this.testContactsError = ko.observable(false); this.testContactsErrorMessage = ko.observable(''); - this.testContactsCommand = createCommand(this, () => { + this.testContactsCommand = createCommand(() => { this.testContactsSuccess(false); this.testContactsError(false); diff --git a/dev/Settings/Admin/Domains.js b/dev/Settings/Admin/Domains.js index 359c52859..0238e07bb 100644 --- a/dev/Settings/Admin/Domains.js +++ b/dev/Settings/Admin/Domains.js @@ -8,6 +8,8 @@ import {showScreenPopup} from 'Knoin/Knoin'; import DomainStore from 'Stores/Admin/Domain'; import Remote from 'Remote/Admin/Ajax'; +import {getApp} from 'Helper/Apps/Admin'; + class DomainsAdminSettings { constructor() { @@ -42,15 +44,15 @@ class DomainsAdminSettings onBuild(oDom) { const self = this; oDom - .on('click', '.b-admin-domains-list-table .e-item .e-action', function() { - const domainItem = ko.dataFor(this); + .on('click', '.b-admin-domains-list-table .e-item .e-action', function() { // eslint-disable-line prefer-arrow-callback + const domainItem = ko.dataFor(this); // eslint-disable-line no-invalid-this if (domainItem) { Remote.domain(self.onDomainLoadRequest, domainItem.name); } }); - require('App/Admin').default.reloadDomainList(); + getApp().reloadDomainList(); } onDomainLoadRequest(sResult, oData) { @@ -61,7 +63,7 @@ class DomainsAdminSettings } onDomainListChangeRequest() { - require('App/Admin').default.reloadDomainList(); + getApp().reloadDomainList(); } } diff --git a/dev/Settings/Admin/Login.js b/dev/Settings/Admin/Login.js index 6a4028828..d41d1f7fe 100644 --- a/dev/Settings/Admin/Login.js +++ b/dev/Settings/Admin/Login.js @@ -5,16 +5,16 @@ import ko from 'ko'; import {settingsSaveHelperSimpleFunction, boolToAjax, trim} from 'Common/Utils'; import {settingsGet} from 'Storage/Settings'; -import AppAdminStore from 'Stores/Admin/App'; +import AppStore from 'Stores/Admin/App'; class LoginAdminSettings { constructor() { - this.determineUserLanguage = AppAdminStore.determineUserLanguage; - this.determineUserDomain = AppAdminStore.determineUserDomain; + this.determineUserLanguage = AppStore.determineUserLanguage; + this.determineUserDomain = AppStore.determineUserDomain; this.defaultDomain = ko.observable(settingsGet('LoginDefaultDomain')).idleTrigger(); - this.allowLanguagesOnLogin = AppAdminStore.allowLanguagesOnLogin; + this.allowLanguagesOnLogin = AppStore.allowLanguagesOnLogin; this.dummy = ko.observable(false); } diff --git a/dev/Settings/Admin/Packages.js b/dev/Settings/Admin/Packages.js index 09f04c819..044f15c8e 100644 --- a/dev/Settings/Admin/Packages.js +++ b/dev/Settings/Admin/Packages.js @@ -9,6 +9,8 @@ import {getNotification} from 'Common/Translator'; import PackageStore from 'Stores/Admin/Package'; import Remote from 'Remote/Admin/Ajax'; +import {getApp} from 'Helper/Apps/Admin'; + class PackagesAdminSettings { constructor() { @@ -30,7 +32,7 @@ class PackagesAdminSettings } onBuild() { - require('App/Admin').default.reloadPackagesList(); + getApp().reloadPackagesList(); } requestHelper(packageToRequest, install) { @@ -63,7 +65,7 @@ class PackagesAdminSettings } else { - require('App/Admin').default.reloadPackagesList(); + getApp().reloadPackagesList(); } }; } diff --git a/dev/Settings/Admin/Plugins.js b/dev/Settings/Admin/Plugins.js index 5ea055526..7b9fc9ed6 100644 --- a/dev/Settings/Admin/Plugins.js +++ b/dev/Settings/Admin/Plugins.js @@ -1,4 +1,6 @@ +/* global RL_COMMUNITY */ + import _ from '_'; import ko from 'ko'; @@ -14,6 +16,8 @@ import PluginStore from 'Stores/Admin/Plugin'; import Remote from 'Remote/Admin/Ajax'; +import {getApp} from 'Helper/Apps/Admin'; + class PluginsAdminSettings { constructor() { @@ -40,17 +44,19 @@ class PluginsAdminSettings } onBuild(oDom) { + const self = this; + oDom - .on('click', '.e-item .configure-plugin-action', function() { - const plugin = ko.dataFor(this); + .on('click', '.e-item .configure-plugin-action', function() { // eslint-disable-line prefer-arrow-callback + const plugin = ko.dataFor(this); // eslint-disable-line no-invalid-this if (plugin) { self.configurePlugin(plugin); } }) - .on('click', '.e-item .disabled-plugin', function() { - const plugin = ko.dataFor(this); + .on('click', '.e-item .disabled-plugin', function() { // eslint-disable-line prefer-arrow-callback + const plugin = ko.dataFor(this); // eslint-disable-line no-invalid-this if (plugin) { self.disablePlugin(plugin); @@ -66,7 +72,7 @@ class PluginsAdminSettings onShow() { PluginStore.plugins.error(''); - require('App/Admin').default.reloadPluginList(); + getApp().reloadPluginList(); } onPluginLoadRequest(result, data) { @@ -92,7 +98,7 @@ class PluginsAdminSettings } } - require('App/Admin').default.reloadPluginList(); + getApp().reloadPluginList(); } } diff --git a/dev/Settings/Admin/Prem/Branding.js b/dev/Settings/Admin/Prem/Branding.js new file mode 100644 index 000000000..3236651d6 --- /dev/null +++ b/dev/Settings/Admin/Prem/Branding.js @@ -0,0 +1,105 @@ + +import _ from '_'; +import {settingsSaveHelperSimpleFunction, trim, boolToAjax} from 'Common/Utils'; + +import {BrandingAdminSettings} from 'Settings/Admin/Branding'; + +class BrandingPremAdminSettings extends BrandingAdminSettings +{ + onBuild(oDom) { + super.onBuild(oDom); + + if (this.capa && this.capa() && !this.community) + { + _.delay(() => { + const + Remote = require('Remote/Admin/Ajax'), + f1 = settingsSaveHelperSimpleFunction(this.loginLogo.trigger, this), + f2 = settingsSaveHelperSimpleFunction(this.loginDescription.trigger, this), + f3 = settingsSaveHelperSimpleFunction(this.loginCss.trigger, this), + f4 = settingsSaveHelperSimpleFunction(this.userLogo.trigger, this), + f5 = settingsSaveHelperSimpleFunction(this.userLogoTitle.trigger, this), + f6 = settingsSaveHelperSimpleFunction(this.loginBackground.trigger, this), + f7 = settingsSaveHelperSimpleFunction(this.userCss.trigger, this), + f8 = settingsSaveHelperSimpleFunction(this.welcomePageUrl.trigger, this), + f9 = settingsSaveHelperSimpleFunction(this.welcomePageDisplay.trigger, this), + f10 = settingsSaveHelperSimpleFunction(this.userLogoMessage.trigger, this), + f11 = settingsSaveHelperSimpleFunction(this.userIframeMessage.trigger, this); + + this.loginLogo.subscribe((value) => { + Remote.saveAdminConfig(f1, { + 'LoginLogo': trim(value) + }); + }); + + this.loginDescription.subscribe((value) => { + Remote.saveAdminConfig(f2, { + 'LoginDescription': trim(value) + }); + }); + + this.loginCss.subscribe((value) => { + Remote.saveAdminConfig(f3, { + 'LoginCss': trim(value) + }); + }); + + this.userLogo.subscribe((value) => { + Remote.saveAdminConfig(f4, { + 'UserLogo': trim(value) + }); + }); + + this.userLogoTitle.subscribe((value) => { + Remote.saveAdminConfig(f5, { + 'UserLogoTitle': trim(value) + }); + }); + + this.userLogoMessage.subscribe((value) => { + Remote.saveAdminConfig(f10, { + 'UserLogoMessage': trim(value) + }); + }); + + this.userIframeMessage.subscribe((value) => { + Remote.saveAdminConfig(f11, { + 'UserIframeMessage': trim(value) + }); + }); + + this.loginBackground.subscribe((value) => { + Remote.saveAdminConfig(f6, { + 'LoginBackground': trim(value) + }); + }); + + this.userCss.subscribe((value) => { + Remote.saveAdminConfig(f7, { + 'UserCss': trim(value) + }); + }); + + this.welcomePageUrl.subscribe((value) => { + Remote.saveAdminConfig(f8, { + 'WelcomePageUrl': trim(value) + }); + }); + + this.welcomePageDisplay.subscribe((value) => { + Remote.saveAdminConfig(f9, { + 'WelcomePageDisplay': trim(value) + }); + }); + + this.loginPowered.subscribe((value) => { + Remote.saveAdminConfig(null, { + 'LoginPowered': boolToAjax(value) + }); + }); + }, 50); + } + } +} + +export {BrandingPremAdminSettings, BrandingPremAdminSettings as default}; diff --git a/dev/Settings/Admin/Prem/Licensing.js b/dev/Settings/Admin/Prem/Licensing.js new file mode 100644 index 000000000..95b44ff56 --- /dev/null +++ b/dev/Settings/Admin/Prem/Licensing.js @@ -0,0 +1,71 @@ + +import ko from 'ko'; + +import {settingsGet} from 'Storage/Settings'; +import {showScreenPopup} from 'Knoin/Knoin'; + +import LicenseStore from 'Stores/Admin/License'; + +import {getApp} from 'Helper/Apps/Admin'; + +class LicensingPremAdminSettings +{ + constructor() { + this.licensing = LicenseStore.licensing; + this.licensingProcess = LicenseStore.licensingProcess; + this.licenseValid = LicenseStore.licenseValid; + this.licenseExpired = LicenseStore.licenseExpired; + this.licenseError = LicenseStore.licenseError; + this.licenseTrigger = LicenseStore.licenseTrigger; + + this.adminDomain = ko.observable(''); + this.subscriptionEnabled = ko.observable(!!settingsGet('SubscriptionEnabled')); + + this.licenseTrigger.subscribe(() => { + if (this.subscriptionEnabled()) + { + getApp().reloadLicensing(true); + } + }); + } + + onBuild() { + if (this.subscriptionEnabled()) + { + getApp().reloadLicensing(false); + } + } + + onShow() { + this.adminDomain(settingsGet('AdminDomain')); + } + + showActivationForm() { + showScreenPopup(require('View/Popup/Activate')); + } + + showTrialForm() { + showScreenPopup(require('View/Popup/Activate'), [true]); + } + + /** + * @returns {boolean} + */ + licenseIsUnlim() { + return 1898625600 === this.licenseExpired() || 1898625700 === this.licenseExpired(); // eslint-disable-line no-magic-numbers + } + + /** + * @returns {string} + */ + licenseExpiredMomentValue() { + const + moment = require('moment'), + time = this.licenseExpired(), + momentUnix = moment.unix(time); + + return this.licenseIsUnlim() ? 'Never' : (time && (momentUnix.format('LL') + ' (' + momentUnix.from(moment()) + ')')); + } +} + +export {LicensingPremAdminSettings, LicensingPremAdminSettings as default}; diff --git a/dev/Settings/Admin/Security.js b/dev/Settings/Admin/Security.js index 642f103ba..5af10f8d2 100644 --- a/dev/Settings/Admin/Security.js +++ b/dev/Settings/Admin/Security.js @@ -77,7 +77,7 @@ class SecurityAdminSettings this.adminPasswordNewError(false); }); - this.saveNewAdminPasswordCommand = createCommand(this, () => { + this.saveNewAdminPasswordCommand = createCommand(() => { if ('' === trim(this.adminLogin())) { diff --git a/dev/Settings/User/Accounts.js b/dev/Settings/User/Accounts.js index 1eefbb25c..ff19e8f18 100644 --- a/dev/Settings/User/Accounts.js +++ b/dev/Settings/User/Accounts.js @@ -8,12 +8,14 @@ import {root} from 'Common/Links'; import {capa} from 'Storage/Settings'; -import {showScreenPopup, routeOff, setHash} from 'Knoin/Knoin'; - import AccountStore from 'Stores/User/Account'; import IdentityStore from 'Stores/User/Identity'; import Remote from 'Remote/User/Ajax'; +import {getApp} from 'Helper/Apps/User'; + +import {showScreenPopup, routeOff, setHash} from 'Knoin/Knoin'; + class AccountsUserSettings { constructor() { @@ -66,7 +68,7 @@ class AccountsUserSettings { this.accounts.remove((account) => accountToRemove === account); - Remote.accountDelete(function(result, data) { + Remote.accountDelete((result, data) => { if (StorageResultType.Success === result && data && data.Result && data.Reload) { @@ -78,7 +80,7 @@ class AccountsUserSettings } else { - require('App/User').default.accountsAndIdentities(); + getApp().accountsAndIdentities(); } }, accountToRemove.email); @@ -100,7 +102,7 @@ class AccountsUserSettings IdentityStore.identities.remove((oIdentity) => identityToRemove === oIdentity); Remote.identityDelete(() => { - require('App/User').default.accountsAndIdentities(); + getApp().accountsAndIdentities(); }, identityToRemove.id); } } @@ -112,18 +114,19 @@ class AccountsUserSettings } onBuild(oDom) { - var self = this; + + const self = this; oDom - .on('click', '.accounts-list .account-item .e-action', function() { - const account = ko.dataFor(this); + .on('click', '.accounts-list .account-item .e-action', function() { // eslint-disable-line prefer-arrow-callback + const account = ko.dataFor(this); // eslint-disable-line no-invalid-this if (account) { self.editAccount(account); } }) - .on('click', '.identities-list .identity-item .e-action', function() { - const identity = ko.dataFor(this); + .on('click', '.identities-list .identity-item .e-action', function() { // eslint-disable-line prefer-arrow-callback + const identity = ko.dataFor(this); // eslint-disable-line no-invalid-this if (identity) { self.editIdentity(identity); diff --git a/dev/Settings/User/ChangePassword.js b/dev/Settings/User/ChangePassword.js index 74c02d912..087011b0b 100644 --- a/dev/Settings/User/ChangePassword.js +++ b/dev/Settings/User/ChangePassword.js @@ -8,6 +8,8 @@ import {getNotificationFromResponse, i18n} from 'Common/Translator'; import Remote from 'Remote/User/Ajax'; +import {getApp} from 'Helper/Apps/User'; + class ChangePasswordUserSettings { constructor() { @@ -41,7 +43,7 @@ class ChangePasswordUserSettings this.passwordMismatch(false); }); - this.saveNewPasswordCommand = createCommand(this, () => { + this.saveNewPasswordCommand = createCommand(() => { if (this.newPassword() !== this.newPassword2()) { this.passwordMismatch(true); @@ -90,7 +92,7 @@ class ChangePasswordUserSettings this.passwordUpdateSuccess(true); this.currentPassword.error(false); - require('App/User').default.setClientSideToken(data.Result); + getApp().setClientSideToken(data.Result); } else { diff --git a/dev/Settings/User/Filters.js b/dev/Settings/User/Filters.js index bab1babff..2a6685d3d 100644 --- a/dev/Settings/User/Filters.js +++ b/dev/Settings/User/Filters.js @@ -47,7 +47,7 @@ class FiltersUserSettings this.filterForDeletion = ko.observable(null) .extend({falseTimeout: 3000}).extend({toggleSubscribeProperty: [this, 'deleteAccess']}); - this.saveChanges = createCommand(this, () => { + this.saveChanges = createCommand(() => { if (!this.filters.saving()) { if (this.filterRaw.active() && '' === trim(this.filterRaw())) @@ -187,11 +187,12 @@ class FiltersUserSettings } onBuild(oDom) { + const self = this; oDom - .on('click', '.filter-item .e-action', function() { - const filter = ko.dataFor(this); + .on('click', '.filter-item .e-action', function() { // eslint-disable-line prefer-arrow-callback + const filter = ko.dataFor(this); // eslint-disable-line no-invalid-this if (filter) { self.editFilter(filter); diff --git a/dev/Settings/User/Folders.js b/dev/Settings/User/Folders.js index edb9e3da6..77d38cfee 100644 --- a/dev/Settings/User/Folders.js +++ b/dev/Settings/User/Folders.js @@ -10,13 +10,15 @@ import {removeFolderFromCacheList} from 'Common/Cache'; import {appSettingsGet} from 'Storage/Settings'; import * as Local from 'Storage/Client'; -import {showScreenPopup} from 'Knoin/Knoin'; - import FolderStore from 'Stores/User/Folder'; import Promises from 'Promises/User/Ajax'; import Remote from 'Remote/User/Ajax'; +import {getApp} from 'Helper/Apps/User'; + +import {showScreenPopup} from 'Knoin/Knoin'; + class FoldersUserSettings { constructor() { @@ -61,7 +63,7 @@ class FoldersUserSettings { Local.set(ClientSideKeyName.FoldersLashHash, ''); - require('App/User').default.foldersPromisesActionHelper( + getApp().foldersPromisesActionHelper( Promises.folderRename(folder.fullNameRaw, nameToEdit, FolderStore.foldersRenaming), Notification.CantRenameFolder ); @@ -131,7 +133,7 @@ class FoldersUserSettings FolderStore.folderList.remove(fRemoveFolder); - require('App/User').default.foldersPromisesActionHelper( + getApp().foldersPromisesActionHelper( Promises.folderDelete(folderToRemove.fullNameRaw, FolderStore.foldersDeleting), Notification.CantDeleteFolder ); diff --git a/dev/Settings/User/General.js b/dev/Settings/User/General.js index 8451ed7ea..9130bed3c 100644 --- a/dev/Settings/User/General.js +++ b/dev/Settings/User/General.js @@ -165,7 +165,7 @@ class GeneralUserSettings }); }); - this.layout.subscribe(function(value) { + this.layout.subscribe((value) => { MessageStore.messageList([]); Remote.saveSettings(f2, { 'Layout': value diff --git a/dev/Settings/User/OpenPgp.js b/dev/Settings/User/OpenPgp.js index c3387af9f..d37164d33 100644 --- a/dev/Settings/User/OpenPgp.js +++ b/dev/Settings/User/OpenPgp.js @@ -5,10 +5,12 @@ import ko from 'ko'; import {delegateRunOnDestroy} from 'Common/Utils'; import {bIsHttps} from 'Common/Globals'; -import {showScreenPopup} from 'Knoin/Knoin'; - import PgpStore from 'Stores/User/Pgp'; +import {getApp} from 'Helper/Apps/User'; + +import {showScreenPopup} from 'Knoin/Knoin'; + class OpenPgpUserSettings { constructor() { @@ -60,7 +62,7 @@ class OpenPgpUserSettings PgpStore.openpgpKeyring.store(); } - require('App/User').default.reloadOpenPgpKeys(); + getApp().reloadOpenPgpKeys(); } } } diff --git a/dev/Settings/User/Social.js b/dev/Settings/User/Social.js index 38b1487fc..31ec24b8b 100644 --- a/dev/Settings/User/Social.js +++ b/dev/Settings/User/Social.js @@ -3,6 +3,8 @@ import {createCommand} from 'Common/Utils'; import SocialStore from 'Stores/Social'; +import {getApp} from 'Helper/Apps/User'; + class SocialUserSettings { constructor() { @@ -28,43 +30,39 @@ class SocialUserSettings this.twitterLoggined = SocialStore.twitter.loggined; this.twitterUserName = SocialStore.twitter.userName; - this.connectGoogle = createCommand(this, () => { + this.connectGoogle = createCommand(() => { if (!this.googleLoggined()) { - this.getApp().googleConnect(); + getApp().googleConnect(); } }, () => !this.googleLoggined() && !this.googleActions()); - this.disconnectGoogle = createCommand(this, () => { - this.getApp().googleDisconnect(); + this.disconnectGoogle = createCommand(() => { + getApp().googleDisconnect(); }); - this.connectFacebook = createCommand(this, () => { + this.connectFacebook = createCommand(() => { if (!this.facebookLoggined()) { - this.getApp().facebookConnect(); + getApp().facebookConnect(); } }, () => !this.facebookLoggined() && !this.facebookActions()); - this.disconnectFacebook = createCommand(this, () => { - this.getApp().facebookDisconnect(); + this.disconnectFacebook = createCommand(() => { + getApp().facebookDisconnect(); }); - this.connectTwitter = createCommand(this, () => { + this.connectTwitter = createCommand(() => { if (!this.twitterLoggined()) { - this.getApp().twitterConnect(); + getApp().twitterConnect(); } }, () => !this.twitterLoggined() && !this.twitterActions()); - this.disconnectTwitter = createCommand(this, () => { - this.getApp().twitterDisconnect(); + this.disconnectTwitter = createCommand(() => { + getApp().twitterDisconnect(); }); } - - getApp() { - return require('App/User').default; - } } export {SocialUserSettings, SocialUserSettings as default}; diff --git a/dev/Settings/User/Templates.js b/dev/Settings/User/Templates.js index 6f3306d22..e5c5ae582 100644 --- a/dev/Settings/User/Templates.js +++ b/dev/Settings/User/Templates.js @@ -3,11 +3,13 @@ import ko from 'ko'; import {i18n} from 'Common/Translator'; -import {showScreenPopup} from 'Knoin/Knoin'; - import TemplateStore from 'Stores/User/Template'; import Remote from 'Remote/User/Ajax'; +import {getApp} from 'Helper/Apps/User'; + +import {showScreenPopup} from 'Knoin/Knoin'; + class TemplatesUserSettings { constructor() { @@ -55,19 +57,16 @@ class TemplatesUserSettings } reloadTemplates() { - this.getApp().templates(); - } - - getApp() { - return require('App/User').default; + getApp().templates(); } onBuild(oDom) { - var self = this; + + const self = this; oDom - .on('click', '.templates-list .template-item .e-action', function() { - const template = ko.dataFor(this); + .on('click', '.templates-list .template-item .e-action', function() { // eslint-disable-line prefer-arrow-callback + const template = ko.dataFor(this); // eslint-disable-line no-invalid-this if (template) { self.editTemplate(template); diff --git a/dev/Stores/AbstractApp.js b/dev/Stores/AbstractApp.js index 65c43d7f2..a396857c1 100644 --- a/dev/Stores/AbstractApp.js +++ b/dev/Stores/AbstractApp.js @@ -11,9 +11,9 @@ class AbstractAppStore this.interfaceAnimation = ko.observable(true); - this.interfaceAnimation.subscribe(function(bValue) { - const bAnim = bMobileDevice || !bValue; - $html.toggleClass('rl-anim', !bAnim).toggleClass('no-rl-anim', bAnim); + this.interfaceAnimation.subscribe((value) => { + const anim = bMobileDevice || !value; + $html.toggleClass('rl-anim', !anim).toggleClass('no-rl-anim', anim); }); this.interfaceAnimation.valueHasMutated(); diff --git a/dev/Stores/Admin/Capa.js b/dev/Stores/Admin/Capa.js index c80bbaac4..6e9e891ed 100644 --- a/dev/Stores/Admin/Capa.js +++ b/dev/Stores/Admin/Capa.js @@ -1,44 +1,39 @@ -var - ko = require('ko'), +import ko from 'ko'; +import {Capa} from 'Common/Enums'; +import * as Settings from 'Storage/Settings'; - Enums = require('Common/Enums'), - - Settings = require('Storage/Settings'); - -/** - * @constructor - */ -function CapaAdminStore() +class CapaAdminStore { - this.additionalAccounts = ko.observable(false); - this.identities = ko.observable(false); - this.gravatar = ko.observable(false); - this.attachmentThumbnails = ko.observable(false); - this.sieve = ko.observable(false); - this.filters = ko.observable(false); - this.themes = ko.observable(true); - this.userBackground = ko.observable(false); - this.openPGP = ko.observable(false); - this.twoFactorAuth = ko.observable(false); - this.twoFactorAuthForce = ko.observable(false); - this.templates = ko.observable(false); + constructor() { + this.additionalAccounts = ko.observable(false); + this.identities = ko.observable(false); + this.gravatar = ko.observable(false); + this.attachmentThumbnails = ko.observable(false); + this.sieve = ko.observable(false); + this.filters = ko.observable(false); + this.themes = ko.observable(true); + this.userBackground = ko.observable(false); + this.openPGP = ko.observable(false); + this.twoFactorAuth = ko.observable(false); + this.twoFactorAuthForce = ko.observable(false); + this.templates = ko.observable(false); + } + + populate() { + this.additionalAccounts(Settings.capa(Capa.AdditionalAccounts)); + this.identities(Settings.capa(Capa.Identities)); + this.gravatar(Settings.capa(Capa.Gravatar)); + this.attachmentThumbnails(Settings.capa(Capa.AttachmentThumbnails)); + this.sieve(Settings.capa(Capa.Sieve)); + this.filters(Settings.capa(Capa.Filters)); + this.themes(Settings.capa(Capa.Themes)); + this.userBackground(Settings.capa(Capa.UserBackground)); + this.openPGP(Settings.capa(Capa.OpenPGP)); + this.twoFactorAuth(Settings.capa(Capa.TwoFactor)); + this.twoFactorAuthForce(Settings.capa(Capa.TwoFactorForce)); + this.templates(Settings.capa(Capa.Templates)); + } } -CapaAdminStore.prototype.populate = function() -{ - this.additionalAccounts(Settings.capa(Enums.Capa.AdditionalAccounts)); - this.identities(Settings.capa(Enums.Capa.Identities)); - this.gravatar(Settings.capa(Enums.Capa.Gravatar)); - this.attachmentThumbnails(Settings.capa(Enums.Capa.AttachmentThumbnails)); - this.sieve(Settings.capa(Enums.Capa.Sieve)); - this.filters(Settings.capa(Enums.Capa.Filters)); - this.themes(Settings.capa(Enums.Capa.Themes)); - this.userBackground(Settings.capa(Enums.Capa.UserBackground)); - this.openPGP(Settings.capa(Enums.Capa.OpenPGP)); - this.twoFactorAuth(Settings.capa(Enums.Capa.TwoFactor)); - this.twoFactorAuthForce(Settings.capa(Enums.Capa.TwoFactorForce)); - this.templates(Settings.capa(Enums.Capa.Templates)); -}; - module.exports = new CapaAdminStore(); diff --git a/dev/Stores/Admin/Core.js b/dev/Stores/Admin/Core.js index 0a6a217c7..173a7a157 100644 --- a/dev/Stores/Admin/Core.js +++ b/dev/Stores/Admin/Core.js @@ -1,23 +1,22 @@ -var ko = require('ko'); +import ko from 'ko'; -/** - * @constructor - */ -function CoreAdminStore() +class CoreAdminStore { - this.coreReal = ko.observable(true); - this.coreChannel = ko.observable('stable'); - this.coreType = ko.observable('stable'); - this.coreUpdatable = ko.observable(true); - this.coreAccess = ko.observable(true); - this.coreWarning = ko.observable(false); - this.coreChecking = ko.observable(false).extend({'throttle': 100}); - this.coreUpdating = ko.observable(false).extend({'throttle': 100}); - this.coreVersion = ko.observable(''); - this.coreRemoteVersion = ko.observable(''); - this.coreRemoteRelease = ko.observable(''); - this.coreVersionCompare = ko.observable(-2); + constructor() { + this.coreReal = ko.observable(true); + this.coreChannel = ko.observable('stable'); + this.coreType = ko.observable('stable'); + this.coreUpdatable = ko.observable(true); + this.coreAccess = ko.observable(true); + this.coreWarning = ko.observable(false); + this.coreChecking = ko.observable(false).extend({throttle: 100}); + this.coreUpdating = ko.observable(false).extend({throttle: 100}); + this.coreVersion = ko.observable(''); + this.coreRemoteVersion = ko.observable(''); + this.coreRemoteRelease = ko.observable(''); + this.coreVersionCompare = ko.observable(-2); + } } module.exports = new CoreAdminStore(); diff --git a/dev/Stores/Admin/Domain.js b/dev/Stores/Admin/Domain.js index 19142ac47..e37ce9241 100644 --- a/dev/Stores/Admin/Domain.js +++ b/dev/Stores/Admin/Domain.js @@ -1,17 +1,13 @@ -var ko = require('ko'); +import ko from 'ko'; -/** - * @constructor - */ -function DomainAdminStore() +class DomainAdminStore { - this.domains = ko.observableArray([]); - this.domains.loading = ko.observable(false).extend({'throttle': 100}); - - this.domainsWithoutAliases = this.domains.filter(function(oItem) { - return oItem && !oItem.alias; - }); + constructor() { + this.domains = ko.observableArray([]); + this.domains.loading = ko.observable(false).extend({'throttle': 100}); + this.domainsWithoutAliases = this.domains.filter((item) => item && !item.alias); + } } module.exports = new DomainAdminStore(); diff --git a/dev/Stores/Admin/License.js b/dev/Stores/Admin/License.js index 954fe1a89..8b0717772 100644 --- a/dev/Stores/Admin/License.js +++ b/dev/Stores/Admin/License.js @@ -1,18 +1,17 @@ -var ko = require('ko'); +import ko from 'ko'; -/** - * @constructor - */ -function LicenseAdminStore() +class LicenseAdminStore { - this.licensing = ko.observable(false); - this.licensingProcess = ko.observable(false); - this.licenseValid = ko.observable(false); - this.licenseExpired = ko.observable(0); - this.licenseError = ko.observable(''); + constructor() { + this.licensing = ko.observable(false); + this.licensingProcess = ko.observable(false); + this.licenseValid = ko.observable(false); + this.licenseExpired = ko.observable(0); + this.licenseError = ko.observable(''); - this.licenseTrigger = ko.observable(false); + this.licenseTrigger = ko.observable(false); + } } module.exports = new LicenseAdminStore(); diff --git a/dev/Stores/Admin/Package.js b/dev/Stores/Admin/Package.js index 1f882c109..b913d48d1 100644 --- a/dev/Stores/Admin/Package.js +++ b/dev/Stores/Admin/Package.js @@ -1,16 +1,15 @@ -var ko = require('ko'); +import ko from 'ko'; -/** - * @constructor - */ -function PackageAdminStore() +class PackageAdminStore { - this.packages = ko.observableArray([]); - this.packages.loading = ko.observable(false).extend({'throttle': 100}); + constructor() { + this.packages = ko.observableArray([]); + this.packages.loading = ko.observable(false).extend({throttle: 100}); - this.packagesReal = ko.observable(true); - this.packagesMainUpdatable = ko.observable(true); + this.packagesReal = ko.observable(true); + this.packagesMainUpdatable = ko.observable(true); + } } module.exports = new PackageAdminStore(); diff --git a/dev/Stores/Admin/Plugin.js b/dev/Stores/Admin/Plugin.js index b51714041..fcdc2389e 100644 --- a/dev/Stores/Admin/Plugin.js +++ b/dev/Stores/Admin/Plugin.js @@ -1,14 +1,13 @@ -var ko = require('ko'); +import ko from 'ko'; -/** - * @constructor - */ -function PluginAdminStore() +class PluginAdminStore { - this.plugins = ko.observableArray([]); - this.plugins.loading = ko.observable(false).extend({'throttle': 100}); - this.plugins.error = ko.observable(''); + constructor() { + this.plugins = ko.observableArray([]); + this.plugins.loading = ko.observable(false).extend({throttle: 100}); + this.plugins.error = ko.observable(''); + } } module.exports = new PluginAdminStore(); diff --git a/dev/Stores/Language.js b/dev/Stores/Language.js index 67ff75777..e6d27d0db 100644 --- a/dev/Stores/Language.js +++ b/dev/Stores/Language.js @@ -1,45 +1,40 @@ -var - ko = require('ko'), +import ko from 'ko'; +import {isArray} from 'Common/Utils'; +import * as Settings from 'Storage/Settings'; - Utils = require('Common/Utils'), - - Settings = require('Storage/Settings'); - -/** - * @constructor - */ -function LanguageStore() +class LanguageStore { - this.languages = ko.observableArray([]); - this.languagesAdmin = ko.observableArray([]); + constructor() { + this.languages = ko.observableArray([]); + this.languagesAdmin = ko.observableArray([]); - this.language = ko.observable('') - .extend({'limitedList': this.languages}) - .extend({'reversible': true}); + this.language = ko.observable('') + .extend({limitedList: this.languages}) + .extend({reversible: true}); - this.languageAdmin = ko.observable('') - .extend({'limitedList': this.languagesAdmin}) - .extend({'reversible': true}); + this.languageAdmin = ko.observable('') + .extend({limitedList: this.languagesAdmin}) + .extend({reversible: true}); - this.userLanguage = ko.observable(''); - this.userLanguageAdmin = ko.observable(''); + this.userLanguage = ko.observable(''); + this.userLanguageAdmin = ko.observable(''); + } + + populate() { + const + aLanguages = Settings.appSettingsGet('languages'), + aLanguagesAdmin = Settings.appSettingsGet('languagesAdmin'); + + this.languages(isArray(aLanguages) ? aLanguages : []); + this.languagesAdmin(isArray(aLanguagesAdmin) ? aLanguagesAdmin : []); + + this.language(Settings.settingsGet('Language')); + this.languageAdmin(Settings.settingsGet('LanguageAdmin')); + + this.userLanguage(Settings.settingsGet('UserLanguage')); + this.userLanguageAdmin(Settings.settingsGet('UserLanguageAdmin')); + } } -LanguageStore.prototype.populate = function() -{ - var - aLanguages = Settings.appSettingsGet('languages'), - aLanguagesAdmin = Settings.appSettingsGet('languagesAdmin'); - - this.languages(Utils.isArray(aLanguages) ? aLanguages : []); - this.languagesAdmin(Utils.isArray(aLanguagesAdmin) ? aLanguagesAdmin : []); - - this.language(Settings.settingsGet('Language')); - this.languageAdmin(Settings.settingsGet('LanguageAdmin')); - - this.userLanguage(Settings.settingsGet('UserLanguage')); - this.userLanguageAdmin(Settings.settingsGet('UserLanguageAdmin')); -}; - module.exports = new LanguageStore(); diff --git a/dev/Stores/Social.js b/dev/Stores/Social.js index 8ba455ea6..39e4b1594 100644 --- a/dev/Stores/Social.js +++ b/dev/Stores/Social.js @@ -1,103 +1,103 @@ -var ko = require('ko'); +import window from 'window'; +import ko from 'ko'; +import $ from '$'; +import * as Settings from 'Storage/Settings'; -/** - * @constructor - */ -function SocialStore() +class SocialStore { - this.google = {}; - this.twitter = {}; - this.facebook = {}; - this.dropbox = {}; + constructor() { + this.google = {}; + this.twitter = {}; + this.facebook = {}; + this.dropbox = {}; - // Google - this.google.enabled = ko.observable(false); + // Google + this.google.enabled = ko.observable(false); - this.google.clientID = ko.observable(''); - this.google.clientSecret = ko.observable(''); - this.google.apiKey = ko.observable(''); + this.google.clientID = ko.observable(''); + this.google.clientSecret = ko.observable(''); + this.google.apiKey = ko.observable(''); - this.google.loading = ko.observable(false); - this.google.userName = ko.observable(''); + this.google.loading = ko.observable(false); + this.google.userName = ko.observable(''); - this.google.loggined = ko.computed(function() { - return '' !== this.google.userName(); - }, this); + this.google.loggined = ko.computed(() => '' !== this.google.userName()); - this.google.capa = {}; - this.google.capa.auth = ko.observable(false); - this.google.capa.authFast = ko.observable(false); - this.google.capa.drive = ko.observable(false); - this.google.capa.preview = ko.observable(false); + this.google.capa = {}; + this.google.capa.auth = ko.observable(false); + this.google.capa.authFast = ko.observable(false); + this.google.capa.drive = ko.observable(false); + this.google.capa.preview = ko.observable(false); - this.google.require = {}; - this.google.require.clientSettings = ko.computed(function() { - return this.google.enabled() && (this.google.capa.auth() || this.google.capa.drive()); - }, this); + this.google.require = {}; + this.google.require.clientSettings = ko.computed( + () => this.google.enabled() && (this.google.capa.auth() || this.google.capa.drive())); - this.google.require.apiKeySettings = ko.computed(function() { - return this.google.enabled() && this.google.capa.drive(); - }, this); + this.google.require.apiKeySettings = ko.computed(() => this.google.enabled() && this.google.capa.drive()); - // Facebook - this.facebook.enabled = ko.observable(false); - this.facebook.appID = ko.observable(''); - this.facebook.appSecret = ko.observable(''); - this.facebook.loading = ko.observable(false); - this.facebook.userName = ko.observable(''); - this.facebook.supported = ko.observable(false); + // Facebook + this.facebook.enabled = ko.observable(false); + this.facebook.appID = ko.observable(''); + this.facebook.appSecret = ko.observable(''); + this.facebook.loading = ko.observable(false); + this.facebook.userName = ko.observable(''); + this.facebook.supported = ko.observable(false); - this.facebook.loggined = ko.computed(function() { - return '' !== this.facebook.userName(); - }, this); + this.facebook.loggined = ko.computed(() => '' !== this.facebook.userName()); - // Twitter - this.twitter.enabled = ko.observable(false); - this.twitter.consumerKey = ko.observable(''); - this.twitter.consumerSecret = ko.observable(''); - this.twitter.loading = ko.observable(false); - this.twitter.userName = ko.observable(''); + // Twitter + this.twitter.enabled = ko.observable(false); + this.twitter.consumerKey = ko.observable(''); + this.twitter.consumerSecret = ko.observable(''); + this.twitter.loading = ko.observable(false); + this.twitter.userName = ko.observable(''); - this.twitter.loggined = ko.computed(function() { - return '' !== this.twitter.userName(); - }, this); + this.twitter.loggined = ko.computed(() => '' !== this.twitter.userName()); - // Dropbox - this.dropbox.enabled = ko.observable(false); - this.dropbox.apiKey = ko.observable(''); + // Dropbox + this.dropbox.enabled = ko.observable(false); + this.dropbox.apiKey = ko.observable(''); + } + + populate() { + this.google.enabled(!!Settings.settingsGet('AllowGoogleSocial')); + this.google.clientID(Settings.settingsGet('GoogleClientID')); + this.google.clientSecret(Settings.settingsGet('GoogleClientSecret')); + this.google.apiKey(Settings.settingsGet('GoogleApiKey')); + + this.google.capa.auth(!!Settings.settingsGet('AllowGoogleSocialAuth')); + this.google.capa.authFast(!!Settings.settingsGet('AllowGoogleSocialAuthFast')); + this.google.capa.drive(!!Settings.settingsGet('AllowGoogleSocialDrive')); + this.google.capa.preview(!!Settings.settingsGet('AllowGoogleSocialPreview')); + + this.facebook.enabled(!!Settings.settingsGet('AllowFacebookSocial')); + this.facebook.appID(Settings.settingsGet('FacebookAppID')); + this.facebook.appSecret(Settings.settingsGet('FacebookAppSecret')); + this.facebook.supported(!!Settings.settingsGet('SupportedFacebookSocial')); + + this.twitter.enabled = ko.observable(!!Settings.settingsGet('AllowTwitterSocial')); + this.twitter.consumerKey = ko.observable(Settings.settingsGet('TwitterConsumerKey')); + this.twitter.consumerSecret = ko.observable(Settings.settingsGet('TwitterConsumerSecret')); + + this.dropbox.enabled(!!Settings.settingsGet('AllowDropboxSocial')); + this.dropbox.apiKey(Settings.settingsGet('DropboxApiKey')); + } + + appendDropbox() { + if (!window.Dropbox && this.dropbox.enabled() && this.dropbox.apiKey()) + { + if (!window.document.getElementById('dropboxjs')) + { + const script = window.document.createElement('script'); + script.type = 'text/javascript'; + script.src = 'https://www.dropbox.com/static/api/2/dropins.js'; + $(script).attr('id', 'dropboxjs').attr('data-app-key', this.dropbox.apiKey()); + + window.document.body.appendChild(script); + } + } + } } -SocialStore.prototype.google = {}; -SocialStore.prototype.twitter = {}; -SocialStore.prototype.facebook = {}; -SocialStore.prototype.dropbox = {}; - -SocialStore.prototype.populate = function() -{ - var Settings = require('Storage/Settings'); - - this.google.enabled(!!Settings.settingsGet('AllowGoogleSocial')); - this.google.clientID(Settings.settingsGet('GoogleClientID')); - this.google.clientSecret(Settings.settingsGet('GoogleClientSecret')); - this.google.apiKey(Settings.settingsGet('GoogleApiKey')); - - this.google.capa.auth(!!Settings.settingsGet('AllowGoogleSocialAuth')); - this.google.capa.authFast(!!Settings.settingsGet('AllowGoogleSocialAuthFast')); - this.google.capa.drive(!!Settings.settingsGet('AllowGoogleSocialDrive')); - this.google.capa.preview(!!Settings.settingsGet('AllowGoogleSocialPreview')); - - this.facebook.enabled(!!Settings.settingsGet('AllowFacebookSocial')); - this.facebook.appID(Settings.settingsGet('FacebookAppID')); - this.facebook.appSecret(Settings.settingsGet('FacebookAppSecret')); - this.facebook.supported(!!Settings.settingsGet('SupportedFacebookSocial')); - - this.twitter.enabled = ko.observable(!!Settings.settingsGet('AllowTwitterSocial')); - this.twitter.consumerKey = ko.observable(Settings.settingsGet('TwitterConsumerKey')); - this.twitter.consumerSecret = ko.observable(Settings.settingsGet('TwitterConsumerSecret')); - - this.dropbox.enabled(!!Settings.settingsGet('AllowDropboxSocial')); - this.dropbox.apiKey(Settings.settingsGet('DropboxApiKey')); -}; - module.exports = new SocialStore(); diff --git a/dev/Stores/Theme.js b/dev/Stores/Theme.js index 50bff9aad..e704a94e4 100644 --- a/dev/Stores/Theme.js +++ b/dev/Stores/Theme.js @@ -1,32 +1,26 @@ -var - ko = require('ko'), +import ko from 'ko'; +import {isArray} from 'Common/Utils'; +import * as Settings from 'Storage/Settings'; - Utils = require('Common/Utils'), - - Settings = require('Storage/Settings'); - -/** - * @constructor - */ -function ThemeStore() +class ThemeStore { - this.themes = ko.observableArray([]); - this.themeBackgroundName = ko.observable(''); - this.themeBackgroundHash = ko.observable(''); + constructor() { + this.themes = ko.observableArray([]); + this.themeBackgroundName = ko.observable(''); + this.themeBackgroundHash = ko.observable(''); - this.theme = ko.observable('') - .extend({'limitedList': this.themes}); + this.theme = ko.observable('').extend({limitedList: this.themes}); + } + + populate() { + const themes = Settings.appSettingsGet('themes'); + + this.themes(isArray(themes) ? themes : []); + this.theme(Settings.settingsGet('Theme')); + this.themeBackgroundName(Settings.settingsGet('UserBackgroundName')); + this.themeBackgroundHash(Settings.settingsGet('UserBackgroundHash')); + } } -ThemeStore.prototype.populate = function() -{ - var aThemes = Settings.appSettingsGet('themes'); - - this.themes(Utils.isArray(aThemes) ? aThemes : []); - this.theme(Settings.settingsGet('Theme')); - this.themeBackgroundName(Settings.settingsGet('UserBackgroundName')); - this.themeBackgroundHash(Settings.settingsGet('UserBackgroundHash')); -}; - module.exports = new ThemeStore(); diff --git a/dev/Stores/User/Account.js b/dev/Stores/User/Account.js index 674c4a7b9..70200e580 100644 --- a/dev/Stores/User/Account.js +++ b/dev/Stores/User/Account.js @@ -1,64 +1,50 @@ -var - _ = require('_'), - ko = require('ko'), +import ko from 'ko'; +import _ from '_'; +import * as Settings from 'Storage/Settings'; - Settings = require('Storage/Settings'); - -/** - * @constructor - */ -function AccountUserStore() +class AccountUserStore { - this.email = ko.observable(''); - this.parentEmail = ko.observable(''); -// this.incLogin = ko.observable(''); -// this.outLogin = ko.observable(''); + constructor() { + this.email = ko.observable(''); + this.parentEmail = ko.observable(''); - this.signature = ko.observable(''); + this.signature = ko.observable(''); - this.accounts = ko.observableArray([]); - this.accounts.loading = ko.observable(false).extend({'throttle': 100}); + this.accounts = ko.observableArray([]); + this.accounts.loading = ko.observable(false).extend({throttle: 100}); - this.computers(); -} + this.computers(); + } -AccountUserStore.prototype.computers = function() -{ - this.accountsEmails = ko.computed(function() { - return _.compact(_.map(this.accounts(), function(oItem) { - return oItem ? oItem.email : null; - })); - }, this); + computers() { + this.accountsEmails = ko.computed( + () => _.compact(_.map(this.accounts(), (item) => (item ? item.email : null)))); - this.accountsUnreadCount = ko.computed(function() { - - var iResult = 0; - -// _.each(this.accounts(), function(oItem) { -// if (oItem) + this.accountsUnreadCount = ko.computed(() => 0); +// this.accountsUnreadCount = ko.computed(() => { +// let result = 0; +// _.each(this.accounts(), (item) => { +// if (item) // { -// iResult += oItem.count(); +// result += item.count(); // } // }); +// return result; +// }); + } - return iResult; + populate() { + this.email(Settings.settingsGet('Email')); + this.parentEmail(Settings.settingsGet('ParentEmail')); + } - }, this); -}; - -AccountUserStore.prototype.populate = function() -{ - this.email(Settings.settingsGet('Email')); - this.parentEmail(Settings.settingsGet('ParentEmail')); -}; - -/** - * @returns {boolean} - */ -AccountUserStore.prototype.isRootAccount = function() -{ - return '' === this.parentEmail(); -}; + /** + * @returns {boolean} + */ + isRootAccount() { + return '' === this.parentEmail(); + } +} module.exports = new AccountUserStore(); diff --git a/dev/Stores/User/App.js b/dev/Stores/User/App.js index e0e268b57..69fbeb69f 100644 --- a/dev/Stores/User/App.js +++ b/dev/Stores/User/App.js @@ -16,8 +16,7 @@ class AppUserStore extends AbstractAppStore this.focusedState = ko.observable(Focused.None); - this.focusedState.subscribe(function(value) { - + this.focusedState.subscribe((value) => { switch (value) { case Focused.MessageList: @@ -32,8 +31,7 @@ class AppUserStore extends AbstractAppStore default: break; } - - }, this); + }); this.projectHash = ko.observable(''); this.threadsAllowed = ko.observable(false); diff --git a/dev/Stores/User/Contact.js b/dev/Stores/User/Contact.js index 1cd191469..301c741a8 100644 --- a/dev/Stores/User/Contact.js +++ b/dev/Stores/User/Contact.js @@ -1,36 +1,32 @@ -var - ko = require('ko'), +import ko from 'ko'; +import * as Settings from 'Storage/Settings'; - Settings = require('Storage/Settings'); - -/** - * @constructor - */ -function ContactUserStore() +class ContactUserStore { - 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}); + constructor() { + 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(false); + this.enableContactsSync = ko.observable(false); + this.contactsSyncUrl = ko.observable(''); + this.contactsSyncUser = ko.observable(''); + this.contactsSyncPass = ko.observable(''); + } + + populate() { + this.allowContactsSync(!!Settings.settingsGet('ContactsSyncIsAllowed')); + this.enableContactsSync(!!Settings.settingsGet('EnableContactsSync')); + + this.contactsSyncUrl(Settings.settingsGet('ContactsSyncUrl')); + this.contactsSyncUser(Settings.settingsGet('ContactsSyncUser')); + this.contactsSyncPass(Settings.settingsGet('ContactsSyncPassword')); + } } -ContactUserStore.prototype.populate = function() -{ - this.allowContactsSync(!!Settings.settingsGet('ContactsSyncIsAllowed')); - this.enableContactsSync(!!Settings.settingsGet('EnableContactsSync')); - - this.contactsSyncUrl(Settings.settingsGet('ContactsSyncUrl')); - this.contactsSyncUser(Settings.settingsGet('ContactsSyncUser')); - this.contactsSyncPass(Settings.settingsGet('ContactsSyncPassword')); -}; - module.exports = new ContactUserStore(); diff --git a/dev/Stores/User/Filter.js b/dev/Stores/User/Filter.js index b7d59bd67..35dbce2c7 100644 --- a/dev/Stores/User/Filter.js +++ b/dev/Stores/User/Filter.js @@ -1,20 +1,19 @@ -var ko = require('ko'); +import ko from 'ko'; -/** - * @constructor - */ -function FilterUserStore() +class FilterUserStore { - this.capa = ko.observable(''); - this.modules = ko.observable({}); + constructor() { + this.capa = ko.observable(''); + this.modules = ko.observable({}); - this.filters = ko.observableArray([]); + this.filters = ko.observableArray([]); - this.filters.loading = ko.observable(false).extend({throttle: 200}); - this.filters.saving = ko.observable(false).extend({throttle: 200}); + this.filters.loading = ko.observable(false).extend({throttle: 200}); + this.filters.saving = ko.observable(false).extend({throttle: 200}); - this.raw = ko.observable(''); + this.raw = ko.observable(''); + } } module.exports = new FilterUserStore(); diff --git a/dev/Stores/User/Folder.js b/dev/Stores/User/Folder.js index ba39cc487..207d76f37 100644 --- a/dev/Stores/User/Folder.js +++ b/dev/Stores/User/Folder.js @@ -1,247 +1,223 @@ -var - _ = require('_'), - ko = require('ko'), +import ko from 'ko'; +import _ from '_'; - Enums = require('Common/Enums'), - Consts = require('Common/Consts'), - Utils = require('Common/Utils'), +import {FolderType} from 'Common/Enums'; +import {UNUSED_OPTION_VALUE} from 'Common/Consts'; +import {isArray, folderListOptionsBuilder} from 'Common/Utils'; +import {getFolderInboxName, getFolderFromCacheList} from 'Common/Cache'; - Cache = require('Common/Cache'); - -/** - * @constructor - */ -function FolderUserStore() +class FolderUserStore { - this.displaySpecSetting = ko.observable(true); + constructor() { + this.displaySpecSetting = ko.observable(true); - this.sentFolder = ko.observable(''); - this.draftFolder = ko.observable(''); - this.spamFolder = ko.observable(''); - this.trashFolder = ko.observable(''); - this.archiveFolder = ko.observable(''); + this.sentFolder = ko.observable(''); + this.draftFolder = ko.observable(''); + this.spamFolder = ko.observable(''); + this.trashFolder = ko.observable(''); + this.archiveFolder = ko.observable(''); - this.namespace = ''; + this.namespace = ''; - this.folderList = ko.observableArray([]); - this.folderList.optimized = ko.observable(false); - this.folderList.error = ko.observable(''); + this.folderList = ko.observableArray([]); + this.folderList.optimized = ko.observable(false); + this.folderList.error = ko.observable(''); - this.foldersLoading = ko.observable(false); - this.foldersCreating = ko.observable(false); - this.foldersDeleting = ko.observable(false); - this.foldersRenaming = ko.observable(false); + this.foldersLoading = ko.observable(false); + this.foldersCreating = ko.observable(false); + this.foldersDeleting = ko.observable(false); + this.foldersRenaming = ko.observable(false); - this.foldersInboxUnreadCount = ko.observable(0); + this.foldersInboxUnreadCount = ko.observable(0); - this.currentFolder = ko.observable(null).extend({toggleSubscribe: [ - null, - function(oPrev) { - if (oPrev) { - oPrev.selected(false); + this.currentFolder = ko.observable(null).extend({toggleSubscribe: [ + null, + (prev) => { + if (prev) { + prev.selected(false); + } + }, + (next) => { + if (next) { + next.selected(true); + } } - }, - function(oNext) { - if (oNext) { - oNext.selected(true); - } - } - ]}); + ]}); - this.computers(); - this.subscribers(); + this.computers(); + this.subscribers(); + } + + computers() { + + this.draftFolderNotEnabled = ko.computed( + () => ('' === this.draftFolder() || UNUSED_OPTION_VALUE === this.draftFolder()) + ); + + this.foldersListWithSingleInboxRootFolder = ko.computed( + () => !_.find(this.folderList(), (folder) => (folder && !folder.isSystemFolder() && folder.visible())) + ); + + this.currentFolderFullNameRaw = ko.computed( + () => (this.currentFolder() ? this.currentFolder().fullNameRaw : '') + ); + + this.currentFolderFullName = ko.computed(() => (this.currentFolder() ? this.currentFolder().fullName : '')); + this.currentFolderFullNameHash = ko.computed(() => (this.currentFolder() ? this.currentFolder().fullNameHash : '')); + + this.foldersChanging = ko.computed(() => { + const + loading = this.foldersLoading(), + creating = this.foldersCreating(), + deleting = this.foldersDeleting(), + renaming = this.foldersRenaming(); + + return loading || creating || deleting || renaming; + }); + + this.folderListSystemNames = ko.computed(() => { + + const + list = [getFolderInboxName()], + folders = this.folderList(), + sentFolder = this.sentFolder(), + draftFolder = this.draftFolder(), + spamFolder = this.spamFolder(), + trashFolder = this.trashFolder(), + archiveFolder = this.archiveFolder(); + + if (isArray(folders) && 0 < folders.length) + { + if ('' !== sentFolder && UNUSED_OPTION_VALUE !== sentFolder) + { + list.push(sentFolder); + } + if ('' !== draftFolder && UNUSED_OPTION_VALUE !== draftFolder) + { + list.push(draftFolder); + } + if ('' !== spamFolder && UNUSED_OPTION_VALUE !== spamFolder) + { + list.push(spamFolder); + } + if ('' !== trashFolder && UNUSED_OPTION_VALUE !== trashFolder) + { + list.push(trashFolder); + } + if ('' !== archiveFolder && UNUSED_OPTION_VALUE !== archiveFolder) + { + list.push(archiveFolder); + } + } + + return list; + }); + + this.folderListSystem = ko.computed( + () => _.compact(_.map(this.folderListSystemNames(), (name) => getFolderFromCacheList(name))) + ); + + this.folderMenuForMove = ko.computed( + () => folderListOptionsBuilder( + this.folderListSystem(), this.folderList(), + [this.currentFolderFullNameRaw()], null, null, null, null, (item) => (item ? item.localName() : '')) + ); + + this.folderMenuForFilters = ko.computed( + () => folderListOptionsBuilder( + this.folderListSystem(), this.folderList(), + ['INBOX'], [['', '']], null, null, null, (item) => (item ? item.localName() : '')) + ); + } + + subscribers() { + const + fRemoveSystemFolderType = (observable) => () => { + const folder = getFolderFromCacheList(observable()); + if (folder) + { + folder.type(FolderType.User); + } + }, + fSetSystemFolderType = (type) => (value) => { + const folder = getFolderFromCacheList(value); + if (folder) + { + folder.type(type); + } + }; + + 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(FolderType.SentItems), this); + this.draftFolder.subscribe(fSetSystemFolderType(FolderType.Draft), this); + this.spamFolder.subscribe(fSetSystemFolderType(FolderType.Spam), this); + this.trashFolder.subscribe(fSetSystemFolderType(FolderType.Trash), this); + this.archiveFolder.subscribe(fSetSystemFolderType(FolderType.Archive), this); + } + + /** + * @returns {Array} + */ + getNextFolderNames() { + + const + result = [], + limit = 5, + utc = require('Common/Momentor').momentNowUnix(), + timeout = utc - 60 * 5, + timeouts = [], + inboxFolderName = getFolderInboxName(), + fSearchFunction = (list) => { + _.each(list, (folder) => { + if (folder && inboxFolderName !== folder.fullNameRaw && + folder.selectable && folder.existen && timeout > folder.interval && + (folder.isSystemFolder() || (folder.subScribed() && folder.checkable())) + ) + { + timeouts.push([folder.interval, folder.fullNameRaw]); + } + + if (folder && 0 < folder.subFolders().length) + { + fSearchFunction(folder.subFolders()); + } + }); + }; + + fSearchFunction(this.folderList()); + + timeouts.sort((a, b) => { + if (a[0] < b[0]) + { + return -1; + } + else if (a[0] > b[0]) + { + return 1; + } + + return 0; + }); + + _.find(timeouts, (aItem) => { + const folder = getFolderFromCacheList(aItem[1]); + if (folder) + { + folder.interval = utc; + result.push(aItem[1]); + } + + return limit <= result.length; + }); + + return _.uniq(result); + } } -FolderUserStore.prototype.computers = function() -{ - this.draftFolderNotEnabled = ko.computed(function() { - return '' === this.draftFolder() || Consts.UNUSED_OPTION_VALUE === this.draftFolder(); - }, this); - - this.foldersListWithSingleInboxRootFolder = ko.computed(function() { - return !_.find(this.folderList(), function(oFolder) { - return oFolder && !oFolder.isSystemFolder() && oFolder.visible(); - }); - }, this); - - 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.foldersChanging = ko.computed(function() { - var - bLoading = this.foldersLoading(), - bCreating = this.foldersCreating(), - bDeleting = this.foldersDeleting(), - bRenaming = this.foldersRenaming(); - return bLoading || bCreating || bDeleting || bRenaming; - }, this); - - this.folderListSystemNames = ko.computed(function() { - - var - aList = [Cache.getFolderInboxName()], - 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.UNUSED_OPTION_VALUE !== sSentFolder) - { - aList.push(sSentFolder); - } - if ('' !== sDraftFolder && Consts.UNUSED_OPTION_VALUE !== sDraftFolder) - { - aList.push(sDraftFolder); - } - if ('' !== sSpamFolder && Consts.UNUSED_OPTION_VALUE !== sSpamFolder) - { - aList.push(sSpamFolder); - } - if ('' !== sTrashFolder && Consts.UNUSED_OPTION_VALUE !== sTrashFolder) - { - aList.push(sTrashFolder); - } - if ('' !== sArchiveFolder && Consts.UNUSED_OPTION_VALUE !== sArchiveFolder) - { - aList.push(sArchiveFolder); - } - } - - return aList; - - }, this); - - this.folderListSystem = ko.computed(function() { - return _.compact(_.map(this.folderListSystemNames(), function(sName) { - return Cache.getFolderFromCacheList(sName); - })); - }, this); - - this.folderMenuForMove = ko.computed(function() { - return Utils.folderListOptionsBuilder(this.folderListSystem(), this.folderList(), [ - this.currentFolderFullNameRaw() - ], null, null, null, null, function(oItem) { - return oItem ? oItem.localName() : ''; - }); - }, this); - - this.folderMenuForFilters = ko.computed(function() { - return Utils.folderListOptionsBuilder(this.folderListSystem(), this.folderList(), - ['INBOX'], [['', '']], null, null, null, function(oItem) { - return oItem ? oItem.localName() : ''; - } - ); - }, this); -}; - -FolderUserStore.prototype.subscribers = function() -{ - var - fRemoveSystemFolderType = function(observable) { - return function() { - var oFolder = Cache.getFolderFromCacheList(observable()); - if (oFolder) - { - oFolder.type(Enums.FolderType.User); - } - }; - }, - fSetSystemFolderType = function(iType) { - return function(sValue) { - var oFolder = Cache.getFolderFromCacheList(sValue); - if (oFolder) - { - oFolder.type(iType); - } - }; - }; - - 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); -}; - -/** - * @returns {Array} - */ -FolderUserStore.prototype.getNextFolderNames = function() -{ - var - aResult = [], - iLimit = 5, - iUtc = require('Common/Momentor').momentNowUnix(), - iTimeout = iUtc - 60 * 5, - aTimeouts = [], - sInboxFolderName = Cache.getFolderInboxName(), - fSearchFunction = function(aList) { - _.each(aList, function(oFolder) { - if (oFolder && sInboxFolderName !== oFolder.fullNameRaw && - oFolder.selectable && oFolder.existen && - iTimeout > oFolder.interval && - (oFolder.isSystemFolder() || (oFolder.subScribed() && oFolder.checkable())) - ) - { - 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]); - if (oFolder) - { - oFolder.interval = iUtc; - aResult.push(aItem[1]); - } - - return iLimit <= aResult.length; - }); - - aResult = _.uniq(aResult); - - return aResult; -}; - module.exports = new FolderUserStore(); diff --git a/dev/Stores/User/Identity.js b/dev/Stores/User/Identity.js index 9afae5936..0b1a8081c 100644 --- a/dev/Stores/User/Identity.js +++ b/dev/Stores/User/Identity.js @@ -8,7 +8,8 @@ class IdentityUserStore this.identities = ko.observableArray([]); this.identities.loading = ko.observable(false).extend({throttle: 100}); - this.identitiesIDS = ko.computed(() => _.compact(_.map(this.identities(), (item) => (item ? item.id : null)))); + this.identitiesIDS = ko.computed( + () => _.compact(_.map(this.identities(), (item) => (item ? item.id : null)))); } } diff --git a/dev/Stores/User/Message.js b/dev/Stores/User/Message.js index 77c14a92b..1e45c467f 100644 --- a/dev/Stores/User/Message.js +++ b/dev/Stores/User/Message.js @@ -1,907 +1,879 @@ -var - _ = require('_'), - ko = require('ko'), - window = require('window'), - $ = require('$'), +import window from 'window'; +import _ from '_'; +import ko from 'ko'; +import $ from '$'; - kn = require('Knoin/Knoin'), +import { + Magics, Layout, Focused, + MessageSetAction, + StorageResultType, + Notification +} from 'Common/Enums'; - Enums = require('Common/Enums'), - Consts = require('Common/Consts'), - Globals = require('Common/Globals'), - Utils = require('Common/Utils'), - Links = require('Common/Links'), - Translator = require('Common/Translator'), +import { + trim, isNormal, isArray, inArray, + pInt, pString, plainToHtml, + windowResize, findEmailAndLinks +} from 'Common/Utils'; - Cache = require('Common/Cache'), +import { + getFolderInboxName, + addNewMessageCache, + setFolderUidNext, + getFolderFromCacheList, + setFolderHash, + initMessageFlagsFromCache, + addRequestedMessage, + clearMessageFlagsFromCacheByFolder, + hasNewMessageAndRemoveFromCache, + storeMessageFlagsToCache, + clearNewMessageCache +} from 'Common/Cache'; - AppStore = require('Stores/User/App'), - FolderStore = require('Stores/User/Folder'), - PgpStore = require('Stores/User/Pgp'), - SettingsStore = require('Stores/User/Settings'), +import {MESSAGE_BODY_CACHE_LIMIT} from 'Common/Consts'; +import {data as GlobalsData, $div} from 'Common/Globals'; +import {mailBox, notificationMailIcon} from 'Common/Links'; +import {i18n, getNotification} from 'Common/Translator'; - Remote = require('Remote/User/Ajax'), +import * as MessageHelper from 'Helper/Message'; +import {MessageModel} from 'Model/Message'; - MessageModel = require('Model/Message').default, - MessageHelper = require('Helper/Message'); +import {setHash} from 'Knoin/Knoin'; -/** - * @constructor - */ -function MessageUserStore() +import AppStore from 'Stores/User/App'; +import FolderStore from 'Stores/User/Folder'; +import PgpStore from 'Stores/User/Pgp'; +import SettingsStore from 'Stores/User/Settings'; + +import {getApp} from 'Helper/Apps/User'; + +import Remote from 'Remote/User/Ajax'; + +class MessageUserStore { - this.staticMessage = new MessageModel(); - - this.messageList = ko.observableArray([]).extend({'rateLimit': 0}); - - this.messageListCount = ko.observable(0); - this.messageListSearch = ko.observable(''); - this.messageListThreadUid = ko.observable(''); - this.messageListPage = ko.observable(1); - this.messageListPageBeforeThread = ko.observable(1); - this.messageListError = ko.observable(''); - - this.messageListEndFolder = ko.observable(''); - this.messageListEndSearch = ko.observable(''); - this.messageListEndThreadUid = ko.observable(''); - this.messageListEndPage = ko.observable(1); - - this.messageListLoading = ko.observable(false); - this.messageListIsNotCompleted = ko.observable(false); - this.messageListCompleteLoadingThrottle = ko.observable(false).extend({'throttle': 200}); - this.messageListCompleteLoadingThrottleForAnimation = ko.observable(false).extend({'specialThrottle': 700}); - - this.messageListDisableAutoSelect = ko.observable(false).extend({'falseTimeout': 500}); - - this.selectorMessageSelected = ko.observable(null); - this.selectorMessageFocused = ko.observable(null); - - // message viewer - this.message = ko.observable(null); - - this.message.viewTrigger = ko.observable(false); - - this.messageError = ko.observable(''); - - this.messageCurrentLoading = ko.observable(false); - - this.messageLoading = ko.computed(function() { - return this.messageCurrentLoading(); - }, this); - - this.messageLoadingThrottle = ko.observable(false).extend({'throttle': Enums.Magics.Time50ms}); - - this.messageFullScreenMode = ko.observable(false); - - this.messagesBodiesDom = ko.observable(null); - this.messageActiveDom = ko.observable(null); - - this.computers(); - this.subscribers(); - - this.onMessageResponse = _.bind(this.onMessageResponse, this); - - this.purgeMessageBodyCacheThrottle = _.throttle(this.purgeMessageBodyCache, Enums.Magics.Time30s); -} - -MessageUserStore.prototype.computers = function() -{ - var self = this; - - this.messageListEndHash = ko.computed(function() { - return this.messageListEndFolder() + '|' + this.messageListEndSearch() + - '|' + this.messageListEndThreadUid() + - '|' + this.messageListEndPage(); - }, this); - - this.messageListPageCount = ko.computed(function() { - var iPage = window.Math.ceil(this.messageListCount() / - SettingsStore.messagesPerPage()); - return 0 >= iPage ? 1 : iPage; - }, this); - - this.mainMessageListSearch = ko.computed({ - 'read': this.messageListSearch, - 'write': function(sValue) { - kn.setHash(Links.mailBox( - FolderStore.currentFolderFullNameHash(), 1, - Utils.trim(sValue.toString()), self.messageListThreadUid() - )); - }, - 'owner': this - }); - - this.messageListCompleteLoading = ko.computed(function() { - var - bOne = this.messageListLoading(), - bTwo = this.messageListIsNotCompleted(); - return bOne || bTwo; - }, this); - - this.isMessageSelected = ko.computed(function() { - return null !== this.message(); - }, this); - - 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.selectorMessageSelected(); - - 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 (1 < oMessage.threadsLen()) - { - aList = _.union(aList, oMessage.threads()); - } - } - }); - return aList; - }, this); -}; - -MessageUserStore.prototype.subscribers = function() -{ - this.messageListCompleteLoading.subscribe(function(bValue) { - bValue = !!bValue; - this.messageListCompleteLoadingThrottle(bValue); - this.messageListCompleteLoadingThrottleForAnimation(bValue); - }, this); - - this.messageList.subscribe(_.debounce(function(aList) { - _.each(aList, function(oItem) { - if (oItem && oItem.newForAnimation()) - { - oItem.newForAnimation(false); - } - }); - }, Enums.Magics.Time500ms)); - - this.message.subscribe(function(oMessage) { - - if (oMessage) - { - if (Enums.Layout.NoPreview === SettingsStore.layout()) - { - AppStore.focusedState(Enums.Focused.MessageView); - } - } - else - { - AppStore.focusedState(Enums.Focused.MessageList); - - this.messageFullScreenMode(false); - this.hideMessageBodies(); - } - - }, this); - - this.messageLoading.subscribe(function(bValue) { - this.messageLoadingThrottle(bValue); - }, this); - - this.messagesBodiesDom.subscribe(function(oDom) { - if (oDom && !(oDom instanceof $)) - { - this.messagesBodiesDom($(oDom)); - } - }, this); - - this.messageListEndFolder.subscribe(function(sFolder) { - var oMessage = this.message(); - if (oMessage && sFolder && sFolder !== oMessage.folderFullNameRaw) - { - this.message(null); - } - }, this); -}; - -MessageUserStore.prototype.purgeMessageBodyCache = function() -{ - var - iCount = 0, - oMessagesDom = null, - iEnd = Globals.data.iMessageBodyCacheCount - Consts.MESSAGE_BODY_CACHE_LIMIT; - - if (0 < iEnd) + constructor() { - oMessagesDom = this.messagesBodiesDom(); - if (oMessagesDom) - { - oMessagesDom.find('.rl-cache-class').each(function() { - var oItem = $(this); - if (iEnd > oItem.data('rl-cache-count')) - { - oItem.addClass('rl-cache-purge'); - iCount += 1; - } - }); + this.staticMessage = new MessageModel(); - if (0 < iCount) - { - _.delay(function() { - oMessagesDom.find('.rl-cache-purge').remove(); - }, Enums.Magics.Time350ms); - } - } + this.messageList = ko.observableArray([]).extend({rateLimit: 0}); + + this.messageListCount = ko.observable(0); + this.messageListSearch = ko.observable(''); + this.messageListThreadUid = ko.observable(''); + this.messageListPage = ko.observable(1); + this.messageListPageBeforeThread = ko.observable(1); + this.messageListError = ko.observable(''); + + this.messageListEndFolder = ko.observable(''); + this.messageListEndSearch = ko.observable(''); + this.messageListEndThreadUid = ko.observable(''); + this.messageListEndPage = ko.observable(1); + + this.messageListLoading = ko.observable(false); + this.messageListIsNotCompleted = ko.observable(false); + this.messageListCompleteLoadingThrottle = ko.observable(false).extend({throttle: 200}); + this.messageListCompleteLoadingThrottleForAnimation = ko.observable(false).extend({specialThrottle: 700}); + + this.messageListDisableAutoSelect = ko.observable(false).extend({falseTimeout: 500}); + + this.selectorMessageSelected = ko.observable(null); + this.selectorMessageFocused = ko.observable(null); + + // message viewer + this.message = ko.observable(null); + + this.message.viewTrigger = ko.observable(false); + + this.messageError = ko.observable(''); + + this.messageCurrentLoading = ko.observable(false); + + this.messageLoadingThrottle = ko.observable(false).extend({throttle: Magics.Time50ms}); + + this.messageFullScreenMode = ko.observable(false); + + this.messagesBodiesDom = ko.observable(null); + this.messageActiveDom = ko.observable(null); + + this.computers(); + this.subscribers(); + + this.onMessageResponse = _.bind(this.onMessageResponse, this); + + this.purgeMessageBodyCacheThrottle = _.throttle(this.purgeMessageBodyCache, Magics.Time30s); } -}; -MessageUserStore.prototype.initUidNextAndNewMessages = function(sFolder, sUidNext, aNewMessages) -{ - if (Cache.getFolderInboxName() === sFolder && Utils.isNormal(sUidNext) && '' !== sUidNext) - { - if (Utils.isArray(aNewMessages) && 0 < aNewMessages.length) - { - var - iIndex = 0, - iLen = aNewMessages.length, - NotificationStore = require('Stores/User/Notification'); + computers() { - _.each(aNewMessages, function(oItem) { - Cache.addNewMessageCache(sFolder, oItem.Uid); - }); + this.messageLoading = ko.computed(() => this.messageCurrentLoading()); - NotificationStore.playSoundNotification(); + this.messageListEndHash = ko.computed( + () => this.messageListEndFolder() + '|' + this.messageListEndSearch() + + '|' + this.messageListEndThreadUid() + '|' + this.messageListEndPage() + ); - if (3 < iLen) - { - NotificationStore.displayDesktopNotification( - Links.notificationMailIcon(), - require('Stores/User/Account').email(), - Translator.i18n('MESSAGE_LIST/NEW_MESSAGE_NOTIFICATION', { - 'COUNT': iLen - }), - {'Folder': '', 'Uid': ''} + this.messageListPageCount = ko.computed(() => { + const page = window.Math.ceil(this.messageListCount() / SettingsStore.messagesPerPage()); + return 0 >= page ? 1 : page; + }); + + this.mainMessageListSearch = ko.computed({ + read: this.messageListSearch, + write: (value) => { + setHash( + mailBox(FolderStore.currentFolderFullNameHash(), 1, trim(value.toString()), this.messageListThreadUid()) ); } + }); + + this.messageListCompleteLoading = ko.computed(() => { + const + one = this.messageListLoading(), + two = this.messageListIsNotCompleted(); + return one || two; + }); + + this.isMessageSelected = ko.computed(() => null !== this.message()); + + this.messageListChecked = ko.computed( + () => _.filter(this.messageList(), (item) => item.checked()) + ).extend({rateLimit: 0}); + + this.hasCheckedMessages = ko.computed(() => 0 < this.messageListChecked().length).extend({rateLimit: 0}); + + this.messageListCheckedOrSelected = ko.computed(() => { + const + checked = this.messageListChecked(), + selectedMessage = this.selectorMessageSelected(); + return _.union(checked, selectedMessage ? [selectedMessage] : []); + }); + + this.messageListCheckedOrSelectedUidsWithSubMails = ko.computed(() => { + let result = []; + _.each(this.messageListCheckedOrSelected(), (message) => { + if (message) + { + result.push(message.uid); + if (1 < message.threadsLen()) + { + result = _.union(result, message.threads()); + } + } + }); + return result; + }); + } + + subscribers() { + + this.messageListCompleteLoading.subscribe((value) => { + value = !!value; + this.messageListCompleteLoadingThrottle(value); + this.messageListCompleteLoadingThrottleForAnimation(value); + }); + + this.messageList.subscribe(_.debounce((list) => { + _.each(list, (item) => { + if (item && item.newForAnimation()) + { + item.newForAnimation(false); + } + }); + }, Magics.Time500ms)); + + this.message.subscribe((message) => { + + if (message) + { + if (Layout.NoPreview === SettingsStore.layout()) + { + AppStore.focusedState(Focused.MessageView); + } + } else { - for (; iIndex < iLen; iIndex++) + AppStore.focusedState(Focused.MessageList); + + this.messageFullScreenMode(false); + this.hideMessageBodies(); + } + + }); + + this.messageLoading.subscribe((value) => { + this.messageLoadingThrottle(value); + }); + + this.messagesBodiesDom.subscribe((dom) => { + if (dom && !(dom instanceof $)) + { + this.messagesBodiesDom($(dom)); + } + }); + + this.messageListEndFolder.subscribe((folder) => { + const message = this.message(); + if (message && folder && folder !== message.folderFullNameRaw) + { + this.message(null); + } + }); + } + + purgeMessageBodyCache() { + + let count = 0; + const end = GlobalsData.iMessageBodyCacheCount - MESSAGE_BODY_CACHE_LIMIT; + + if (0 < end) + { + const messagesDom = this.messagesBodiesDom(); + if (messagesDom) + { + messagesDom.find('.rl-cache-class').each(function() { + const item = $(this); // eslint-disable-line no-invalid-this + if (end > item.data('rl-cache-count')) + { + item.addClass('rl-cache-purge'); + count += 1; + } + }); + + if (0 < count) + { + _.delay(() => messagesDom.find('.rl-cache-purge').remove(), Magics.Time350ms); + } + } + } + } + + initUidNextAndNewMessages(folder, uidNext, newMessages) { + if (getFolderInboxName() === folder && isNormal(uidNext) && '' !== uidNext) + { + if (isArray(newMessages) && 0 < newMessages.length) + { + const + len = newMessages.length, + NotificationStore = require('Stores/User/Notification'); + + _.each(newMessages, (item) => { + addNewMessageCache(folder, item.Uid); + }); + + NotificationStore.playSoundNotification(); + + if (3 < len) { NotificationStore.displayDesktopNotification( - Links.notificationMailIcon(), - MessageHelper.emailArrayToString(MessageHelper.emailArrayFromJson(aNewMessages[iIndex].From), false), - aNewMessages[iIndex].Subject, - {'Folder': aNewMessages[iIndex].Folder, 'Uid': aNewMessages[iIndex].Uid} + notificationMailIcon(), + require('Stores/User/Account').email(), + i18n('MESSAGE_LIST/NEW_MESSAGE_NOTIFICATION', { + 'COUNT': len + }), + {'Folder': '', 'Uid': ''} ); } - } - } - - Cache.setFolderUidNext(sFolder, sUidNext); - } -}; - -MessageUserStore.prototype.hideMessageBodies = function() -{ - var oMessagesDom = this.messagesBodiesDom(); - if (oMessagesDom) - { - oMessagesDom.find('.b-text-part').hide(); - } -}; - -/** - * @param {string} sFromFolderFullNameRaw - * @param {Array} aUidForRemove - * @param {string=} sToFolderFullNameRaw = '' - * @param {bCopy=} bCopy = false - */ -MessageUserStore.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 - self = this, - iUnseenCount = 0, - sTrashFolder = FolderStore.trashFolder(), - sSpamFolder = FolderStore.spamFolder(), - aMessageList = this.messageList(), - oFromFolder = Cache.getFolderFromCacheList(sFromFolderFullNameRaw), - oToFolder = '' === sToFolderFullNameRaw ? null : Cache.getFolderFromCacheList(sToFolderFullNameRaw || ''), - sCurrentFolderFullNameRaw = FolderStore.currentFolderFullNameRaw(), - oCurrentMessage = this.message(), - aMessages = sCurrentFolderFullNameRaw === sFromFolderFullNameRaw ? _.filter(aMessageList, function(item) { - return item && -1 < Utils.inArray(Utils.pInt(item.uid), aUidForRemove); - }) : []; - - _.each(aMessages, function(item) { - if (item && item.unseen()) - { - iUnseenCount += 1; - } - }); - - 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) - { - if (sTrashFolder === oToFolder.fullNameRaw || sSpamFolder === oToFolder.fullNameRaw) - { - iUnseenCount = 0; - } - - 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(item) { - item.checked(false); - }); - } - else - { - this.messageListIsNotCompleted(true); - - _.each(aMessages, function(item) { - if (oCurrentMessage && oCurrentMessage.hash === item.hash) + else { - oCurrentMessage = null; - self.message(null); + _.each(newMessages, (item) => { + NotificationStore.displayDesktopNotification( + notificationMailIcon(), + MessageHelper.emailArrayToString(MessageHelper.emailArrayFromJson(item.From), false), + item.Subject, + {'Folder': item.Folder, 'Uid': item.Uid} + ); + }); } + } - item.deleted(true); - }); - - _.delay(function() { - _.each(aMessages, function(item) { - self.messageList.remove(item); - }); - }, Enums.Magics.Time350ms); + setFolderUidNext(folder, uidNext); } } - if ('' !== sFromFolderFullNameRaw) - { - Cache.setFolderHash(sFromFolderFullNameRaw, ''); - } - - if ('' !== sToFolderFullNameRaw) - { - Cache.setFolderHash(sToFolderFullNameRaw, ''); - } - - if ('' !== this.messageListThreadUid()) - { - aMessageList = this.messageList(); - - if (aMessageList && 0 < aMessageList.length && !!_.find(aMessageList, function(item) { - return !!(item && item.deleted() && item.uid === self.messageListThreadUid()); - })) + hideMessageBodies() { + const messagesDom = this.messagesBodiesDom(); + if (messagesDom) { - var oMessage = _.find(aMessageList, function(item) { - return item && !item.deleted(); - }); + messagesDom.find('.b-text-part').hide(); + } + } - if (oMessage && this.messageListThreadUid() !== Utils.pString(oMessage.uid)) + /** + * @param {string} fromFolderFullNameRaw + * @param {Array} uidForRemove + * @param {string=} toFolderFullNameRaw = '' + * @param {boolean=} bCocopypy = false + */ + removeMessagesFromList(fromFolderFullNameRaw, uidForRemove, toFolderFullNameRaw = '', copy = false) { + + uidForRemove = _.map(uidForRemove, (mValue) => pInt(mValue)); + + let + unseenCount = 0, + messageList = this.messageList(), + currentMessage = this.message(); + + const + trashFolder = FolderStore.trashFolder(), + spamFolder = FolderStore.spamFolder(), + fromFolder = getFolderFromCacheList(fromFolderFullNameRaw), + toFolder = '' === toFolderFullNameRaw ? null : getFolderFromCacheList(toFolderFullNameRaw || ''), + currentFolderFullNameRaw = FolderStore.currentFolderFullNameRaw(), + messages = currentFolderFullNameRaw === fromFolderFullNameRaw ? + _.filter(messageList, (item) => (item && -1 < inArray(pInt(item.uid), uidForRemove))) : []; + + _.each(messages, (item) => { + if (item && item.unseen()) { - this.messageListThreadUid(Utils.pString(oMessage.uid)); - - kn.setHash(Links.mailBox( - FolderStore.currentFolderFullNameHash(), - this.messageListPage(), - this.messageListSearch(), - this.messageListThreadUid() - ), true, true); + unseenCount += 1; } - else if (!oMessage) - { - if (1 < this.messageListPage()) - { - this.messageListPage(this.messageListPage() - 1); + }); - kn.setHash(Links.mailBox( + if (fromFolder && !copy) + { + fromFolder.messageCountAll(0 <= fromFolder.messageCountAll() - uidForRemove.length ? + fromFolder.messageCountAll() - uidForRemove.length : 0); + + if (0 < unseenCount) + { + fromFolder.messageCountUnread(0 <= fromFolder.messageCountUnread() - unseenCount ? + fromFolder.messageCountUnread() - unseenCount : 0); + } + } + + if (toFolder) + { + if (trashFolder === toFolder.fullNameRaw || spamFolder === toFolder.fullNameRaw) + { + unseenCount = 0; + } + + toFolder.messageCountAll(toFolder.messageCountAll() + uidForRemove.length); + if (0 < unseenCount) + { + toFolder.messageCountUnread(toFolder.messageCountUnread() + unseenCount); + } + + toFolder.actionBlink(true); + } + + if (0 < messages.length) + { + if (copy) + { + _.each(messages, (item) => { + item.checked(false); + }); + } + else + { + this.messageListIsNotCompleted(true); + + _.each(messages, (item) => { + if (currentMessage && currentMessage.hash === item.hash) + { + currentMessage = null; + this.message(null); + } + + item.deleted(true); + }); + + _.delay(() => { + _.each(messages, (item) => { + this.messageList.remove(item); + }); + }, Magics.Time350ms); + } + } + + if ('' !== fromFolderFullNameRaw) + { + setFolderHash(fromFolderFullNameRaw, ''); + } + + if ('' !== toFolderFullNameRaw) + { + setFolderHash(toFolderFullNameRaw, ''); + } + + if ('' !== this.messageListThreadUid()) + { + messageList = this.messageList(); + + if (messageList && 0 < messageList.length && + !!_.find(messageList, (item) => !!(item && item.deleted() && item.uid === this.messageListThreadUid()))) + { + const message = _.find(messageList, (item) => item && !item.deleted()); + if (message && this.messageListThreadUid() !== pString(message.uid)) + { + this.messageListThreadUid(pString(message.uid)); + + setHash(mailBox( FolderStore.currentFolderFullNameHash(), this.messageListPage(), this.messageListSearch(), this.messageListThreadUid() ), true, true); } - else + else if (!message) { - this.messageListThreadUid(''); + if (1 < this.messageListPage()) + { + this.messageListPage(this.messageListPage() - 1); - kn.setHash(Links.mailBox( - FolderStore.currentFolderFullNameHash(), - this.messageListPageBeforeThread(), - this.messageListSearch() - ), true, true); + setHash(mailBox( + FolderStore.currentFolderFullNameHash(), + this.messageListPage(), + this.messageListSearch(), + this.messageListThreadUid() + ), true, true); + } + else + { + this.messageListThreadUid(''); + + setHash(mailBox( + FolderStore.currentFolderFullNameHash(), + this.messageListPageBeforeThread(), + this.messageListSearch() + ), true, true); + } } } } } -}; -MessageUserStore.prototype.addBlockquoteSwitcherCallback = function() -{ - var $self = $(this); - if ('' !== Utils.trim(($self.text()))) - { - $self.addClass('rl-bq-switcher hidden-bq'); - $('') - .insertBefore($self) - .on('click.rlBlockquoteSwitcher', function() { - $self.toggleClass('hidden-bq'); - Utils.windowResize(); - }) - .after('
') - .before('
'); - } -}; - -/** - * @param {Object} oMessageTextBody - */ -MessageUserStore.prototype.initBlockquoteSwitcher = function(oMessageTextBody) -{ - if (oMessageTextBody) - { - var $oList = $('blockquote:not(.rl-bq-switcher)', oMessageTextBody).filter(function() { - return 0 === $(this).parent().closest('blockquote', oMessageTextBody).length; - }); - - if ($oList && 0 < $oList.length) + /** + * @param {Object} messageTextBody + */ + initBlockquoteSwitcher(messageTextBody) { + if (messageTextBody) { - $oList.each(this.addBlockquoteSwitcherCallback); - } - } -}; + const $oList = $('blockquote:not(.rl-bq-switcher)', messageTextBody).filter(function() { + return 0 === $(this).parent().closest('blockquote', messageTextBody).length; // eslint-disable-line no-invalid-this + }); -/** - * @param {Object} oMessageTextBody - */ -MessageUserStore.prototype.initOpenPgpControls = function(oMessageTextBody, oMessage) -{ - if (oMessageTextBody && oMessageTextBody.find) - { - oMessageTextBody.find('.b-plain-openpgp:not(.inited)').each(function() { - PgpStore.initMessageBodyControls($(this), oMessage); - }); - } -}; - -MessageUserStore.prototype.setMessage = function(oData, bCached) -{ - var - bNew = false, - oBody = null, - sId = '', - sPlain = '', - sResultHtml = '', - bPgpSigned = false, - oMessagesDom = this.messagesBodiesDom(), - oSelectedMessage = this.selectorMessageSelected(), - oMessage = this.message(); - - if (oData && oMessage && oData.Result && 'Object/Message' === oData.Result['@Object'] && - oMessage.folderFullNameRaw === oData.Result.Folder) - { - var aThreads = oMessage.threads(); - if (oMessage.uid !== oData.Result.Uid && 1 < aThreads.length && - -1 < Utils.inArray(oData.Result.Uid, aThreads)) - { - oMessage = MessageModel.newInstanceFromJson(oData.Result); - if (oMessage) + if ($oList && 0 < $oList.length) { - oMessage.threads(aThreads); - Cache.initMessageFlagsFromCache(oMessage); - - this.message(this.staticMessage.populateByMessageListItem(oMessage)); - oMessage = this.message(); - - bNew = true; - } - } - - if (oMessage && oMessage.uid === oData.Result.Uid) - { - this.messageError(''); - - oMessage.initUpdateByMessageJson(oData.Result); - Cache.addRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid); - - if (!bCached) - { - oMessage.initFlagsByJson(oData.Result); - } - - oMessagesDom = oMessagesDom && oMessagesDom[0] ? oMessagesDom : null; - if (oMessagesDom) - { - sId = 'rl-mgs-' + oMessage.hash.replace(/[^a-zA-Z0-9]/g, ''); - - var oTextBody = oMessagesDom.find('#' + sId); - if (!oTextBody || !oTextBody[0]) - { - var bIsHtml = false; - if (Utils.isNormal(oData.Result.Html) && '' !== oData.Result.Html) + $oList.each(function() { + const $this = $(this); // eslint-disable-line no-invalid-this + if ('' !== trim($this.text())) { - bIsHtml = true; - sResultHtml = oData.Result.Html.toString(); + $this.addClass('rl-bq-switcher hidden-bq'); + $('') + .insertBefore($this) + .on('click.rlBlockquoteSwitcher', () => { + $this.toggleClass('hidden-bq'); + windowResize(); + }) + .after('
') + .before('
'); } - else if (Utils.isNormal(oData.Result.Plain) && '' !== oData.Result.Plain) + }); + } + } + } + + /** + * @param {Object} oMessageTextBody + */ + initOpenPgpControls(oMessageTextBody, oMessage) { + if (oMessageTextBody && oMessageTextBody.find) + { + oMessageTextBody.find('.b-plain-openpgp:not(.inited)').each(function() { + PgpStore.initMessageBodyControls($(this), oMessage); // eslint-disable-line no-invalid-this + }); + } + } + + setMessage(data, cached) { + + let + isNew = false, + body = null, + id = '', + plain = '', + resultHtml = '', + pgpSigned = false, + messagesDom = this.messagesBodiesDom(), + selectedMessage = this.selectorMessageSelected(), + message = this.message(); + + if (data && message && data.Result && 'Object/Message' === data.Result['@Object'] && + message.folderFullNameRaw === data.Result.Folder) + { + const threads = message.threads(); + if (message.uid !== data.Result.Uid && 1 < threads.length && -1 < inArray(data.Result.Uid, threads)) + { + message = MessageModel.newInstanceFromJson(data.Result); + if (message) + { + message.threads(threads); + initMessageFlagsFromCache(message); + + this.message(this.staticMessage.populateByMessageListItem(message)); + message = this.message(); + + isNew = true; + } + } + + if (message && message.uid === data.Result.Uid) + { + this.messageError(''); + + message.initUpdateByMessageJson(data.Result); + addRequestedMessage(message.folderFullNameRaw, message.uid); + + if (!cached) + { + message.initFlagsByJson(data.Result); + } + + messagesDom = messagesDom && messagesDom[0] ? messagesDom : null; + if (messagesDom) + { + id = 'rl-mgs-' + message.hash.replace(/[^a-zA-Z0-9]/g, ''); + + const textBody = messagesDom.find('#' + id); + if (!textBody || !textBody[0]) { - bIsHtml = false; - sResultHtml = Utils.plainToHtml(oData.Result.Plain.toString(), false); - - if ((oMessage.isPgpSigned() || oMessage.isPgpEncrypted()) && require('Stores/User/Pgp').capaOpenPGP()) + let isHtml = false; + if (isNormal(data.Result.Html) && '' !== data.Result.Html) { - sPlain = Utils.pString(oData.Result.Plain); + isHtml = true; + resultHtml = data.Result.Html.toString(); + } + else if (isNormal(data.Result.Plain) && '' !== data.Result.Plain) + { + isHtml = false; + resultHtml = plainToHtml(data.Result.Plain.toString(), false); - var bPgpEncrypted = (/---BEGIN PGP MESSAGE---/).test(sPlain); - if (!bPgpEncrypted) + if ((message.isPgpSigned() || message.isPgpEncrypted()) && require('Stores/User/Pgp').capaOpenPGP()) { - bPgpSigned = (/-----BEGIN PGP SIGNED MESSAGE-----/).test(sPlain) && - (/-----BEGIN PGP SIGNATURE-----/).test(sPlain); - } + plain = pString(data.Result.Plain); - Globals.$div.empty(); - if (bPgpSigned && oMessage.isPgpSigned()) - { - sResultHtml = - Globals.$div.append( - $('
').text(sPlain)
+								const isPgpEncrypted = (/---BEGIN PGP MESSAGE---/).test(plain);
+								if (!isPgpEncrypted)
+								{
+									pgpSigned = (/-----BEGIN PGP SIGNED MESSAGE-----/).test(plain) &&
+										(/-----BEGIN PGP SIGNATURE-----/).test(plain);
+								}
+
+								$div.empty();
+								if (pgpSigned && message.isPgpSigned())
+								{
+									resultHtml = $div.append(
+										$('
').text(plain)
 									).html();
-							}
-							else if (bPgpEncrypted && oMessage.isPgpEncrypted())
-							{
-								sResultHtml =
-									Globals.$div.append(
-										$('
').text(sPlain)
+								}
+								else if (isPgpEncrypted && message.isPgpEncrypted())
+								{
+									resultHtml = $div.append(
+										$('
').text(plain)
 									).html();
+								}
+								else
+								{
+									resultHtml = '
' + resultHtml + '
'; + } + + $div.empty(); + + message.isPgpSigned(pgpSigned); + message.isPgpEncrypted(isPgpEncrypted); } else { - sResultHtml = '
' + sResultHtml + '
'; + resultHtml = '
' + resultHtml + '
'; } - - Globals.$div.empty(); - - oMessage.isPgpSigned(bPgpSigned); - oMessage.isPgpEncrypted(bPgpEncrypted); } else { - sResultHtml = '
' + sResultHtml + '
'; + isHtml = false; + resultHtml = '
' + resultHtml + '
'; + } + + GlobalsData.iMessageBodyCacheCount += 1; + + body = $('
').hide().addClass('rl-cache-class'); + body.data('rl-cache-count', GlobalsData.iMessageBodyCacheCount); + + body + .html(findEmailAndLinks(resultHtml)) + .addClass('b-text-part ' + (isHtml ? 'html' : 'plain')); + + message.isHtml(!!isHtml); + message.hasImages(!!data.Result.HasExternals); + + message.body = body; + if (message.body) + { + messagesDom.append(message.body); + } + + message.storeDataInDom(); + + if (data.Result.HasInternals) + { + message.showInternalImages(true); + } + + if (message.hasImages() && SettingsStore.showImages()) + { + message.showExternalImages(true); + } + + this.purgeMessageBodyCacheThrottle(); + } + else + { + message.body = textBody; + if (message.body) + { + GlobalsData.iMessageBodyCacheCount += 1; + message.body.data('rl-cache-count', GlobalsData.iMessageBodyCacheCount); + message.fetchDataFromDom(); } } - else + + this.messageActiveDom(message.body); + + this.hideMessageBodies(); + + if (body) { - bIsHtml = false; - sResultHtml = '
' + sResultHtml + '
'; + this.initOpenPgpControls(body, message); + + this.initBlockquoteSwitcher(body); } - Globals.data.iMessageBodyCacheCount += 1; - - oBody = $('
').hide().addClass('rl-cache-class'); - oBody.data('rl-cache-count', Globals.data.iMessageBodyCacheCount); - - oBody - .html(Utils.findEmailAndLinks(sResultHtml)) - .addClass('b-text-part ' + (bIsHtml ? 'html' : 'plain')); - - oMessage.isHtml(!!bIsHtml); - oMessage.hasImages(!!oData.Result.HasExternals); - - oMessage.body = oBody; - if (oMessage.body) - { - oMessagesDom.append(oMessage.body); - } - - oMessage.storeDataInDom(); - - if (oData.Result.HasInternals) - { - oMessage.showInternalImages(true); - } - - if (oMessage.hasImages() && SettingsStore.showImages()) - { - oMessage.showExternalImages(true); - } - - this.purgeMessageBodyCacheThrottle(); + message.body.show(); } - else + + initMessageFlagsFromCache(message); + if (message.unseen() || message.hasUnseenSubMessage()) { - oMessage.body = oTextBody; - if (oMessage.body) - { - Globals.data.iMessageBodyCacheCount += 1; - oMessage.body.data('rl-cache-count', Globals.data.iMessageBodyCacheCount); - oMessage.fetchDataFromDom(); - } + getApp().messageListAction( + message.folderFullNameRaw, message.uid, MessageSetAction.SetSeen, [message]); } - this.messageActiveDom(oMessage.body); - - this.hideMessageBodies(); - - if (oBody) + if (isNew) { - this.initOpenPgpControls(oBody, oMessage); + message = this.message(); + + if (selectedMessage && message && ( + message.folderFullNameRaw !== selectedMessage.folderFullNameRaw || + message.uid !== selectedMessage.uid + )) + { + this.selectorMessageSelected(null); + if (1 === this.messageList().length) + { + this.selectorMessageFocused(null); + } + } + else if (!selectedMessage && message) + { + selectedMessage = _.find(this.messageList(), + (subMessage) => subMessage && + subMessage.folderFullNameRaw === message.folderFullNameRaw && + subMessage.uid === message.uid + ); + + if (selectedMessage) + { + this.selectorMessageSelected(selectedMessage); + this.selectorMessageFocused(selectedMessage); + } + } - this.initBlockquoteSwitcher(oBody); } - oMessage.body.show(); + windowResize(); } - - Cache.initMessageFlagsFromCache(oMessage); - if (oMessage.unseen() || oMessage.hasUnseenSubMessage()) - { - require('App/User').default.messageListAction(oMessage.folderFullNameRaw, - oMessage.uid, Enums.MessageSetAction.SetSeen, [oMessage]); - } - - if (bNew) - { - oMessage = this.message(); - - if (oSelectedMessage && oMessage && ( - oMessage.folderFullNameRaw !== oSelectedMessage.folderFullNameRaw || - oMessage.uid !== oSelectedMessage.uid - )) - { - this.selectorMessageSelected(null); - if (1 === this.messageList().length) - { - this.selectorMessageFocused(null); - } - } - else if (!oSelectedMessage && oMessage) - { - oSelectedMessage = _.find(this.messageList(), function(oSubMessage) { - return oSubMessage && - oSubMessage.folderFullNameRaw === oMessage.folderFullNameRaw && - oSubMessage.uid === oMessage.uid; - }); - - if (oSelectedMessage) - { - this.selectorMessageSelected(oSelectedMessage); - this.selectorMessageFocused(oSelectedMessage); - } - } - - } - - Utils.windowResize(); } } -}; -MessageUserStore.prototype.selectMessage = function(oMessage) -{ - if (oMessage) - { - this.message(this.staticMessage.populateByMessageListItem(oMessage)); - - this.populateMessageBody(this.message()); - } - else - { - this.message(null); - } -}; - -MessageUserStore.prototype.selectMessageByFolderAndUid = function(sFolder, sUid) -{ - if (sFolder && sUid) - { - this.message(this.staticMessage.populateByMessageListItem(null)); - this.message().folderFullNameRaw = sFolder; - this.message().uid = sUid; - - this.populateMessageBody(this.message()); - } - else - { - this.message(null); - } -}; - -MessageUserStore.prototype.populateMessageBody = function(oMessage) -{ - if (oMessage) - { - if (Remote.message(this.onMessageResponse, oMessage.folderFullNameRaw, oMessage.uid)) + selectMessage(oMessage) { + if (oMessage) { - this.messageCurrentLoading(true); + this.message(this.staticMessage.populateByMessageListItem(oMessage)); + this.populateMessageBody(this.message()); + } + else + { + this.message(null); } } -}; -/** - * @param {string} sResult - * @param {AjaxJsonDefaultResponse} oData - * @param {boolean} bCached - */ -MessageUserStore.prototype.onMessageResponse = function(sResult, oData, bCached) -{ - this.hideMessageBodies(); - - this.messageCurrentLoading(false); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - this.setMessage(oData, bCached); - } - else if (Enums.StorageResultType.Unload === sResult) - { - this.message(null); - this.messageError(''); - } - else if (Enums.StorageResultType.Abort !== sResult) - { - this.message(null); - this.messageError((oData && oData.ErrorCode ? - Translator.getNotification(oData.ErrorCode) : - Translator.getNotification(Enums.Notification.UnknownError))); - } -}; - -/** - * @param {Array} aList - * @returns {string} - */ -MessageUserStore.prototype.calculateMessageListHash = function(aList) -{ - return _.map(aList, function(oMessage) { - return '' + oMessage.hash + '_' + oMessage.threadsLen() + '_' + oMessage.flagHash(); - }).join('|'); -}; - -MessageUserStore.prototype.setMessageList = function(oData, bCached) -{ - if (oData && oData.Result && 'Collection/MessageCollection' === oData.Result['@Object'] && - oData.Result['@Collection'] && Utils.isArray(oData.Result['@Collection'])) - { - var - iCount = 0, - iOffset = 0, - aList = [], - iNewCount = 0, - iUtc = require('Common/Momentor').momentNowUnix(), - bUnreadCountChange = false; - - iCount = Utils.pInt(oData.Result.MessageResultCount); - iOffset = Utils.pInt(oData.Result.Offset); - - var oFolder = Cache.getFolderFromCacheList(Utils.isNormal(oData.Result.Folder) ? oData.Result.Folder : ''); - if (oFolder && !bCached) + selectMessageByFolderAndUid(sFolder, sUid) { + if (sFolder && sUid) { - oFolder.interval = iUtc; + this.message(this.staticMessage.populateByMessageListItem(null)); + this.message().folderFullNameRaw = sFolder; + this.message().uid = sUid; - Cache.setFolderHash(oData.Result.Folder, oData.Result.FolderHash); + this.populateMessageBody(this.message()); + } + else + { + this.message(null); + } + } - if (Utils.isNormal(oData.Result.MessageCount)) + populateMessageBody(oMessage) { + if (oMessage) + { + if (Remote.message(this.onMessageResponse, oMessage.folderFullNameRaw, oMessage.uid)) { - oFolder.messageCountAll(oData.Result.MessageCount); + this.messageCurrentLoading(true); } + } + } - if (Utils.isNormal(oData.Result.MessageUnseenCount)) + /** + * @param {string} sResult + * @param {AjaxJsonDefaultResponse} oData + * @param {boolean} bCached + */ + onMessageResponse(sResult, oData, bCached) { + + this.hideMessageBodies(); + + this.messageCurrentLoading(false); + + if (StorageResultType.Success === sResult && oData && oData.Result) + { + this.setMessage(oData, bCached); + } + else if (StorageResultType.Unload === sResult) + { + this.message(null); + this.messageError(''); + } + else if (StorageResultType.Abort !== sResult) + { + this.message(null); + this.messageError((oData && oData.ErrorCode ? + getNotification(oData.ErrorCode) : getNotification(Notification.UnknownError))); + } + } + + /** + * @param {Array} aList + * @returns {string} + */ + calculateMessageListHash(list) { + return _.map(list, (message) => '' + message.hash + '_' + message.threadsLen() + '_' + message.flagHash()).join('|'); + } + + setMessageList(data, cached) { + if (data && data.Result && 'Collection/MessageCollection' === data.Result['@Object'] && + data.Result['@Collection'] && isArray(data.Result['@Collection'])) + { + let + newCount = 0, + unreadCountChange = false; + + const + list = [], + utc = require('Common/Momentor').momentNowUnix(), + iCount = pInt(data.Result.MessageResultCount), + iOffset = pInt(data.Result.Offset); + + const folder = getFolderFromCacheList(isNormal(data.Result.Folder) ? data.Result.Folder : ''); + + if (folder && !cached) { - if (Utils.pInt(oFolder.messageCountUnread()) !== Utils.pInt(oData.Result.MessageUnseenCount)) + folder.interval = utc; + + setFolderHash(data.Result.Folder, data.Result.FolderHash); + + if (isNormal(data.Result.MessageCount)) { - bUnreadCountChange = true; + folder.messageCountAll(data.Result.MessageCount); } - oFolder.messageCountUnread(oData.Result.MessageUnseenCount); - } - - this.initUidNextAndNewMessages(oFolder.fullNameRaw, oData.Result.UidNext, oData.Result.NewMessages); - } - - if (bUnreadCountChange && oFolder) - { - Cache.clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw); - } - - _.each(oData.Result['@Collection'], function(oJsonMessage) { - if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object']) - { - var oMessage = MessageModel.newInstanceFromJson(oJsonMessage); - if (oMessage) + if (isNormal(data.Result.MessageUnseenCount)) { - if (Cache.hasNewMessageAndRemoveFromCache(oMessage.folderFullNameRaw, oMessage.uid) && 5 >= iNewCount) + if (pInt(folder.messageCountUnread()) !== pInt(data.Result.MessageUnseenCount)) { - iNewCount += 1; - oMessage.newForAnimation(true); + unreadCountChange = true; } - oMessage.deleted(false); - - if (bCached) - { - Cache.initMessageFlagsFromCache(oMessage); - } - else - { - Cache.storeMessageFlagsToCache(oMessage); - } - - aList.push(oMessage); + folder.messageCountUnread(data.Result.MessageUnseenCount); } + + this.initUidNextAndNewMessages(folder.fullNameRaw, data.Result.UidNext, data.Result.NewMessages); } - }); - this.messageListCount(iCount); - this.messageListSearch(Utils.isNormal(oData.Result.Search) ? oData.Result.Search : ''); - this.messageListPage(window.Math.ceil((iOffset / SettingsStore.messagesPerPage()) + 1)); - this.messageListThreadUid(Utils.isNormal(oData.Result.ThreadUid) ? Utils.pString(oData.Result.ThreadUid) : ''); + if (unreadCountChange && folder) + { + clearMessageFlagsFromCacheByFolder(folder.fullNameRaw); + } - this.messageListEndFolder(Utils.isNormal(oData.Result.Folder) ? oData.Result.Folder : ''); - this.messageListEndSearch(this.messageListSearch()); - this.messageListEndThreadUid(this.messageListThreadUid()); - this.messageListEndPage(this.messageListPage()); + _.each(data.Result['@Collection'], (jsonMessage) => { + if (jsonMessage && 'Object/Message' === jsonMessage['@Object']) + { + const message = MessageModel.newInstanceFromJson(jsonMessage); + if (message) + { + if (hasNewMessageAndRemoveFromCache(message.folderFullNameRaw, message.uid) && 5 >= newCount) + { + newCount += 1; + message.newForAnimation(true); + } - this.messageListDisableAutoSelect(true); + message.deleted(false); - this.messageList(aList); - this.messageListIsNotCompleted(false); + if (cached) + { + initMessageFlagsFromCache(message); + } + else + { + storeMessageFlagsToCache(message); + } - Cache.clearNewMessageCache(); + list.push(message); + } + } + }); - if (oFolder && (bCached || bUnreadCountChange || SettingsStore.useThreads())) + this.messageListCount(iCount); + this.messageListSearch(isNormal(data.Result.Search) ? data.Result.Search : ''); + this.messageListPage(window.Math.ceil((iOffset / SettingsStore.messagesPerPage()) + 1)); + this.messageListThreadUid(isNormal(data.Result.ThreadUid) ? pString(data.Result.ThreadUid) : ''); + + this.messageListEndFolder(isNormal(data.Result.Folder) ? data.Result.Folder : ''); + this.messageListEndSearch(this.messageListSearch()); + this.messageListEndThreadUid(this.messageListThreadUid()); + this.messageListEndPage(this.messageListPage()); + + this.messageListDisableAutoSelect(true); + + this.messageList(list); + this.messageListIsNotCompleted(false); + + clearNewMessageCache(); + + if (folder && (cached || unreadCountChange || SettingsStore.useThreads())) + { + getApp().folderInformation(folder.fullNameRaw, list); + } + } + else { - require('App/User').default.folderInformation(oFolder.fullNameRaw, aList); + this.messageListCount(0); + this.messageList([]); + this.messageListError(getNotification( + data && data.ErrorCode ? data.ErrorCode : Notification.CantGetMessageList + )); } } - else - { - this.messageListCount(0); - this.messageList([]); - this.messageListError(Translator.getNotification( - oData && oData.ErrorCode ? oData.ErrorCode : Enums.Notification.CantGetMessageList - )); - } -}; +} module.exports = new MessageUserStore(); diff --git a/dev/Stores/User/Notification.js b/dev/Stores/User/Notification.js index 360dc3ce9..797a1b558 100644 --- a/dev/Stores/User/Notification.js +++ b/dev/Stores/User/Notification.js @@ -1,220 +1,207 @@ -var - window = require('window'), - ko = require('ko'), +import window from 'window'; +import ko from 'ko'; - Enums = require('Common/Enums'), - Events = require('Common/Events'), - Audio = require('Common/Audio'), +import {DesktopNotification, Magics} from 'Common/Enums'; +import * as Events from 'Common/Events'; +import Audio from 'Common/Audio'; - Settings = require('Storage/Settings'); +import * as Settings from 'Storage/Settings'; -/** - * @constructor - */ -function NotificationUserStore() +class NotificationUserStore { - var self = this; + constructor() { + this.enableSoundNotification = ko.observable(false); + this.soundNotificationIsSupported = ko.observable(false); - this.enableSoundNotification = ko.observable(false); - this.soundNotificationIsSupported = ko.observable(false); + this.allowDesktopNotification = ko.observable(false); - this.allowDesktopNotification = ko.observable(false); + this.desktopNotificationPermissions = ko.computed(() => { - this.desktopNotificationPermissions = ko.computed(function() { + this.allowDesktopNotification(); - this.allowDesktopNotification(); + let result = DesktopNotification.NotSupported; - var - NotificationClass = this.notificationClass(), - iResult = Enums.DesktopNotification.NotSupported; - - if (NotificationClass && NotificationClass.permission) - { - switch (NotificationClass.permission.toLowerCase()) + const NotificationClass = this.notificationClass(); + if (NotificationClass && NotificationClass.permission) { - case 'granted': - iResult = Enums.DesktopNotification.Allowed; - break; - case 'denied': - iResult = Enums.DesktopNotification.Denied; - break; - case 'default': - iResult = Enums.DesktopNotification.NotAllowed; - break; - // no default - } - } - else if (window.webkitNotifications && window.webkitNotifications.checkPermission) - { - iResult = window.webkitNotifications.checkPermission(); - } - - return iResult; - - }, this).extend({'notify': 'always'}); - - this.enableDesktopNotification = ko.computed({ - 'owner': this, - 'read': function() { - return this.allowDesktopNotification() && - Enums.DesktopNotification.Allowed === this.desktopNotificationPermissions(); - }, - 'write': function(bValue) { - if (bValue) - { - var - NotificationClass = this.notificationClass(), - iPermission = this.desktopNotificationPermissions(); - - if (NotificationClass && Enums.DesktopNotification.Allowed === iPermission) + switch (NotificationClass.permission.toLowerCase()) { - this.allowDesktopNotification(true); + case 'granted': + result = DesktopNotification.Allowed; + break; + case 'denied': + result = DesktopNotification.Denied; + break; + case 'default': + result = DesktopNotification.NotAllowed; + break; + // no default } - else if (NotificationClass && Enums.DesktopNotification.NotAllowed === iPermission) + } + else if (window.webkitNotifications && window.webkitNotifications.checkPermission) + { + result = window.webkitNotifications.checkPermission(); + } + + return result; + + }).extend({notify: 'always'}); + + this.enableDesktopNotification = ko.computed({ + read: () => this.allowDesktopNotification() && DesktopNotification.Allowed === this.desktopNotificationPermissions(), + write: (value) => { + if (value) { - NotificationClass.requestPermission(function() { - self.allowDesktopNotification.valueHasMutated(); - if (Enums.DesktopNotification.Allowed === self.desktopNotificationPermissions()) - { - if (self.allowDesktopNotification()) + const + NotificationClass = this.notificationClass(), + permission = this.desktopNotificationPermissions(); + + if (NotificationClass && DesktopNotification.Allowed === permission) + { + this.allowDesktopNotification(true); + } + else if (NotificationClass && DesktopNotification.NotAllowed === permission) + { + NotificationClass.requestPermission(() => { + + this.allowDesktopNotification.valueHasMutated(); + + if (DesktopNotification.Allowed === this.desktopNotificationPermissions()) { - self.allowDesktopNotification.valueHasMutated(); + if (this.allowDesktopNotification()) + { + this.allowDesktopNotification.valueHasMutated(); + } + else + { + this.allowDesktopNotification(true); + } } else { - self.allowDesktopNotification(true); + if (this.allowDesktopNotification()) + { + this.allowDesktopNotification(false); + } + else + { + this.allowDesktopNotification.valueHasMutated(); + } } - } - else - { - if (self.allowDesktopNotification()) - { - self.allowDesktopNotification(false); - } - else - { - self.allowDesktopNotification.valueHasMutated(); - } - } - }); + }); + } + else + { + this.allowDesktopNotification(false); + } } else { this.allowDesktopNotification(false); } } - else - { - this.allowDesktopNotification(false); - } - } - }).extend({'notify': 'always'}); + }).extend({notify: 'always'}); - if (!this.enableDesktopNotification.valueHasMutated) - { - this.enableDesktopNotification.valueHasMutated = function() { - self.allowDesktopNotification.valueHasMutated(); - }; + if (!this.enableDesktopNotification.valueHasMutated) + { + this.enableDesktopNotification.valueHasMutated = () => { + this.allowDesktopNotification.valueHasMutated(); + }; + } + + this.computers(); + + this.initNotificationPlayer(); } - this.computers(); + computers() { + this.isDesktopNotificationSupported = ko.computed( + () => DesktopNotification.NotSupported !== this.desktopNotificationPermissions() + ); - this.initNotificationPlayer(); + this.isDesktopNotificationDenied = ko.computed( + () => DesktopNotification.NotSupported === this.desktopNotificationPermissions() || + DesktopNotification.Denied === this.desktopNotificationPermissions() + ); + } + + initNotificationPlayer() { + if (Audio && Audio.supportedNotification) + { + this.soundNotificationIsSupported(true); + } + else + { + this.enableSoundNotification(false); + this.soundNotificationIsSupported(false); + } + } + + playSoundNotification(skipSetting) { + if (Audio && Audio.supportedNotification && (skipSetting ? true : this.enableSoundNotification())) + { + Audio.playNotification(); + } + } + + displayDesktopNotification(imageSrc, title, text, nessageData) { + if (this.enableDesktopNotification()) + { + const + NotificationClass = this.notificationClass(), + notification = NotificationClass ? new NotificationClass(title, { + body: text, + icon: imageSrc + }) : null; + + if (notification) + { + if (notification.show) + { + notification.show(); + } + + if (nessageData) + { + notification.onclick = () => { + + window.focus(); + + if (nessageData.Folder && nessageData.Uid) + { + Events.pub('mailbox.message.show', [nessageData.Folder, nessageData.Uid]); + } + }; + } + + window.setTimeout((function(localNotifications) { + return () => { + if (localNotifications.cancel) + { + localNotifications.cancel(); + } + else if (localNotifications.close) + { + localNotifications.close(); + } + }; + }(notification)), Magics.Time7s); + } + } + } + + populate() { + this.enableSoundNotification(!!Settings.settingsGet('SoundNotification')); + this.enableDesktopNotification(!!Settings.settingsGet('DesktopNotifications')); + } + + /** + * @returns {*|null} + */ + notificationClass() { + return window.Notification && window.Notification.requestPermission ? window.Notification : null; + } } -NotificationUserStore.prototype.computers = function() -{ - this.isDesktopNotificationSupported = ko.computed(function() { - return Enums.DesktopNotification.NotSupported !== this.desktopNotificationPermissions(); - }, this); - - this.isDesktopNotificationDenied = ko.computed(function() { - return Enums.DesktopNotification.NotSupported === this.desktopNotificationPermissions() || - Enums.DesktopNotification.Denied === this.desktopNotificationPermissions(); - }, this); -}; - -NotificationUserStore.prototype.initNotificationPlayer = function() -{ - if (Audio && Audio.supportedNotification) - { - this.soundNotificationIsSupported(true); - } - else - { - this.enableSoundNotification(false); - this.soundNotificationIsSupported(false); - } -}; - -NotificationUserStore.prototype.playSoundNotification = function(bSkipSetting) -{ - if (Audio && Audio.supportedNotification && (bSkipSetting ? true : this.enableSoundNotification())) - { - Audio.playNotification(); - } -}; - -NotificationUserStore.prototype.displayDesktopNotification = function(sImageSrc, sTitle, sText, oMessageData) -{ - if (this.enableDesktopNotification()) - { - var - NotificationClass = this.notificationClass(), - oNotification = NotificationClass ? new NotificationClass(sTitle, { - 'body': sText, - 'icon': sImageSrc - }) : null; - - if (oNotification) - { - if (oNotification.show) - { - oNotification.show(); - } - - if (oMessageData) - { - oNotification.onclick = function() { - - window.focus(); - - if (oMessageData.Folder && oMessageData.Uid) - { - Events.pub('mailbox.message.show', [oMessageData.Folder, oMessageData.Uid]); - } - }; - } - - window.setTimeout((function(oLocalNotifications) { - return function() { - if (oLocalNotifications.cancel) - { - oLocalNotifications.cancel(); - } - else if (oLocalNotifications.close) - { - oLocalNotifications.close(); - } - }; - }(oNotification)), Enums.Magics.Time7s); - } - } -}; - -NotificationUserStore.prototype.populate = function() -{ - this.enableSoundNotification(!!Settings.settingsGet('SoundNotification')); - this.enableDesktopNotification(!!Settings.settingsGet('DesktopNotifications')); -}; - -/** - * @returns {*|null} - */ -NotificationUserStore.prototype.notificationClass = function() -{ - return window.Notification && window.Notification.requestPermission ? window.Notification : null; -}; - module.exports = new NotificationUserStore(); diff --git a/dev/Stores/User/Pgp.js b/dev/Stores/User/Pgp.js index e973f5fc7..15e67747e 100644 --- a/dev/Stores/User/Pgp.js +++ b/dev/Stores/User/Pgp.js @@ -1,485 +1,403 @@ -var - _ = require('_'), - ko = require('ko'), - $ = require('$'), - kn = require('Knoin/Knoin'), +import ko from 'ko'; +import _ from '_'; +import $ from '$'; - Translator = require('Common/Translator'), - Settings = require('Storage/Settings'), +import {showScreenPopup} from 'Knoin/Knoin'; - Utils = require('Common/Utils'); +import {i18n} from 'Common/Translator'; +import {log, isArray, isNonEmptyArray, pString, isUnd, trim} from 'Common/Utils'; -/** - * @constructor - */ -function PgpUserStore() +class PgpUserStore { - this.capaOpenPGP = ko.observable(false); + constructor() { + this.capaOpenPGP = ko.observable(false); - this.openpgp = null; + this.openpgp = null; - this.openpgpkeys = ko.observableArray([]); - this.openpgpKeyring = null; + 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); - }); -} - -/** - * @returns {boolean} - */ -PgpUserStore.prototype.isSupported = function() -{ - return !!this.openpgp; -}; - -PgpUserStore.prototype.findKeyByHex = function(aKeys, sHash) -{ - return _.find(aKeys, function(oItem) { - return sHash && oItem && (sHash === oItem.id || -1 < oItem.ids.indexOf(sHash)); - }); -}; - -PgpUserStore.prototype.findPublicKeyByHex = function(sHash) -{ - return this.findKeyByHex(this.openpgpkeysPublic(), sHash); -}; - -PgpUserStore.prototype.findPrivateKeyByHex = function(sHash) -{ - return this.findKeyByHex(this.openpgpkeysPrivate(), sHash); -}; - -PgpUserStore.prototype.findPublicKeysByEmail = function(sEmail) -{ - return _.compact(_.flatten(_.map(this.openpgpkeysPublic(), function(oItem) { - var oKey = oItem && -1 < oItem.emails.indexOf(sEmail) ? oItem : null; - return oKey ? oKey.getNativeKeys() : [null]; - }), true)); -}; - -PgpUserStore.prototype.findPublicKeysBySigningKeyIds = function(aSigningKeyIds) -{ - var self = this; - return _.compact(_.flatten(_.map(aSigningKeyIds, function(oId) { - var oKey = oId && oId.toHex ? self.findPublicKeyByHex(oId.toHex()) : null; - return oKey ? oKey.getNativeKeys() : [null]; - }), true)); -}; - -PgpUserStore.prototype.findPrivateKeysByEncryptionKeyIds = function(aEncryptionKeyIds, aRecipients, bReturnWrapKeys) -{ - var - self = this, - aResult = Utils.isArray(aEncryptionKeyIds) ? _.compact(_.flatten(_.map(aEncryptionKeyIds, function(oId) { - var oKey = oId && oId.toHex ? self.findPrivateKeyByHex(oId.toHex()) : null; - return oKey ? (bReturnWrapKeys ? [oKey] : oKey.getNativeKeys()) : [null]; - }), true)) : []; - - if (0 === aResult.length && Utils.isNonEmptyArray(aRecipients)) - { - aResult = _.uniq(_.compact(_.flatten(_.map(aRecipients, function(sEmail) { - var aKeys = sEmail ? self.findAllPrivateKeysByEmailNotNative(sEmail) : null; - return aKeys ? (bReturnWrapKeys ? aKeys : _.flatten(_.map(aKeys, function(oKey) { - return oKey.getNativeKeys(); - }), true)) : [null]; - }), true)), function(oKey) {return oKey.id;}); + this.openpgpkeysPublic = this.openpgpkeys.filter((item) => !!(item && !item.isPrivate)); + this.openpgpkeysPrivate = this.openpgpkeys.filter((item) => !!(item && item.isPrivate)); } - return aResult; -}; + /** + * @returns {boolean} + */ + isSupported() { + return !!this.openpgp; + } -/** - * @param {string} sEmail - * @returns {?} - */ -PgpUserStore.prototype.findPublicKeyByEmailNotNative = function(sEmail) -{ - return _.find(this.openpgpkeysPublic(), function(oItem) { - return oItem && -1 < oItem.emails.indexOf(sEmail); - }) || null; -}; + findKeyByHex(keys, hash) { + return _.find(keys, (item) => (hash && item && (hash === item.id || -1 < item.ids.indexOf(hash)))); + } -/** - * @param {string} sEmail - * @returns {?} - */ -PgpUserStore.prototype.findPrivateKeyByEmailNotNative = function(sEmail) -{ - return _.find(this.openpgpkeysPrivate(), function(oItem) { - return oItem && -1 < oItem.emails.indexOf(sEmail); - }) || null; -}; + findPublicKeyByHex(hash) { + return this.findKeyByHex(this.openpgpkeysPublic(), hash); + } -/** - * @param {string} sEmail - * @returns {?} - */ -PgpUserStore.prototype.findAllPublicKeysByEmailNotNative = function(sEmail) -{ - return _.filter(this.openpgpkeysPublic(), function(oItem) { - return oItem && -1 < oItem.emails.indexOf(sEmail); - }) || null; -}; + findPrivateKeyByHex(hash) { + return this.findKeyByHex(this.openpgpkeysPrivate(), hash); + } -/** - * @param {string} sEmail - * @returns {?} - */ -PgpUserStore.prototype.findAllPrivateKeysByEmailNotNative = function(sEmail) -{ - return _.filter(this.openpgpkeysPrivate(), function(oItem) { - return oItem && -1 < oItem.emails.indexOf(sEmail); - }) || null; -}; + findPublicKeysByEmail(email) { + return _.compact(_.flatten(_.map(this.openpgpkeysPublic(), (item) => { + const key = item && -1 < item.emails.indexOf(email) ? item : null; + return key ? key.getNativeKeys() : [null]; + }), true)); + } -/** - * @param {string} sEmail - * @param {string=} sPassword - * @returns {?} - */ -PgpUserStore.prototype.findPrivateKeyByEmail = function(sEmail, sPassword) -{ - var - oPrivateKey = null, - oKey = _.find(this.openpgpkeysPrivate(), function(oItem) { - return oItem && -1 < oItem.emails.indexOf(sEmail); - }); + findPublicKeysBySigningKeyIds(signingKeyIds) { + return _.compact(_.flatten(_.map(signingKeyIds, (id) => { + const key = id && id.toHex ? this.findPublicKeyByHex(id.toHex()) : null; + return key ? key.getNativeKeys() : [null]; + }), true)); + } - if (oKey) - { - try + findPrivateKeysByEncryptionKeyIds(encryptionKeyIds, recipients, returnWrapKeys) { + let + result = isArray(encryptionKeyIds) ? _.compact(_.flatten(_.map(encryptionKeyIds, (id) => { + const key = id && id.toHex ? this.findPrivateKeyByHex(id.toHex()) : null; + return key ? (returnWrapKeys ? [key] : key.getNativeKeys()) : [null]; + }), true)) : []; + + if (0 === result.length && isNonEmptyArray(recipients)) { - oPrivateKey = oKey.getNativeKeys()[0] || null; - if (oPrivateKey) + result = _.uniq(_.compact(_.flatten(_.map(recipients, (sEmail) => { + const keys = sEmail ? this.findAllPrivateKeysByEmailNotNative(sEmail) : null; + return keys ? (returnWrapKeys ? keys : _.flatten(_.map(keys, (key) => key.getNativeKeys()), true)) : [null]; + }), true)), (key) => key.id); + } + + return result; + } + + /** + * @param {string} email + * @returns {?} + */ + findPublicKeyByEmailNotNative(email) { + return _.find(this.openpgpkeysPublic(), (item) => (item && -1 < item.emails.indexOf(email))) || null; + } + + /** + * @param {string} email + * @returns {?} + */ + findPrivateKeyByEmailNotNative(email) { + return _.find(this.openpgpkeysPrivate(), (item) => (item && -1 < item.emails.indexOf(email))) || null; + } + + /** + * @param {string} email + * @returns {?} + */ + findAllPublicKeysByEmailNotNative(email) { + return _.filter(this.openpgpkeysPublic(), (item) => (item && -1 < item.emails.indexOf(email))) || null; + } + + /** + * @param {string} email + * @returns {?} + */ + findAllPrivateKeysByEmailNotNative(email) { + return _.filter(this.openpgpkeysPrivate(), (item) => (item && -1 < item.emails.indexOf(email))) || null; + } + + /** + * @param {string} email + * @param {string=} password + * @returns {?} + */ + findPrivateKeyByEmail(email, password) { + + let privateKey = null; + const key = _.find(this.openpgpkeysPrivate(), (item) => (item && -1 < item.emails.indexOf(email))); + + if (key) + { + try { - oPrivateKey.decrypt(Utils.pString(sPassword)); + privateKey = key.getNativeKeys()[0] || null; + if (privateKey) + { + privateKey.decrypt(pString(password)); + } + } + catch (e) + { + privateKey = null; } } - catch (e) - { - oPrivateKey = null; - } + + return privateKey; } - return oPrivateKey; -}; + /** + * @param {string=} password + * @returns {?} + */ + findSelfPrivateKey(password) { + return this.findPrivateKeyByEmail(require('Stores/User/Account').email(), password); + } -/** - * @param {string=} sPassword - * @returns {?} - */ -PgpUserStore.prototype.findSelfPrivateKey = function(sPassword) -{ - return this.findPrivateKeyByEmail(require('Stores/User/Account').email(), sPassword); -}; - -PgpUserStore.prototype.decryptMessage = function(oMessage, aRecipients, fCallback) -{ - if (oMessage && oMessage.getEncryptionKeyIds) - { - var self = this, - aPrivateKeys = this.findPrivateKeysByEncryptionKeyIds(oMessage.getEncryptionKeyIds(), aRecipients, true); - - if (aPrivateKeys && 0 < aPrivateKeys.length) + decryptMessage(message, recipients, fCallback) { + if (message && message.getEncryptionKeyIds) { - kn.showScreenPopup(require('View/Popup/MessageOpenPgp'), [function(oDecryptedKey) { + const privateKeys = this.findPrivateKeysByEncryptionKeyIds(message.getEncryptionKeyIds(), recipients, true); + if (privateKeys && 0 < privateKeys.length) + { + showScreenPopup(require('View/Popup/MessageOpenPgp'), [(decryptedKey) => { - if (oDecryptedKey) - { - oMessage.decrypt(oDecryptedKey).then(function(oDecryptedMessage) { - var oPrivateKey = null; - if (oDecryptedMessage) - { - oPrivateKey = self.findPrivateKeyByHex(oDecryptedKey.primaryKey.keyid.toHex()); - if (oPrivateKey) + if (decryptedKey) + { + message.decrypt(decryptedKey).then((decryptedMessage) => { + let privateKey = null; + if (decryptedMessage) { - self.verifyMessage(oDecryptedMessage, function(oValidKey, aSigningKeyIds) { - fCallback(oPrivateKey, oDecryptedMessage, oValidKey || null, aSigningKeyIds || null); - }); + privateKey = this.findPrivateKeyByHex(decryptedKey.primaryKey.keyid.toHex()); + if (privateKey) + { + this.verifyMessage(decryptedMessage, (oValidKey, aSigningKeyIds) => { + fCallback(privateKey, decryptedMessage, oValidKey || null, aSigningKeyIds || null); + }); + } + else + { + fCallback(privateKey, decryptedMessage); + } } else { - fCallback(oPrivateKey, oDecryptedMessage); + fCallback(privateKey, decryptedMessage); } - } - else - { - fCallback(oPrivateKey, oDecryptedMessage); - } - }, function() { - fCallback(null, null); - }); - } - else - { - fCallback(null, null); - } - - }, aPrivateKeys]); - - return false; - } - } - - fCallback(null, null); - - return false; -}; - -PgpUserStore.prototype.findKeyExternal = function(sEmail, fCallback) -{ - if (this.openpgp.HKP && Settings.appSettingsGet('openpgpPublicKeyServer')) - { - var oHkp = new this.openpgp.HKP(Settings.appSettingsGet('openpgpPublicKeyServer').replace(/\/$/, '')); - oHkp.lookup({query: sEmail}).then(function(sKey) { - fCallback(sKey); - }, function() { - fCallback(null); - }); - } - else - { - fCallback(null); - } -}; - -PgpUserStore.prototype.verifyMessage = function(oMessage, fCallback) -{ - if (oMessage && oMessage.getSigningKeyIds) - { - var aSigningKeyIds = oMessage.getSigningKeyIds(); - if (aSigningKeyIds && 0 < aSigningKeyIds.length) - { - var aPublicKeys = this.findPublicKeysBySigningKeyIds(aSigningKeyIds); - if (aPublicKeys && 0 < aPublicKeys.length) - { - try - { - var - aResult = oMessage.verify(aPublicKeys), - oValid = _.find(_.isArray(aResult) ? aResult : [], function(oItem) { - return oItem && oItem.valid && oItem.keyid; + }, () => { + fCallback(null, null); }); - - if (oValid && oValid.keyid && oValid.keyid && oValid.keyid.toHex) - { - fCallback(this.findPublicKeyByHex(oValid.keyid.toHex())); - return true; - } - } - catch (e) - { - Utils.log(e); - } - } - - fCallback(null, aSigningKeyIds); - return false; - } - } - - fCallback(null); - return false; -}; - -/** - * @param {*} mDom - */ -PgpUserStore.prototype.controlsHelper = function(mDom, oVerControl, bSuccess, sTitle, sText) -{ - if (bSuccess) - { - mDom.removeClass('error').addClass('success').attr('title', sTitle); - oVerControl.removeClass('error').addClass('success').attr('title', sTitle); - } - else - { - mDom.removeClass('success').addClass('error').attr('title', sTitle); - oVerControl.removeClass('success').addClass('error').attr('title', sTitle); - } - - if (!Utils.isUnd(sText)) - { - mDom.text(Utils.trim(sText.replace(/(\u200C|\u0002)/g, ''))); - } -}; - -/** - * @static - */ -PgpUserStore.domControlEncryptedClickHelper = function(store, mDom, sArmoredMessage, aRecipients) -{ - return function() { - - var - message = null, - $this = $(this); - - if ($this.hasClass('success')) - { - return false; - } - - try - { - message = store.openpgp.message.readArmored(sArmoredMessage); - } - catch (e) - { - Utils.log(e); - } - - if (message && message.getText && message.verify && message.decrypt) - { - store.decryptMessage(message, aRecipients, function(oValidPrivateKey, oDecryptedMessage, oValidPublicKey, aSigningKeyIds) { - - if (oDecryptedMessage) - { - if (oValidPublicKey) - { - store.controlsHelper(mDom, $this, true, Translator.i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', { - 'USER': oValidPublicKey.user + ' (' + oValidPublicKey.id + ')' - }), oDecryptedMessage.getText()); - } - else if (oValidPrivateKey) - { - var - aKeyIds = Utils.isNonEmptyArray(aSigningKeyIds) ? aSigningKeyIds : null, - sAdditional = aKeyIds ? _.compact(_.map(aKeyIds, function(oItem) { - return oItem && oItem.toHex ? oItem.toHex() : null; - })).join(', ') : ''; - - store.controlsHelper(mDom, $this, false, - Translator.i18n('PGP_NOTIFICATIONS/UNVERIFIRED_SIGNATURE') + - (sAdditional ? ' (' + sAdditional + ')' : ''), - oDecryptedMessage.getText()); } else { - store.controlsHelper(mDom, $this, false, - Translator.i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR')); + fCallback(null, null); + } + + }, privateKeys]); + + return false; + } + } + + fCallback(null, null); + + return false; + } + + verifyMessage(message, fCallback) { + if (message && message.getSigningKeyIds) + { + const signingKeyIds = message.getSigningKeyIds(); + if (signingKeyIds && 0 < signingKeyIds.length) + { + const publicKeys = this.findPublicKeysBySigningKeyIds(signingKeyIds); + if (publicKeys && 0 < publicKeys.length) + { + try + { + const + result = message.verify(publicKeys), + valid = _.find(_.isArray(result) ? result : [], (item) => (item && item.valid && item.keyid)); + + if (valid && valid.keyid && valid.keyid && valid.keyid.toHex) + { + fCallback(this.findPublicKeyByHex(valid.keyid.toHex())); + return true; + } + } + catch (e) + { + log(e); } } - else - { - store.controlsHelper(mDom, $this, false, - Translator.i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR')); - } - }); - return false; - } - - store.controlsHelper(mDom, $this, false, Translator.i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR')); - return false; - }; -}; - -/** - * @static - */ -PgpUserStore.domControlSignedClickHelper = function(store, mDom, sArmoredMessage) -{ - return function() { - - var - message = null, - $this = $(this); - - if ($this.hasClass('success') || $this.hasClass('error')) - { - return false; - } - - try - { - message = store.openpgp.cleartext.readArmored(sArmoredMessage); - } - catch (e) - { - Utils.log(e); - } - - if (message && message.getText && message.verify) - { - store.verifyMessage(message, function(oValidKey, aSigningKeyIds) { - if (oValidKey) - { - store.controlsHelper(mDom, $this, true, Translator.i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', { - 'USER': oValidKey.user + ' (' + oValidKey.id + ')' - }), message.getText()); - } - else - { - var - aKeyIds = Utils.isNonEmptyArray(aSigningKeyIds) ? aSigningKeyIds : null, - sAdditional = aKeyIds ? _.compact(_.map(aKeyIds, function(oItem) { - return oItem && oItem.toHex ? oItem.toHex() : null; - })).join(', ') : ''; - - store.controlsHelper(mDom, $this, false, - Translator.i18n('PGP_NOTIFICATIONS/UNVERIFIRED_SIGNATURE') + - (sAdditional ? ' (' + sAdditional + ')' : '')); - } - }); - - return false; - } - - store.controlsHelper(mDom, $this, false, Translator.i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR')); - return false; - }; -}; - -/** - * @param {*} mDom - * @param {MessageModel} oRainLoopMessage - */ -PgpUserStore.prototype.initMessageBodyControls = function(mDom, oRainLoopMessage) -{ - if (mDom && !mDom.hasClass('inited')) - { - mDom.addClass('inited'); - - var - bEncrypted = mDom.hasClass('encrypted'), - bSigned = mDom.hasClass('signed'), - oVerControl = null, - aRecipients = oRainLoopMessage ? oRainLoopMessage.getEmails(['from', 'to', 'cc']) : [], - sData = ''; - - if (bEncrypted || bSigned) - { - sData = mDom.text(); - mDom.data('openpgp-original', sData); - - if (bEncrypted) - { - oVerControl = $('
') - .attr('title', Translator.i18n('MESSAGE/PGP_ENCRYPTED_MESSAGE_DESC')) - .on('click', PgpUserStore.domControlEncryptedClickHelper(this, mDom, sData, aRecipients)); + fCallback(null, signingKeyIds); + return false; } - else if (bSigned) + } + + fCallback(null); + return false; + } + + controlsHelper(dom, verControl, success, title, text) { + if (success) + { + dom.removeClass('error').addClass('success').attr('title', title); + verControl.removeClass('error').addClass('success').attr('title', title); + } + else + { + dom.removeClass('success').addClass('error').attr('title', title); + verControl.removeClass('success').addClass('error').attr('title', title); + } + + if (!isUnd(text)) + { + dom.text(trim(text)); + } + } + + static domControlEncryptedClickHelper(store, dom, armoredMessage, recipients) { + + return function() { + + let message = null; + const $this = $(this); // eslint-disable-line no-invalid-this + + if ($this.hasClass('success')) { - oVerControl = $('
') - .attr('title', Translator.i18n('MESSAGE/PGP_SIGNED_MESSAGE_DESC')) - .on('click', PgpUserStore.domControlSignedClickHelper(this, mDom, sData)); + return false; } - if (oVerControl) + try { - mDom.before(oVerControl).before('
'); + message = store.openpgp.message.readArmored(armoredMessage); + } + catch (e) + { + log(e); + } + + if (message && message.getText && message.verify && message.decrypt) + { + store.decryptMessage(message, recipients, (validPrivateKey, decryptedMessage, validPublicKey, signingKeyIds) => { + if (decryptedMessage) + { + if (validPublicKey) + { + store.controlsHelper(dom, $this, true, i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', { + 'USER': validPublicKey.user + ' (' + validPublicKey.id + ')' + }), decryptedMessage.getText()); + } + else if (validPrivateKey) + { + const + keyIds = isNonEmptyArray(signingKeyIds) ? signingKeyIds : null, + additional = keyIds ? _.compact(_.map(keyIds, + (item) => (item && item.toHex ? item.toHex() : null))).join(', ') : ''; + + store.controlsHelper(dom, $this, false, i18n('PGP_NOTIFICATIONS/UNVERIFIRED_SIGNATURE') + + (additional ? ' (' + additional + ')' : ''), decryptedMessage.getText()); + } + else + { + store.controlsHelper(dom, $this, false, i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR')); + } + } + else + { + store.controlsHelper(dom, $this, false, i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR')); + } + }); + + return false; + } + + store.controlsHelper(dom, $this, false, i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR')); + return false; + }; + } + + static domControlSignedClickHelper(store, dom, armoredMessage) { + + return function() { + + let message = null; + const $this = $(this); // eslint-disable-line no-invalid-this + + if ($this.hasClass('success') || $this.hasClass('error')) + { + return false; + } + + try + { + message = store.openpgp.cleartext.readArmored(armoredMessage); + } + catch (e) + { + log(e); + } + + if (message && message.getText && message.verify) + { + store.verifyMessage(message, (validKey, signingKeyIds) => { + if (validKey) + { + store.controlsHelper(dom, $this, true, i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', { + 'USER': validKey.user + ' (' + validKey.id + ')' + }), message.getText()); + } + else + { + const + keyIds = isNonEmptyArray(signingKeyIds) ? signingKeyIds : null, + additional = keyIds ? _.compact(_.map(keyIds, (item) => (item && item.toHex ? item.toHex() : null))).join(', ') : ''; + + store.controlsHelper(dom, $this, false, + i18n('PGP_NOTIFICATIONS/UNVERIFIRED_SIGNATURE') + (additional ? ' (' + additional + ')' : '')); + } + }); + + return false; + } + + store.controlsHelper(dom, $this, false, i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR')); + return false; + }; + } + + /** + * @param {*} dom + * @param {MessageModel} rainLoopMessage + */ + initMessageBodyControls(dom, rainLoopMessage) { + if (dom && !dom.hasClass('inited')) + { + dom.addClass('inited'); + + const + encrypted = dom.hasClass('encrypted'), + signed = dom.hasClass('signed'), + recipients = rainLoopMessage ? rainLoopMessage.getEmails(['from', 'to', 'cc']) : []; + + let verControl = null; + + if (encrypted || signed) + { + const domText = dom.text(); + dom.data('openpgp-original', domText); + + if (encrypted) + { + verControl = $('
') + .attr('title', i18n('MESSAGE/PGP_ENCRYPTED_MESSAGE_DESC')) + .on('click', PgpUserStore.domControlEncryptedClickHelper(this, dom, domText, recipients)); + } + else if (signed) + { + verControl = $('
') + .attr('title', i18n('MESSAGE/PGP_SIGNED_MESSAGE_DESC')) + .on('click', PgpUserStore.domControlSignedClickHelper(this, dom, domText)); + } + + if (verControl) + { + dom.before(verControl).before('
'); + } } } } -}; +} module.exports = new PgpUserStore(); diff --git a/dev/Stores/User/Quota.js b/dev/Stores/User/Quota.js index 4f7b1c013..6bdc16efc 100644 --- a/dev/Stores/User/Quota.js +++ b/dev/Stores/User/Quota.js @@ -1,35 +1,32 @@ -var - window = require('window'), - ko = require('ko'); +import window from 'window'; +import ko from 'ko'; -/** - * @constructor - */ -function QuotaUserStore() +class QuotaUserStore { - this.quota = ko.observable(0); - this.usage = ko.observable(0); + constructor() { + this.quota = ko.observable(0); + this.usage = ko.observable(0); - this.percentage = ko.computed(function() { + this.percentage = ko.computed(() => { - var - iQuota = this.quota(), - iUsed = this.usage(); + const + quota = this.quota(), + usage = this.usage(); - return 0 < iQuota ? window.Math.ceil((iUsed / iQuota) * 100) : 0; + return 0 < quota ? window.Math.ceil((usage / quota) * 100) : 0; - }, this); + }); + } + + /** + * @param {number} quota + * @param {number} usage + */ + populateData(quota, usage) { + this.quota(quota * 1024); + this.usage(usage * 1024); + } } -/** - * @param {number} iQuota - * @param {number} iUsage - */ -QuotaUserStore.prototype.populateData = function(iQuota, iUsage) -{ - this.quota(iQuota * 1024); - this.usage(iUsage * 1024); -}; - module.exports = new QuotaUserStore(); diff --git a/dev/Stores/User/Settings.js b/dev/Stores/User/Settings.js index 96f285c00..53330456d 100644 --- a/dev/Stores/User/Settings.js +++ b/dev/Stores/User/Settings.js @@ -1,93 +1,81 @@ -var - window = require('window'), - ko = require('ko'), +import window from 'window'; +import ko from 'ko'; - Consts = require('Common/Consts'), - Enums = require('Common/Enums'), - Globals = require('Common/Globals'), - Utils = require('Common/Utils'), - Events = require('Common/Events'), +import {MESSAGES_PER_PAGE, MESSAGES_PER_PAGE_VALUES} from 'Common/Consts'; +import {Layout, EditorDefaultType, Magics} from 'Common/Enums'; +import {$html} from 'Common/Globals'; +import {pInt} from 'Common/Utils'; +import * as Events from 'Common/Events'; - Settings = require('Storage/Settings'); +import * as Settings from 'Storage/Settings'; -/** - * @constructor - */ -function SettingsUserStore() +class SettingsUserStore { - this.iAutoLogoutTimer = 0; + constructor() { - this.layout = ko.observable(Enums.Layout.SidePreview) - .extend({'limitedList': [ - Enums.Layout.SidePreview, Enums.Layout.BottomPreview, Enums.Layout.NoPreview - ]}); + this.iAutoLogoutTimer = 0; - this.editorDefaultType = ko.observable(Enums.EditorDefaultType.Html) - .extend({'limitedList': [ - Enums.EditorDefaultType.Html, Enums.EditorDefaultType.Plain, - Enums.EditorDefaultType.HtmlForced, Enums.EditorDefaultType.PlainForced - ]}); + this.layout = ko.observable(Layout.SidePreview) + .extend({limitedList: [Layout.SidePreview, Layout.BottomPreview, Layout.NoPreview]}); - this.messagesPerPage = ko.observable(Consts.MESSAGES_PER_PAGE) - .extend({'limitedList': Consts.MESSAGES_PER_PAGE_VALUES}); + this.editorDefaultType = ko.observable(EditorDefaultType.Html) + .extend({limitedList: [ + EditorDefaultType.Html, EditorDefaultType.Plain, + EditorDefaultType.HtmlForced, EditorDefaultType.PlainForced + ]}); - this.showImages = ko.observable(false); - this.useCheckboxesInList = ko.observable(true); - this.useThreads = ko.observable(false); - this.replySameFolder = ko.observable(false); + this.messagesPerPage = ko.observable(MESSAGES_PER_PAGE) + .extend({limitedList: MESSAGES_PER_PAGE_VALUES}); - this.autoLogout = ko.observable(30); + this.showImages = ko.observable(false); + this.useCheckboxesInList = ko.observable(true); + this.useThreads = ko.observable(false); + this.replySameFolder = ko.observable(false); - this.computers(); - this.subscribers(); + this.autoLogout = ko.observable(30); + + this.computers(); + this.subscribers(); + } + + computers() { + this.usePreviewPane = ko.computed(() => Layout.NoPreview !== this.layout()); + } + + subscribers() { + this.layout.subscribe((nValue) => { + $html.toggleClass('rl-no-preview-pane', Layout.NoPreview === nValue); + $html.toggleClass('rl-side-preview-pane', Layout.SidePreview === nValue); + $html.toggleClass('rl-bottom-preview-pane', Layout.BottomPreview === nValue); + Events.pub('layout', [nValue]); + }); + } + + populate() { + this.layout(pInt(Settings.settingsGet('Layout'))); + this.editorDefaultType(Settings.settingsGet('EditorDefaultType')); + + this.autoLogout(pInt(Settings.settingsGet('AutoLogout'))); + this.messagesPerPage(Settings.settingsGet('MPP')); + + this.showImages(!!Settings.settingsGet('ShowImages')); + this.useCheckboxesInList(!!Settings.settingsGet('UseCheckboxesInList')); + this.useThreads(!!Settings.settingsGet('UseThreads')); + this.replySameFolder(!!Settings.settingsGet('ReplySameFolder')); + + Events.sub('rl.auto-logout-refresh', () => { + window.clearTimeout(this.iAutoLogoutTimer); + if (0 < this.autoLogout() && !Settings.settingsGet('AccountSignMe')) + { + this.iAutoLogoutTimer = window.setTimeout(() => { + Events.pub('rl.auto-logout'); + }, this.autoLogout() * Magics.Time1m); + } + }); + + Events.pub('rl.auto-logout-refresh'); + } } -SettingsUserStore.prototype.computers = function() -{ - this.usePreviewPane = ko.computed(function() { - return Enums.Layout.NoPreview !== this.layout(); - }, this); -}; - -SettingsUserStore.prototype.subscribers = function() -{ - this.layout.subscribe(function(nValue) { - - Globals.$html.toggleClass('rl-no-preview-pane', Enums.Layout.NoPreview === nValue); - Globals.$html.toggleClass('rl-side-preview-pane', Enums.Layout.SidePreview === nValue); - Globals.$html.toggleClass('rl-bottom-preview-pane', Enums.Layout.BottomPreview === nValue); - - Events.pub('layout', [nValue]); - }); -}; - -SettingsUserStore.prototype.populate = function() -{ - this.layout(Utils.pInt(Settings.settingsGet('Layout'))); - this.editorDefaultType(Settings.settingsGet('EditorDefaultType')); - - this.autoLogout(Utils.pInt(Settings.settingsGet('AutoLogout'))); - this.messagesPerPage(Settings.settingsGet('MPP')); - - this.showImages(!!Settings.settingsGet('ShowImages')); - this.useCheckboxesInList(!!Settings.settingsGet('UseCheckboxesInList')); - this.useThreads(!!Settings.settingsGet('UseThreads')); - this.replySameFolder(!!Settings.settingsGet('ReplySameFolder')); - - var self = this; - - Events.sub('rl.auto-logout-refresh', function() { - window.clearTimeout(self.iAutoLogoutTimer); - if (0 < self.autoLogout() && !Settings.settingsGet('AccountSignMe')) - { - self.iAutoLogoutTimer = window.setTimeout(function() { - Events.pub('rl.auto-logout'); - }, self.autoLogout() * Enums.Magics.Time1m); - } - }); - - Events.pub('rl.auto-logout-refresh'); -}; - module.exports = new SettingsUserStore(); diff --git a/dev/Stores/User/Template.js b/dev/Stores/User/Template.js index e59c2cd7b..c9049677a 100644 --- a/dev/Stores/User/Template.js +++ b/dev/Stores/User/Template.js @@ -1,33 +1,28 @@ -var - _ = require('_'), - ko = require('ko'); +import ko from 'ko'; +import _ from '_'; // Remote = require('Remote/User/Ajax'); -/** - * @constructor - */ -function TemplateUserStore() +class TemplateUserStore { - this.templates = ko.observableArray([]); - this.templates.loading = ko.observable(false).extend({'throttle': 100}); + constructor() { + this.templates = ko.observableArray([]); + this.templates.loading = ko.observable(false).extend({throttle: 100}); - this.templatesNames = ko.observableArray([]).extend({'throttle': 1000}); - this.templatesNames.skipFirst = true; + this.templatesNames = ko.observableArray([]).extend({throttle: 1000}); + this.templatesNames.skipFirst = true; - this.subscribers(); -} + this.subscribers(); + } -TemplateUserStore.prototype.subscribers = function() -{ - this.templates.subscribe(function(aList) { - this.templatesNames(_.compact(_.map(aList, function(oItem) { - return oItem ? oItem.name : null; - }))); - }, this); + subscribers() { -// this.templatesNames.subscribe(function(aList) { + this.templates.subscribe((list) => { + this.templatesNames(_.compact(_.map(list, (item) => (item ? item.name : null)))); + }); + +// this.templatesNames.subscribe((aList) => { // if (this.templatesNames.skipFirst) // { // this.templatesNames.skipFirst = false; @@ -36,7 +31,8 @@ TemplateUserStore.prototype.subscribers = function() // { // Remote.templatesSortOrder(null, aList); // } -// }, this); -}; +// }); + } +} module.exports = new TemplateUserStore(); diff --git a/dev/Styles/@Boot.css b/dev/Styles/@Boot.css index a998c33ea..caa791184 100644 --- a/dev/Styles/@Boot.css +++ b/dev/Styles/@Boot.css @@ -45,10 +45,10 @@ html.no-css .thm-body { html.no-css .thm-loading { color: #333 !important; text-shadow: none !important; +} - .e-spinner .e-bounce { - display: none !important; - } +html.no-css .thm-loading .e-spinner .e-bounce { + display: none !important; } html.no-css .thm-login-desc .desc { diff --git a/dev/Styles/Animations.less b/dev/Styles/Animations.less index 7654f8316..bb34a8a4e 100644 --- a/dev/Styles/Animations.less +++ b/dev/Styles/Animations.less @@ -73,6 +73,15 @@ html { html.rl-anim { + .rl-animated-visible { + opacity: 1; + .transition(opacity 0.5s linear); + + &.rl-animated-hidden { + opacity: 0; + } + } + &.cssanimations.csstransitions.no-mobile .b-login-content .errorAnimated { animation: login-form-shake 400ms ease-in-out; } diff --git a/dev/Styles/_End.less b/dev/Styles/_End.less index 7d769e9d9..a26681d62 100644 --- a/dev/Styles/_End.less +++ b/dev/Styles/_End.less @@ -93,3 +93,10 @@ svg-icon { .btn .btn-text { padding-left: 8px; } + +.active-scale-transition { + transition: transform .2s; + &:active { + transform: scale(.95); + } +} diff --git a/dev/View/Admin/Login.js b/dev/View/Admin/Login.js index 3def3fb56..ac0cf2bc0 100644 --- a/dev/View/Admin/Login.js +++ b/dev/View/Admin/Login.js @@ -1,141 +1,131 @@ -var - _ = require('_'), - ko = require('ko'), +import ko from 'ko'; +import _ from '_'; - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Translator = require('Common/Translator'), +import { + trim, createCommand, + triggerAutocompleteInputChange +} from 'Common/Utils'; - Settings = require('Storage/Settings'), - Remote = require('Remote/Admin/Ajax'), +import {StorageResultType, Notification, Magics} from 'Common/Enums'; +import {getNotification} from 'Common/Translator'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import * as Settings from 'Storage/Settings'; -/** - * @constructor - * @extends AbstractView - */ -function LoginAdminView() +import Remote from 'Remote/Admin/Ajax'; + +import {getApp} from 'Helper/Apps/Admin'; + +import {view, ViewType, routeOff} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; + +@view({ + name: 'View/Admin/Login', + type: ViewType.Center, + templateID: 'AdminLogin' +}) +class LoginAdminView extends AbstractViewNext { - AbstractView.call(this, 'Center', 'AdminLogin'); + constructor() { + super(); - this.logoPowered = !!Settings.settingsGet('LoginPowered'); + this.logoPowered = !!Settings.settingsGet('LoginPowered'); - this.mobile = !!Settings.appSettingsGet('mobile'); - this.mobileDevice = !!Settings.appSettingsGet('mobileDevice'); + this.mobile = !!Settings.appSettingsGet('mobile'); + this.mobileDevice = !!Settings.appSettingsGet('mobileDevice'); - this.login = ko.observable(''); - this.password = ko.observable(''); + this.login = ko.observable(''); + this.password = ko.observable(''); - this.loginError = ko.observable(false); - this.passwordError = ko.observable(false); + this.loginError = ko.observable(false); + this.passwordError = ko.observable(false); - this.loginErrorAnimation = ko.observable(false).extend({'falseTimeout': 500}); - this.passwordErrorAnimation = ko.observable(false).extend({'falseTimeout': 500}); + this.loginErrorAnimation = ko.observable(false).extend({'falseTimeout': 500}); + this.passwordErrorAnimation = ko.observable(false).extend({'falseTimeout': 500}); - this.loginFocus = ko.observable(false); + this.loginFocus = ko.observable(false); - this.formHidden = ko.observable(false); + this.formHidden = ko.observable(false); - this.formError = ko.computed(function() { - return this.loginErrorAnimation() || this.passwordErrorAnimation(); - }, this); + this.formError = ko.computed(() => this.loginErrorAnimation() || this.passwordErrorAnimation()); - this.login.subscribe(function() { - this.loginError(false); - }, this); + this.login.subscribe(() => this.loginError(false)); - this.password.subscribe(function() { - this.passwordError(false); - }, this); + this.password.subscribe(() => this.passwordError(false)); - this.loginError.subscribe(function(bV) { - this.loginErrorAnimation(!!bV); - }, this); + this.loginError.subscribe((v) => this.loginErrorAnimation(!!v)); - this.passwordError.subscribe(function(bV) { - this.passwordErrorAnimation(!!bV); - }, this); + this.passwordError.subscribe((v) => { + this.passwordErrorAnimation(!!v); + }); - this.submitRequest = ko.observable(false); - this.submitError = ko.observable(''); + this.submitRequest = ko.observable(false); + this.submitError = ko.observable(''); - this.submitCommand = Utils.createCommand(this, function() { + this.submitCommand = createCommand(() => { - Utils.triggerAutocompleteInputChange(); + triggerAutocompleteInputChange(); - this.loginError(false); - this.passwordError(false); + this.loginError(false); + this.passwordError(false); - this.loginError('' === Utils.trim(this.login())); - this.passwordError('' === Utils.trim(this.password())); + this.loginError('' === trim(this.login())); + this.passwordError('' === trim(this.password())); - if (this.loginError() || this.passwordError()) - { - return false; - } - - this.submitRequest(true); - - Remote.adminLogin(_.bind(function(sResult, oData) { - - if (Enums.StorageResultType.Success === sResult && oData && 'AdminLogin' === oData.Action) + if (this.loginError() || this.passwordError()) { - if (oData.Result) + return false; + } + + this.submitRequest(true); + + Remote.adminLogin((sResult, oData) => { + + if (StorageResultType.Success === sResult && oData && 'AdminLogin' === oData.Action) { - require('App/Admin').default.loginAndLogoutReload(true); + if (oData.Result) + { + getApp().loginAndLogoutReload(true); + } + else if (oData.ErrorCode) + { + this.submitRequest(false); + this.submitError(getNotification(oData.ErrorCode)); + } } - else if (oData.ErrorCode) + else { this.submitRequest(false); - this.submitError(Translator.getNotification(oData.ErrorCode)); + this.submitError(getNotification(Notification.UnknownError)); } - } - else - { - this.submitRequest(false); - this.submitError(Translator.getNotification(Enums.Notification.UnknownError)); - } - }, this), this.login(), this.password()); + }, this.login(), this.password()); - return true; + return true; - }, function() { - return !this.submitRequest(); - }); + }, () => !this.submitRequest()); + } - kn.constructorEnd(this); + onShow() { + + routeOff(); + + _.delay(() => { + this.loginFocus(true); + }, Magics.Time100ms); + } + + onHide() { + this.loginFocus(false); + } + + onBuild() { + triggerAutocompleteInputChange(true); + } + + submitForm() { + this.submitCommand(); + } } -kn.extendAsViewModel(['View/Admin/Login', 'AdminLoginViewModel'], LoginAdminView); -_.extend(LoginAdminView.prototype, AbstractView.prototype); - -LoginAdminView.prototype.onShow = function() -{ - kn.routeOff(); - - _.delay(_.bind(function() { - this.loginFocus(true); - }, this), Enums.Magics.Time100ms); - -}; - -LoginAdminView.prototype.onHide = function() -{ - this.loginFocus(false); -}; - -LoginAdminView.prototype.onBuild = function() -{ - Utils.triggerAutocompleteInputChange(true); -}; - -LoginAdminView.prototype.submitForm = function() -{ - this.submitCommand(); -}; - -module.exports = LoginAdminView; +export {LoginAdminView, LoginAdminView as default}; diff --git a/dev/View/Admin/Settings/Menu.js b/dev/View/Admin/Settings/Menu.js index caa07fd1d..f70458a79 100644 --- a/dev/View/Admin/Settings/Menu.js +++ b/dev/View/Admin/Settings/Menu.js @@ -1,69 +1,66 @@ -var - _ = require('_'), - $ = require('$'), - key = require('key'), +import _ from '_'; +import $ from '$'; +import key from 'key'; - Globals = require('Common/Globals'), - Enums = require('Common/Enums'), +import {leftPanelDisabled} from 'Common/Globals'; +import {Magics} from 'Common/Enums'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType, setHash} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @param {?} oScreen - * - * @extends AbstractView - */ -function MenuSettingsAdminView(oScreen) +@view({ + name: 'View/Admin/Settings/Menu', + type: ViewType.Left, + templateID: 'AdminMenu' +}) +class MenuSettingsAdminView extends AbstractViewNext { - AbstractView.call(this, 'Left', 'AdminMenu'); + /** + * @param {?} screen + */ + constructor(screen) { - this.leftPanelDisabled = Globals.leftPanelDisabled; + super(); - this.menu = oScreen.menu; + this.leftPanelDisabled = leftPanelDisabled; - kn.constructorEnd(this); + this.menu = screen.menu; + } + + link(route) { + return '#/' + route; + } + + onBuild(dom) { + + key('up, down', _.throttle((event, handler) => { + + const + up = handler && 'up' === handler.shortcut, + $items = $('.b-admin-menu .e-item', dom); + + if (event && $items.length) + { + let index = $items.index($items.filter('.selected')); + if (up && 0 < index) + { + index -= 1; + } + else if (!up && index < $items.length - 1) + { + index += 1; + } + + const sH = $items.eq(index).attr('href'); + if (sH) + { + setHash(sH, false, true); + } + } + + }, Magics.Time200ms)); + } } -kn.extendAsViewModel(['View/Admin/Settings/Menu', 'AdminSettingsMenuViewModel'], MenuSettingsAdminView); -_.extend(MenuSettingsAdminView.prototype, AbstractView.prototype); - -MenuSettingsAdminView.prototype.link = function(sRoute) -{ - return '#/' + sRoute; -}; - -MenuSettingsAdminView.prototype.onBuild = function(oDom) -{ - key('up, down', _.throttle(function(event, handler) { - - var - sH = '', - bUp = handler && 'up' === handler.shortcut, - $items = $('.b-admin-menu .e-item', oDom); - - if (event && $items.length) - { - var index = $items.index($items.filter('.selected')); - if (bUp && 0 < index) - { - index -= 1; - } - else if (!bUp && index < $items.length - 1) - { - index += 1; - } - - sH = $items.eq(index).attr('href'); - if (sH) - { - kn.setHash(sH, false, true); - } - } - - }, Enums.Magics.Time200ms)); -}; - -module.exports = MenuSettingsAdminView; +export {MenuSettingsAdminView, MenuSettingsAdminView as default}; diff --git a/dev/View/Admin/Settings/Pane.js b/dev/View/Admin/Settings/Pane.js index c42ed1569..2cfbb2386 100644 --- a/dev/View/Admin/Settings/Pane.js +++ b/dev/View/Admin/Settings/Pane.js @@ -1,51 +1,55 @@ -var - _ = require('_'), - ko = require('ko'), +/* global RL_COMMUNITY */ - Settings = require('Storage/Settings'), - Remote = require('Remote/Admin/Ajax'), +import ko from 'ko'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import * as Settings from 'Storage/Settings'; -/** - * @constructor - * @extends AbstractView - */ -function PaneSettingsAdminView() +import Remote from 'Remote/Admin/Ajax'; + +import DomainStore from 'Stores/Admin/Domain'; +import PluginStore from 'Stores/Admin/Plugin'; +import PackageStore from 'Stores/Admin/Package'; + +import {getApp} from 'Helper/Apps/Admin'; + +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; + +@view({ + name: 'View/Admin/Settings/Pane', + type: ViewType.Right, + templateID: 'AdminPane' +}) +class PaneSettingsAdminView extends AbstractViewNext { - AbstractView.call(this, 'Right', 'AdminPane'); + constructor() { + super(); - this.adminDomain = ko.observable(Settings.settingsGet('AdminDomain')); - this.version = ko.observable(Settings.appSettingsGet('version')); + this.adminDomain = ko.observable(Settings.settingsGet('AdminDomain')); + this.version = ko.observable(Settings.appSettingsGet('version')); - this.capa = !!Settings.settingsGet('PremType'); - this.community = RL_COMMUNITY; + this.capa = !!Settings.settingsGet('PremType'); + this.community = RL_COMMUNITY; - this.adminManLoading = ko.computed(function() { - return '000' !== [ - require('Stores/Admin/Domain').domains.loading() ? '1' : '0', - require('Stores/Admin/Plugin').plugins.loading() ? '1' : '0', - require('Stores/Admin/Package').packages.loading() ? '1' : '0' - ].join(''); - }, this); + this.adminManLoading = ko.computed( + () => '000' !== [ + DomainStore.domains.loading() ? '1' : '0', + PluginStore.plugins.loading() ? '1' : '0', + PackageStore.packages.loading() ? '1' : '0' + ].join('') + ); - this.adminManLoadingVisibility = ko.computed(function() { - return this.adminManLoading() ? 'visible' : 'hidden'; - }, this).extend({'rateLimit': 300}); + this.adminManLoadingVisibility = ko.computed( + () => (this.adminManLoading() ? 'visible' : 'hidden') + ).extend({rateLimit: 300}); + } - kn.constructorEnd(this); + logoutClick() { + Remote.adminLogout(() => { + getApp().loginAndLogoutReload(true, true); + }); + } } -kn.extendAsViewModel(['View/Admin/Settings/Pane', 'AdminSettingsPaneViewModel'], PaneSettingsAdminView); -_.extend(PaneSettingsAdminView.prototype, AbstractView.prototype); - -PaneSettingsAdminView.prototype.logoutClick = function() -{ - Remote.adminLogout(function() { - require('App/Admin').default.loginAndLogoutReload(true, true); - }); -}; - -module.exports = PaneSettingsAdminView; +export {PaneSettingsAdminView, PaneSettingsAdminView as default}; diff --git a/dev/View/Popup/Account.js b/dev/View/Popup/Account.js index 2e0760afd..b231d9484 100644 --- a/dev/View/Popup/Account.js +++ b/dev/View/Popup/Account.js @@ -1,128 +1,121 @@ -var - _ = require('_'), - ko = require('ko'), +import ko from 'ko'; - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Translator = require('Common/Translator'), +import {StorageResultType, Notification} from 'Common/Enums'; +import {trim, createCommand} from 'Common/Utils'; +import {getNotification} from 'Common/Translator'; - Remote = require('Remote/User/Ajax'), +import Remote from 'Remote/User/Ajax'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {getApp} from 'Helper/Apps/User'; -/** - * @constructor - * @extends AbstractView - */ -function AccountPopupView() +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; + +@view({ + name: 'View/Popup/Account', + type: ViewType.Popup, + templateID: 'PopupsAccount' +}) +class AccountPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsAccount'); + constructor() { + super(); - this.isNew = ko.observable(true); + this.isNew = ko.observable(true); - this.email = ko.observable(''); - this.password = ko.observable(''); + this.email = ko.observable(''); + this.password = ko.observable(''); - this.emailError = ko.observable(false); - this.passwordError = ko.observable(false); + this.emailError = ko.observable(false); + this.passwordError = ko.observable(false); - this.email.subscribe(function() { - this.emailError(false); - }, this); + this.email.subscribe(() => { + this.emailError(false); + }); - this.password.subscribe(function() { - this.passwordError(false); - }, this); + this.password.subscribe(() => { + this.passwordError(false); + }); - this.submitRequest = ko.observable(false); - this.submitError = ko.observable(''); - this.submitErrorAdditional = ko.observable(''); + this.submitRequest = ko.observable(false); + this.submitError = ko.observable(''); + this.submitErrorAdditional = ko.observable(''); - this.emailFocus = ko.observable(false); + this.emailFocus = ko.observable(false); - this.addAccountCommand = Utils.createCommand(this, function() { + this.addAccountCommand = createCommand(() => { - this.emailError('' === Utils.trim(this.email())); - this.passwordError('' === Utils.trim(this.password())); + this.emailError('' === trim(this.email())); + this.passwordError('' === trim(this.password())); - if (this.emailError() || this.passwordError()) - { - return false; - } - - this.submitRequest(true); - - Remote.accountSetup(_.bind(function(sResult, oData) { - - this.submitRequest(false); - if (Enums.StorageResultType.Success === sResult && oData) + if (this.emailError() || this.passwordError()) { - if (oData.Result) + return false; + } + + this.submitRequest(true); + + Remote.accountSetup((result, data) => { + + this.submitRequest(false); + if (StorageResultType.Success === result && data) { - require('App/User').default.accountsAndIdentities(); - this.cancelCommand(); + if (data.Result) + { + getApp().accountsAndIdentities(); + this.cancelCommand(); + } + else + { + this.submitError(data.ErrorCode ? getNotification(data.ErrorCode) : + getNotification(Notification.UnknownError)); + + if (data.ErrorMessageAdditional) + { + this.submitErrorAdditional(data.ErrorMessageAdditional); + } + } } else { - this.submitError(oData.ErrorCode ? Translator.getNotification(oData.ErrorCode) : - Translator.getNotification(Enums.Notification.UnknownError)); - - if (oData.ErrorMessageAdditional) - { - this.submitErrorAdditional(oData.ErrorMessageAdditional); - } + this.submitError(getNotification(Notification.UnknownError)); + this.submitErrorAdditional(''); } - } - else - { - this.submitError(Translator.getNotification(Enums.Notification.UnknownError)); - this.submitErrorAdditional(''); - } - }, this), this.email(), this.password(), this.isNew()); + }, this.email(), this.password(), this.isNew()); - return true; + return true; - }, function() { - return !this.submitRequest(); - }); + }, () => !this.submitRequest()); + } - kn.constructorEnd(this); + clearPopup() { + this.isNew(true); + + this.email(''); + this.password(''); + + this.emailError(false); + this.passwordError(false); + + this.submitRequest(false); + this.submitError(''); + this.submitErrorAdditional(''); + } + + onShow(account) { + this.clearPopup(); + if (account && account.canBeEdit()) + { + this.isNew(false); + this.email(account.email); + } + } + + onShowWithDelay() { + this.emailFocus(true); + } } -kn.extendAsViewModel(['View/Popup/Account', 'View/Popup/AddAccount', 'PopupsAddAccountViewModel'], AccountPopupView); -_.extend(AccountPopupView.prototype, AbstractView.prototype); - -AccountPopupView.prototype.clearPopup = function() -{ - this.isNew(true); - - this.email(''); - this.password(''); - - this.emailError(false); - this.passwordError(false); - - this.submitRequest(false); - this.submitError(''); - this.submitErrorAdditional(''); -}; - -AccountPopupView.prototype.onShow = function(oAccount) -{ - this.clearPopup(); - if (oAccount && oAccount.canBeEdit()) - { - this.isNew(false); - this.email(oAccount.email); - } -}; - -AccountPopupView.prototype.onShowWithDelay = function() -{ - this.emailFocus(true); -}; - module.exports = AccountPopupView; diff --git a/dev/View/Popup/Activate.js b/dev/View/Popup/Activate.js index 5ab3f5b63..06a0ba353 100644 --- a/dev/View/Popup/Activate.js +++ b/dev/View/Popup/Activate.js @@ -1,143 +1,130 @@ -var - _ = require('_'), - ko = require('ko'), +import ko from 'ko'; - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Consts = require('Common/Consts'), - Translator = require('Common/Translator'), +import {StorageResultType, Notification} from 'Common/Enums'; +import {trim, isUnd, createCommand} from 'Common/Utils'; +import {RAINLOOP_TRIAL_KEY} from 'Common/Consts'; +import {i18n, getNotification} from 'Common/Translator'; - Settings = require('Storage/Settings'), - Remote = require('Remote/Admin/Ajax'), +import * as Settings from 'Storage/Settings'; - LicenseStore = require('Stores/Admin/License'), +import Remote from 'Remote/Admin/Ajax'; +import LicenseStore from 'Stores/Admin/License'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function ActivatePopupView() +@view({ + name: 'View/Popup/Activate', + type: ViewType.Popup, + templateID: 'PopupsActivate' +}) +class ActivatePopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsActivate'); + constructor() { + super(); - var self = this; + this.domain = ko.observable(''); + this.key = ko.observable(''); + this.key.focus = ko.observable(false); + this.activationSuccessed = ko.observable(false); - this.domain = ko.observable(''); - this.key = ko.observable(''); - this.key.focus = ko.observable(false); - this.activationSuccessed = ko.observable(false); + this.licenseTrigger = LicenseStore.licenseTrigger; - this.licenseTrigger = LicenseStore.licenseTrigger; + this.activateProcess = ko.observable(false); + this.activateText = ko.observable(''); + this.activateText.isError = ko.observable(false); - this.activateProcess = ko.observable(false); - this.activateText = ko.observable(''); - this.activateText.isError = ko.observable(false); + this.htmlDescription = ko.computed(() => i18n('POPUPS_ACTIVATE/HTML_DESC', {'DOMAIN': this.domain()})); - this.htmlDescription = ko.computed(function() { - return Translator.i18n('POPUPS_ACTIVATE/HTML_DESC', {'DOMAIN': this.domain()}); - }, this); + this.key.subscribe(() => { + this.activateText(''); + this.activateText.isError(false); + }); - this.key.subscribe(function() { - this.activateText(''); - this.activateText.isError(false); - }, this); + this.activationSuccessed.subscribe((value) => { + if (value) + { + this.licenseTrigger(!this.licenseTrigger()); + } + }); - this.activationSuccessed.subscribe(function(bValue) { - if (bValue) - { - this.licenseTrigger(!this.licenseTrigger()); - } - }, this); + this.activateCommand = createCommand(() => { - this.activateCommand = Utils.createCommand(this, function() { + this.activateProcess(true); + if (this.validateSubscriptionKey()) + { + Remote.licensingActivate((sResult, oData) => { - this.activateProcess(true); - if (this.validateSubscriptionKey()) - { - Remote.licensingActivate(function(sResult, oData) { - - self.activateProcess(false); - if (Enums.StorageResultType.Success === sResult && oData.Result) - { - if (true === oData.Result) + this.activateProcess(false); + if (StorageResultType.Success === sResult && oData.Result) { - self.activationSuccessed(true); - self.activateText(Translator.i18n('POPUPS_ACTIVATE/SUBS_KEY_ACTIVATED')); - self.activateText.isError(false); + if (true === oData.Result) + { + this.activationSuccessed(true); + this.activateText(i18n('POPUPS_ACTIVATE/SUBS_KEY_ACTIVATED')); + this.activateText.isError(false); + } + else + { + this.activateText(oData.Result); + this.activateText.isError(true); + this.key.focus(true); + } + } + else if (oData.ErrorCode) + { + this.activateText(getNotification(oData.ErrorCode)); + this.activateText.isError(true); + this.key.focus(true); } else { - self.activateText(oData.Result); - self.activateText.isError(true); - self.key.focus(true); + this.activateText(getNotification(Notification.UnknownError)); + this.activateText.isError(true); + this.key.focus(true); } - } - else if (oData.ErrorCode) - { - self.activateText(Translator.getNotification(oData.ErrorCode)); - self.activateText.isError(true); - self.key.focus(true); - } - else - { - self.activateText(Translator.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(i18n('POPUPS_ACTIVATE/ERROR_INVALID_SUBS_KEY')); + this.activateText.isError(true); + this.key.focus(true); + } + + }, () => !this.activateProcess() && '' !== this.domain() && '' !== this.key() && !this.activationSuccessed()); + } + + onShow(isTrial) { + this.domain(Settings.settingsGet('AdminDomain')); + if (!this.activateProcess()) + { + isTrial = isUnd(isTrial) ? false : !!isTrial; + + this.key(isTrial ? RAINLOOP_TRIAL_KEY : ''); + this.activateText(''); + this.activateText.isError(false); + this.activationSuccessed(false); + } + } + + onShowWithDelay() { + if (!this.activateProcess()) { - this.activateProcess(false); - this.activateText(Translator.i18n('POPUPS_ACTIVATE/ERROR_INVALID_SUBS_KEY')); - this.activateText.isError(true); this.key.focus(true); } + } - }, function() { - return !this.activateProcess() && '' !== this.domain() && '' !== this.key() && !this.activationSuccessed(); - }); - - kn.constructorEnd(this); + /** + * @returns {boolean} + */ + validateSubscriptionKey() { + const value = this.key(); + return '' === value || RAINLOOP_TRIAL_KEY === value || !!(/^RL[\d]+-[A-Z0-9\-]+Z$/).test(trim(value)); + } } -kn.extendAsViewModel(['View/Popup/Activate', 'PopupsActivateViewModel'], ActivatePopupView); -_.extend(ActivatePopupView.prototype, AbstractView.prototype); - -ActivatePopupView.prototype.onShow = function(bTrial) -{ - this.domain(Settings.settingsGet('AdminDomain')); - if (!this.activateProcess()) - { - bTrial = Utils.isUnd(bTrial) ? false : !!bTrial; - - this.key(bTrial ? Consts.RAINLOOP_TRIAL_KEY : ''); - this.activateText(''); - this.activateText.isError(false); - this.activationSuccessed(false); - } -}; - -ActivatePopupView.prototype.onShowWithDelay = function() -{ - if (!this.activateProcess()) - { - this.key.focus(true); - } -}; - -/** - * @returns {boolean} - */ -ActivatePopupView.prototype.validateSubscriptionKey = function() -{ - var sValue = this.key(); - return '' === sValue || Consts.RAINLOOP_TRIAL_KEY === sValue || !!(/^RL[\d]+-[A-Z0-9\-]+Z$/).test(Utils.trim(sValue)); -}; - module.exports = ActivatePopupView; diff --git a/dev/View/Popup/AddOpenPgpKey.js b/dev/View/Popup/AddOpenPgpKey.js index 1a098caaa..7c3ccbd35 100644 --- a/dev/View/Popup/AddOpenPgpKey.js +++ b/dev/View/Popup/AddOpenPgpKey.js @@ -1,108 +1,122 @@ -var - _ = require('_'), - ko = require('ko'), +import ko from 'ko'; +import {trim, delegateRun, createCommand, log} from 'Common/Utils'; - Utils = require('Common/Utils'), +import PgpStore from 'Stores/User/Pgp'; - PgpStore = require('Stores/User/Pgp'), +import {getApp} from 'Helper/Apps/User'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function AddOpenPgpKeyPopupView() +@view({ + name: 'View/Popup/AddOpenPgpKey', + type: ViewType.Popup, + templateID: 'PopupsAddOpenPgpKey' +}) +class AddOpenPgpKeyPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsAddOpenPgpKey'); + constructor() { + super(); - this.key = ko.observable(''); - this.key.error = ko.observable(false); - this.key.focus = ko.observable(false); + this.key = ko.observable(''); + this.key.focus = ko.observable(false); + this.key.error = ko.observable(false); + this.key.errorMessage = ko.observable(''); - this.key.subscribe(function() { - this.key.error(false); - }, this); + this.key.subscribe(() => { + this.key.error(false); + this.key.errorMessage(''); + }); - this.addOpenPgpKeyCommand = Utils.createCommand(this, function() { + this.addOpenPgpKeyCommand = createCommand(() => { - var - count = 30, - keyTrimmed = Utils.trim(this.key()), - reg = /[\-]{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, - openpgpKeyring = PgpStore.openpgpKeyring; + const + reg = /[\-]{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, + openpgpKeyring = PgpStore.openpgpKeyring; - if (/[\n]/.test(keyTrimmed)) - { - keyTrimmed = keyTrimmed.replace(/[\r]+/g, '').replace(/[\n]{2,}/g, '\n\n'); - } + let keyTrimmed = trim(this.key()); - this.key.error('' === keyTrimmed); - - if (!openpgpKeyring || this.key.error()) - { - return false; - } - - var done = false; - - do - { - var match = reg.exec(keyTrimmed); - if (match && 0 < count) + if (/[\n]/.test(keyTrimmed)) { - if (match[0] && match[1] && match[2] && match[1] === match[2]) - { - if ('PRIVATE' === match[1]) - { - openpgpKeyring.privateKeys.importKey(match[0]); - } - else if ('PUBLIC' === match[1]) - { - openpgpKeyring.publicKeys.importKey(match[0]); - } - } + keyTrimmed = keyTrimmed.replace(/[\r]+/g, '').replace(/[\n]{2,}/g, '\n\n'); + } - count -= 1; + this.key.error('' === keyTrimmed); + this.key.errorMessage(''); + + if (!openpgpKeyring || this.key.error()) + { + return false; + } + + let + match = null, + count = 30, done = false; - } - else + + do { - done = true; + match = reg.exec(keyTrimmed); + if (match && 0 < count) + { + if (match[0] && match[1] && match[2] && match[1] === match[2]) + { + let err = null; + if ('PRIVATE' === match[1]) + { + err = openpgpKeyring.privateKeys.importKey(match[0]); + } + else if ('PUBLIC' === match[1]) + { + err = openpgpKeyring.publicKeys.importKey(match[0]); + } + + if (err) + { + this.key.error(true); + this.key.errorMessage(err && err[0] ? '' + err[0] : ''); + log(err); + } + } + + count -= 1; + done = false; + } + else + { + done = true; + } } - } - while (!done); + while (!done); - openpgpKeyring.store(); + openpgpKeyring.store(); - require('App/User').default.reloadOpenPgpKeys(); - Utils.delegateRun(this, 'cancelCommand'); + getApp().reloadOpenPgpKeys(); - return true; - }); + if (this.key.error()) + { + return false; + } - kn.constructorEnd(this); + delegateRun(this, 'cancelCommand'); + return true; + }); + } + + clearPopup() { + this.key(''); + this.key.error(false); + this.key.errorMessage(''); + } + + onShow() { + this.clearPopup(); + } + + onShowWithDelay() { + this.key.focus(true); + } } -kn.extendAsViewModel(['View/Popup/AddOpenPgpKey', 'PopupsAddOpenPgpKeyViewModel'], AddOpenPgpKeyPopupView); -_.extend(AddOpenPgpKeyPopupView.prototype, AbstractView.prototype); - -AddOpenPgpKeyPopupView.prototype.clearPopup = function() -{ - this.key(''); - this.key.error(false); -}; - -AddOpenPgpKeyPopupView.prototype.onShow = function() -{ - this.clearPopup(); -}; - -AddOpenPgpKeyPopupView.prototype.onShowWithDelay = function() -{ - this.key.focus(true); -}; - module.exports = AddOpenPgpKeyPopupView; diff --git a/dev/View/Popup/AdvancedSearch.js b/dev/View/Popup/AdvancedSearch.js index 3a1ae4a75..0044b8bc9 100644 --- a/dev/View/Popup/AdvancedSearch.js +++ b/dev/View/Popup/AdvancedSearch.js @@ -1,187 +1,174 @@ -var - _ = require('_'), - ko = require('ko'), +import _ from '_'; +import ko from 'ko'; - Utils = require('Common/Utils'), - Translator = require('Common/Translator'), +import {trim, createCommand} from 'Common/Utils'; +import {i18n, trigger as translatorTrigger} from 'Common/Translator'; +import {searchSubtractFormatDateHelper} from 'Common/Momentor'; - MessageStore = require('Stores/User/Message'), +import MessageStore from 'Stores/User/Message'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function AdvancedSearchPopupView() +@view({ + name: 'View/Popup/AdvancedSearch', + type: ViewType.Popup, + templateID: 'PopupsAdvancedSearch' +}) +class AdvancedSearchPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsAdvancedSearch'); + constructor() { + super(); - this.fromFocus = ko.observable(false); + 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.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.hasAttachment = ko.observable(false); + this.starred = ko.observable(false); + this.unseen = ko.observable(false); - this.searchCommand = Utils.createCommand(this, function() { + this.searchCommand = createCommand(() => { + const search = this.buildSearchString(); + if ('' !== search) + { + MessageStore.mainMessageListSearch(search); + } - var sSearch = this.buildSearchString(); - if ('' !== sSearch) + this.cancelCommand(); + }); + + this.selectedDates = ko.computed(() => { + translatorTrigger(); + return [ + {id: -1, name: i18n('SEARCH/LABEL_ADV_DATE_ALL')}, + {id: 3, name: i18n('SEARCH/LABEL_ADV_DATE_3_DAYS')}, + {id: 7, name: i18n('SEARCH/LABEL_ADV_DATE_7_DAYS')}, + {id: 30, name: i18n('SEARCH/LABEL_ADV_DATE_MONTH')}, + {id: 90, name: i18n('SEARCH/LABEL_ADV_DATE_3_MONTHS')}, + {id: 180, name: i18n('SEARCH/LABEL_ADV_DATE_6_MONTHS')}, + {id: 365, name: i18n('SEARCH/LABEL_ADV_DATE_YEAR')} + ]; + }); + } + + parseSearchStringValue(search) { + const parts = (search || '').split(/[\s]+/g); + _.each(parts, (part) => { + switch (part) + { + case 'has:attachment': + this.hasAttachment(true); + break; + case 'is:unseen,flagged': + this.starred(true); + /* falls through */ + case 'is:unseen': + this.unseen(true); + break; + // no default + } + }); + } + + buildSearchStringValue(value) { + if (-1 < value.indexOf(' ')) { - MessageStore.mainMessageListSearch(sSearch); + value = '"' + value + '"'; + } + return value; + } + + buildSearchString() { + const + result = [], + from_ = trim(this.from()), + to = trim(this.to()), + subject = trim(this.subject()), + text = trim(this.text()), + isPart = [], + hasPart = []; + + if (from_ && '' !== from_) + { + result.push('from:' + this.buildSearchStringValue(from_)); } - this.cancelCommand(); - }); + if (to && '' !== to) + { + result.push('to:' + this.buildSearchStringValue(to)); + } - this.selectedDates = ko.computed(function() { - Translator.trigger(); - return [ - {'id': -1, 'name': Translator.i18n('SEARCH/LABEL_ADV_DATE_ALL')}, - {'id': 3, 'name': Translator.i18n('SEARCH/LABEL_ADV_DATE_3_DAYS')}, - {'id': 7, 'name': Translator.i18n('SEARCH/LABEL_ADV_DATE_7_DAYS')}, - {'id': 30, 'name': Translator.i18n('SEARCH/LABEL_ADV_DATE_MONTH')}, - {'id': 90, 'name': Translator.i18n('SEARCH/LABEL_ADV_DATE_3_MONTHS')}, - {'id': 180, 'name': Translator.i18n('SEARCH/LABEL_ADV_DATE_6_MONTHS')}, - {'id': 365, 'name': Translator.i18n('SEARCH/LABEL_ADV_DATE_YEAR')} - ]; - }, this); + if (subject && '' !== subject) + { + result.push('subject:' + this.buildSearchStringValue(subject)); + } - kn.constructorEnd(this); + if (this.hasAttachment()) + { + hasPart.push('attachment'); + } + + if (this.unseen()) + { + isPart.push('unseen'); + } + + if (this.starred()) + { + isPart.push('flagged'); + } + + if (0 < hasPart.length) + { + result.push('has:' + hasPart.join(',')); + } + + if (0 < isPart.length) + { + result.push('is:' + isPart.join(',')); + } + + if (-1 < this.selectedDateValue()) + { + result.push('date:' + searchSubtractFormatDateHelper(this.selectedDateValue()) + '/'); + } + + if (text && '' !== text) + { + result.push('text:' + this.buildSearchStringValue(text)); + } + + return trim(result.join(' ')); + } + + clearPopup() { + this.from(''); + this.to(''); + this.subject(''); + this.text(''); + + this.selectedDateValue(-1); + this.hasAttachment(false); + this.starred(false); + this.unseen(false); + + this.fromFocus(true); + } + + onShow(search) { + this.clearPopup(); + this.parseSearchStringValue(search); + } + + onShowWithDelay() { + this.fromFocus(true); + } } -kn.extendAsViewModel(['View/Popup/AdvancedSearch', 'PopupsAdvancedSearchViewModel'], AdvancedSearchPopupView); -_.extend(AdvancedSearchPopupView.prototype, AbstractView.prototype); - -AdvancedSearchPopupView.prototype.parseSearchStringValue = function(search) -{ - var - self = this, - parts = (search || '').split(/[\s]+/g); - - _.each(parts, function(part) { - switch (part) - { - case 'has:attachment': - self.hasAttachment(true); - break; - case 'is:unseen,flagged': - self.starred(true); - /* falls through */ - case 'is:unseen': - self.unseen(true); - break; - // no default - } - }); -}; - -AdvancedSearchPopupView.prototype.buildSearchStringValue = function(sValue) -{ - if (-1 < sValue.indexOf(' ')) - { - sValue = '"' + sValue + '"'; - } - - return sValue; -}; - -AdvancedSearchPopupView.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 = []; - - 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:' + require('Common/Momentor').searchSubtractFormatDateHelper(this.selectedDateValue()) + '/'); - } - - if (sText && '' !== sText) - { - aResult.push('text:' + this.buildSearchStringValue(sText)); - } - - return Utils.trim(aResult.join(' ')); -}; - -AdvancedSearchPopupView.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); -}; - -AdvancedSearchPopupView.prototype.onShow = function(search) -{ - this.clearPopup(); - this.parseSearchStringValue(search); -}; - -AdvancedSearchPopupView.prototype.onShowWithDelay = function() -{ - this.fromFocus(true); -}; - module.exports = AdvancedSearchPopupView; diff --git a/dev/View/Popup/Ask.js b/dev/View/Popup/Ask.js index eb8daf22f..e92f55b2e 100644 --- a/dev/View/Popup/Ask.js +++ b/dev/View/Popup/Ask.js @@ -1,134 +1,125 @@ -var - _ = require('_'), - ko = require('ko'), - key = require('key'), +import ko from 'ko'; +import key from 'key'; - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Translator = require('Common/Translator'), +import {KeyState} from 'Common/Enums'; +import {isFunc} from 'Common/Utils'; +import {i18n} from 'Common/Translator'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function AskPopupView() +@view({ + name: 'View/Popup/Ask', + type: ViewType.Popup, + templateID: 'PopupsAsk' +}) +class AskPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsAsk'); + constructor() { + super(); - this.askDesc = ko.observable(''); - this.yesButton = ko.observable(''); - this.noButton = ko.observable(''); + this.askDesc = ko.observable(''); + this.yesButton = ko.observable(''); + this.noButton = ko.observable(''); - this.yesFocus = ko.observable(false); - this.noFocus = ko.observable(false); + this.yesFocus = ko.observable(false); + this.noFocus = ko.observable(false); - this.fYesAction = null; - this.fNoAction = null; + this.fYesAction = null; + this.fNoAction = null; - this.bFocusYesOnShow = true; - this.bDisabeCloseOnEsc = true; - this.sDefaultKeyScope = Enums.KeyState.PopupAsk; - - kn.constructorEnd(this); -} - -kn.extendAsViewModel(['View/Popup/Ask', 'PopupsAskViewModel'], AskPopupView); -_.extend(AskPopupView.prototype, AbstractView.prototype); - -AskPopupView.prototype.clearPopup = function() -{ - this.askDesc(''); - this.yesButton(Translator.i18n('POPUPS_ASK/BUTTON_YES')); - this.noButton(Translator.i18n('POPUPS_ASK/BUTTON_NO')); - - this.yesFocus(false); - this.noFocus(false); - - this.fYesAction = null; - this.fNoAction = null; -}; - -AskPopupView.prototype.yesClick = function() -{ - this.cancelCommand(); - - if (Utils.isFunc(this.fYesAction)) - { - this.fYesAction.call(null); - } -}; - -AskPopupView.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 - * @param {boolean=} bFocusYesOnShow - * @returns {void} - */ -AskPopupView.prototype.onShow = function(sAskDesc, fYesFunc, fNoFunc, sYesButton, sNoButton, bFocusYesOnShow) -{ - this.clearPopup(); - - this.fYesAction = fYesFunc || null; - this.fNoAction = fNoFunc || null; - - this.askDesc(sAskDesc || ''); - - if (sYesButton) - { - this.yesButton(sYesButton); + this.bFocusYesOnShow = true; + this.bDisabeCloseOnEsc = true; + this.sDefaultKeyScope = KeyState.PopupAsk; } - if (sNoButton) - { - this.noButton(sNoButton); + clearPopup() { + this.askDesc(''); + this.yesButton(i18n('POPUPS_ASK/BUTTON_YES')); + this.noButton(i18n('POPUPS_ASK/BUTTON_NO')); + + this.yesFocus(false); + this.noFocus(false); + + this.fYesAction = null; + this.fNoAction = null; } - this.bFocusYesOnShow = Utils.isUnd(bFocusYesOnShow) ? true : !!bFocusYesOnShow; -}; + yesClick() { + this.cancelCommand(); -AskPopupView.prototype.onShowWithDelay = function() -{ - if (this.bFocusYesOnShow) - { - this.yesFocus(true); - } -}; - -AskPopupView.prototype.onBuild = function() -{ - key('tab, shift+tab, right, left', Enums.KeyState.PopupAsk, _.bind(function() { - if (this.yesFocus()) + if (isFunc(this.fYesAction)) { - this.noFocus(true); + this.fYesAction.call(null); } - else + } + + noClick() { + this.cancelCommand(); + + if (isFunc(this.fNoAction)) + { + this.fNoAction.call(null); + } + } + + /** + * @param {string} sAskDesc + * @param {Function=} fYesFunc + * @param {Function=} fNoFunc + * @param {string=} sYesButton + * @param {string=} sNoButton + * @param {boolean=} bFocusYesOnShow = true + * @returns {void} + */ + onShow(askDesc, fYesFunc = null, fNoFunc = null, yesButton = '', noButton = '', isFocusYesOnShow = true) { + + this.clearPopup(); + + this.fYesAction = fYesFunc || null; + this.fNoAction = fNoFunc || null; + + this.askDesc(askDesc || ''); + + if (yesButton) + { + this.yesButton(yesButton); + } + + if (noButton) + { + this.noButton(noButton); + } + + this.bFocusYesOnShow = !!isFocusYesOnShow; + } + + onShowWithDelay() { + if (this.bFocusYesOnShow) { this.yesFocus(true); } - return false; - }, this)); + } - key('esc', Enums.KeyState.PopupAsk, _.bind(function() { - this.noClick(); - return false; - }, this)); -}; + onBuild() { + key('tab, shift+tab, right, left', KeyState.PopupAsk, () => { + if (this.yesFocus()) + { + this.noFocus(true); + } + else + { + this.yesFocus(true); + } + return false; + }); + + key('esc', KeyState.PopupAsk, () => { + this.noClick(); + return false; + }); + } +} module.exports = AskPopupView; diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js index c2a428a2e..d29995c82 100644 --- a/dev/View/Popup/Compose.js +++ b/dev/View/Popup/Compose.js @@ -1,2121 +1,1994 @@ -var - window = require('window'), - _ = require('_'), - $ = require('$'), - ko = require('ko'), - key = require('key'), - Jua = require('Jua'), +import window from 'window'; +import _ from '_'; +import $ from '$'; +import ko from 'ko'; +import key from 'key'; +import Jua from 'Jua'; - Enums = require('Common/Enums'), - Consts = require('Common/Consts'), - Utils = require('Common/Utils'), - Globals = require('Common/Globals'), - Events = require('Common/Events'), - Links = require('Common/Links'), - HtmlEditor = require('Common/HtmlEditor').default, +import { + Capa, Magics, KeyState, ComposeType, StorageResultType, + EditorDefaultType, Notification, SetSystemFoldersNotification, + UploadErrorCode +} from 'Common/Enums'; - Translator = require('Common/Translator'), - Momentor = require('Common/Momentor'), +import { + trim, isArray, isNormal, createCommand, delegateRun, + isNonEmptyArray, clearBqSwitcher, replySubjectAdd, + encodeHtml, noopFalse, inFocus, delegateRunOnDestroy, + pInt, isUnd +} from 'Common/Utils'; - Cache = require('Common/Cache'), +import {UNUSED_OPTION_VALUE} from 'Common/Consts'; +import {bXMLHttpRequestSupported, bMobileDevice} from 'Common/Globals'; +import {upload} from 'Common/Links'; +import {i18n, getNotification, getUploadErrorDescByCode} from 'Common/Translator'; +import {format as momentorFormat} from 'Common/Momentor'; +import {getMessageFlagsFromCache, setMessageFlagsToCache, setFolderHash} from 'Common/Cache'; - AppStore = require('Stores/User/App'), - SettingsStore = require('Stores/User/Settings'), - IdentityStore = require('Stores/User/Identity'), - AccountStore = require('Stores/User/Account'), - FolderStore = require('Stores/User/Folder'), - PgpStore = require('Stores/User/Pgp'), - MessageStore = require('Stores/User/Message'), - SocialStore = require('Stores/Social'), +import {HtmlEditor} from 'Common/HtmlEditor'; - Settings = require('Storage/Settings'), - Remote = require('Remote/User/Ajax'), +import AppStore from 'Stores/User/App'; +import SettingsStore from 'Stores/User/Settings'; +import IdentityStore from 'Stores/User/Identity'; +import AccountStore from 'Stores/User/Account'; +import FolderStore from 'Stores/User/Folder'; +import PgpStore from 'Stores/User/Pgp'; +import MessageStore from 'Stores/User/Message'; +import SocialStore from 'Stores/Social'; - ComposeAttachmentModel = require('Model/ComposeAttachment').default, +import Remote from 'Remote/User/Ajax'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import * as Settings from 'Storage/Settings'; +import * as Events from 'Common/Events'; -/** - * @constructor - * @extends AbstractView - */ -function ComposePopupView() +import {ComposeAttachmentModel} from 'Model/ComposeAttachment'; + +import {getApp} from 'Helper/Apps/User'; + +import {view, ViewType, isPopupVisible, showScreenPopup, hideScreenPopup, routeOn, routeOff} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; + +@view({ + name: 'View/Popup/Compose', + type: ViewType.Popup, + templateID: 'PopupsCompose' +}) +class ComposePopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsCompose'); + constructor() { + super(); - var - self = this, - fEmailOutInHelper = function(context, oIdentity, sName, bIn) { - if (oIdentity && context && oIdentity[sName]() && (bIn ? true : context[sName]())) - { - var - sIdentityEmail = oIdentity[sName](), - aList = Utils.trim(context[sName]()).split(/[,]/); - - aList = _.filter(aList, function(sEmail) { - sEmail = Utils.trim(sEmail); - return sEmail && Utils.trim(sIdentityEmail) !== sEmail; - }); - - if (bIn) + const + fEmailOutInHelper = (context, identity, name, isIn) => { + if (identity && context && identity[name]() && (isIn ? true : context[name]())) { - aList.push(sIdentityEmail); - } + const identityEmail = identity[name](); + let list = trim(context[name]()).split(/[,]/); - context[sName](aList.join(',')); - } - }; + list = _.filter(list, (email) => { + email = trim(email); + return email && trim(identityEmail) !== email; + }); - this.oLastMessage = null; - this.oEditor = null; - this.aDraftInfo = null; - this.sInReplyTo = ''; - this.bFromDraft = false; - this.sReferences = ''; - - this.sLastFocusedField = 'to'; - - this.resizerTrigger = _.bind(this.resizerTrigger, this); - - this.allowContacts = !!AppStore.contactsIsAllowed(); - this.allowFolders = !!Settings.capa(Enums.Capa.Folders); - - this.bSkipNextHide = false; - this.composeInEdit = AppStore.composeInEdit; - this.editorDefaultType = SettingsStore.editorDefaultType; - - this.capaOpenPGP = PgpStore.capaOpenPGP; - - this.identitiesDropdownTrigger = ko.observable(false); - - this.to = ko.observable(''); - this.to.focused = ko.observable(false); - this.cc = ko.observable(''); - this.cc.focused = ko.observable(false); - this.bcc = ko.observable(''); - this.bcc.focused = ko.observable(false); - this.replyTo = ko.observable(''); - this.replyTo.focused = ko.observable(false); - - ko.computed(function() { - switch (true) - { - case this.to.focused(): - this.sLastFocusedField = 'to'; - break; - case this.cc.focused(): - this.sLastFocusedField = 'cc'; - break; - case this.bcc.focused(): - this.sLastFocusedField = 'bcc'; - break; - // no default - } - }, this).extend({'notify': 'always'}); - - this.subject = ko.observable(''); - this.subject.focused = ko.observable(false); - - this.isHtml = ko.observable(false); - - this.requestDsn = ko.observable(false); - this.requestReadReceipt = ko.observable(false); - this.markAsImportant = ko.observable(false); - - this.sendError = ko.observable(false); - this.sendSuccessButSaveError = ko.observable(false); - this.savedError = ko.observable(false); - - this.sendButtonSuccess = ko.computed(function() { - return !this.sendError() && !this.sendSuccessButSaveError(); - }, this); - - this.sendErrorDesc = ko.observable(''); - this.savedErrorDesc = ko.observable(''); - - this.sendError.subscribe(function(bValue) { - if (!bValue) - { - this.sendErrorDesc(''); - } - }, this); - - this.savedError.subscribe(function(bValue) { - if (!bValue) - { - this.savedErrorDesc(''); - } - }, this); - - this.sendSuccessButSaveError.subscribe(function(bValue) { - if (!bValue) - { - this.savedErrorDesc(''); - } - }, this); - - this.savedTime = ko.observable(0); - this.savedTimeText = ko.computed(function() { - return 0 < this.savedTime() ? Translator.i18n('COMPOSE/SAVED_TIME', { - 'TIME': Momentor.format(this.savedTime() - 1, 'LT') - }) : ''; - }, this); - - this.emptyToError = ko.observable(false); - this.emptyToErrorTooltip = ko.computed(function() { - return this.emptyToError() ? Translator.i18n('COMPOSE/EMPTY_TO_ERROR_DESC') : ''; - }, this); - - this.attachmentsInProcessError = ko.observable(false); - this.attachmentsInErrorError = ko.observable(false); - - this.attachmentsErrorTooltip = ko.computed(function() { - - var sResult = ''; - switch (true) - { - case this.attachmentsInProcessError(): - sResult = Translator.i18n('COMPOSE/ATTACHMENTS_UPLOAD_ERROR_DESC'); - break; - case this.attachmentsInErrorError(): - sResult = Translator.i18n('COMPOSE/ATTACHMENTS_ERROR_DESC'); - break; - // no default - } - - return sResult; - - }, this); - - this.showCc = ko.observable(false); - this.showBcc = ko.observable(false); - this.showReplyTo = ko.observable(false); - - this.cc.subscribe(function(aValue) { - if (false === self.showCc() && 0 < aValue.length) - { - self.showCc(true); - } - }, this); - - this.bcc.subscribe(function(aValue) { - if (false === self.showBcc() && 0 < aValue.length) - { - self.showBcc(true); - } - }, this); - - this.replyTo.subscribe(function(aValue) { - if (false === self.showReplyTo() && 0 < aValue.length) - { - self.showReplyTo(true); - } - }, this); - - this.draftFolder = ko.observable(''); - this.draftUid = ko.observable(''); - this.sending = ko.observable(false); - this.saving = ko.observable(false); - this.attachments = ko.observableArray([]); - - this.attachmentsInProcess = this.attachments.filter(function(oItem) { - return oItem && !oItem.complete(); - }); - - this.attachmentsInReady = this.attachments.filter(function(oItem) { - return oItem && oItem.complete(); - }); - - this.attachmentsInError = this.attachments.filter(function(oItem) { - return oItem && '' !== oItem.error(); - }); - - this.attachmentsCount = ko.computed(function() { - return this.attachments().length; - }, this); - - this.attachmentsInErrorCount = ko.computed(function() { - return this.attachmentsInError().length; - }, this); - - this.attachmentsInProcessCount = ko.computed(function() { - return this.attachmentsInProcess().length; - }, this); - - this.isDraftFolderMessage = ko.computed(function() { - return '' !== this.draftFolder() && '' !== this.draftUid(); - }, this); - - this.attachmentsPlace = ko.observable(false); - - this.attachments.subscribe(this.resizerTrigger); - this.attachmentsPlace.subscribe(this.resizerTrigger); - - this.attachmentsInErrorCount.subscribe(function(iN) { - if (0 === iN) - { - this.attachmentsInErrorError(false); - } - }, this); - - 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 = IdentityStore.identities; - this.identitiesOptions = ko.computed(function() { - return _.map(IdentityStore.identities(), function(oItem) { - return { - 'item': oItem, - 'optValue': oItem.id(), - 'optText': oItem.formattedName() - }; - }); - }, this); - - this.currentIdentity = ko.observable( - this.identities()[0] ? this.identities()[0] : null); - - this.currentIdentity.extend({'toggleSubscribe': [this, - function(oIdentity) { - fEmailOutInHelper(this, oIdentity, 'bcc'); - fEmailOutInHelper(this, oIdentity, 'replyTo'); - }, function(oIdentity) { - fEmailOutInHelper(this, oIdentity, 'bcc', true); - fEmailOutInHelper(this, oIdentity, 'replyTo', true); - } - ]}); - - this.currentIdentityView = ko.computed(function() { - var oItem = this.currentIdentity(); - return oItem ? oItem.formattedName() : 'unknown'; - }, 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.resizer = ko.observable(false).extend({'throttle': 50}); - - this.resizer.subscribe(_.bind(function() { - if (this.oEditor) { - this.oEditor.resize(); - } - }, this)); - - this.canBeSentOrSaved = ko.computed(function() { - return !this.sending() && !this.saving(); - }, this); - - this.deleteCommand = Utils.createCommand(this, function() { - - var - PopupsAskViewModel = require('View/Popup/Ask'); - - if (!kn.isPopupVisible(PopupsAskViewModel) && this.modalVisibility()) - { - kn.showScreenPopup(PopupsAskViewModel, [Translator.i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'), function() { - if (self.modalVisibility()) - { - require('App/User').default.deleteMessagesFromFolderWithoutCheck(self.draftFolder(), [self.draftUid()]); - kn.hideScreenPopup(ComposePopupView); - } - }]); - } - - }, 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()), - sCc = Utils.trim(this.cc()), - sBcc = Utils.trim(this.bcc()), - sSentFolder = FolderStore.sentFolder(); - - this.attachmentsInProcessError(false); - this.attachmentsInErrorError(false); - this.emptyToError(false); - - if (0 < this.attachmentsInProcess().length) - { - this.attachmentsInProcessError(true); - this.attachmentsPlace(true); - } - else if (0 < this.attachmentsInError().length) - { - this.attachmentsInErrorError(true); - this.attachmentsPlace(true); - } - - if ('' === sTo && '' === sCc && '' === sBcc) - { - this.emptyToError(true); - } - - if (!this.emptyToError() && !this.attachmentsInErrorError() && !this.attachmentsInProcessError()) - { - if (SettingsStore.replySameFolder()) - { - if (Utils.isArray(this.aDraftInfo) && 3 === this.aDraftInfo.length && Utils.isNormal(this.aDraftInfo[2]) && 0 < this.aDraftInfo[2].length) - { - sSentFolder = this.aDraftInfo[2]; - } - } - - if (!this.allowFolders) - { - sSentFolder = Consts.UNUSED_OPTION_VALUE; - } - - if ('' === sSentFolder) - { - kn.showScreenPopup(require('View/Popup/FolderSystem'), [Enums.SetSystemFoldersNotification.Sent]); - } - else - { - this.sendError(false); - this.sending(true); - - if (Utils.isArray(this.aDraftInfo) && 3 === this.aDraftInfo.length) - { - var aFlagsCache = Cache.getMessageFlagsFromCache(this.aDraftInfo[2], this.aDraftInfo[1]); - if (aFlagsCache) + if (isIn) { - if ('forward' === this.aDraftInfo[0]) - { - aFlagsCache[3] = true; - } - else - { - aFlagsCache[2] = true; - } + list.push(identityEmail); + } - Cache.setMessageFlagsToCache(this.aDraftInfo[2], this.aDraftInfo[1], aFlagsCache); - require('App/User').default.reloadFlagsCurrentMessageListAndMessageFromCache(); - Cache.setFolderHash(this.aDraftInfo[2], ''); + context[name](list.join(',')); + } + }; + + this.oLastMessage = null; + this.oEditor = null; + this.aDraftInfo = null; + this.sInReplyTo = ''; + this.bFromDraft = false; + this.sReferences = ''; + + this.sLastFocusedField = 'to'; + + this.resizerTrigger = _.bind(this.resizerTrigger, this); + + this.allowContacts = !!AppStore.contactsIsAllowed(); + this.allowFolders = !!Settings.capa(Capa.Folders); + + this.bSkipNextHide = false; + this.composeInEdit = AppStore.composeInEdit; + this.editorDefaultType = SettingsStore.editorDefaultType; + + this.capaOpenPGP = PgpStore.capaOpenPGP; + + this.identitiesDropdownTrigger = ko.observable(false); + + this.to = ko.observable(''); + this.to.focused = ko.observable(false); + this.cc = ko.observable(''); + this.cc.focused = ko.observable(false); + this.bcc = ko.observable(''); + this.bcc.focused = ko.observable(false); + this.replyTo = ko.observable(''); + this.replyTo.focused = ko.observable(false); + + ko.computed(() => { + switch (true) + { + case this.to.focused(): + this.sLastFocusedField = 'to'; + break; + case this.cc.focused(): + this.sLastFocusedField = 'cc'; + break; + case this.bcc.focused(): + this.sLastFocusedField = 'bcc'; + break; + // no default + } + }).extend({notify: 'always'}); + + this.subject = ko.observable(''); + this.subject.focused = ko.observable(false); + + this.isHtml = ko.observable(false); + + this.requestDsn = ko.observable(false); + this.requestReadReceipt = ko.observable(false); + this.markAsImportant = ko.observable(false); + + this.sendError = ko.observable(false); + this.sendSuccessButSaveError = ko.observable(false); + this.savedError = ko.observable(false); + + this.sendButtonSuccess = ko.computed( + () => !this.sendError() && !this.sendSuccessButSaveError() + ); + + this.sendErrorDesc = ko.observable(''); + this.savedErrorDesc = ko.observable(''); + + this.sendError.subscribe((value) => { + if (!value) + { + this.sendErrorDesc(''); + } + }); + + this.savedError.subscribe((value) => { + if (!value) + { + this.savedErrorDesc(''); + } + }); + + this.sendSuccessButSaveError.subscribe((value) => { + if (!value) + { + this.savedErrorDesc(''); + } + }); + + this.savedTime = ko.observable(0); + this.savedTimeText = ko.computed( + () => (0 < this.savedTime() ? i18n('COMPOSE/SAVED_TIME', {'TIME': momentorFormat(this.savedTime() - 1, 'LT')}) : '') + ); + + this.emptyToError = ko.observable(false); + this.emptyToErrorTooltip = ko.computed( + () => (this.emptyToError() ? i18n('COMPOSE/EMPTY_TO_ERROR_DESC') : '') + ); + + this.attachmentsInProcessError = ko.observable(false); + this.attachmentsInErrorError = ko.observable(false); + + this.attachmentsErrorTooltip = ko.computed(() => { + let result = ''; + switch (true) + { + case this.attachmentsInProcessError(): + result = i18n('COMPOSE/ATTACHMENTS_UPLOAD_ERROR_DESC'); + break; + case this.attachmentsInErrorError(): + result = i18n('COMPOSE/ATTACHMENTS_ERROR_DESC'); + break; + // no default + } + return result; + }); + + this.showCc = ko.observable(false); + this.showBcc = ko.observable(false); + this.showReplyTo = ko.observable(false); + + this.cc.subscribe((value) => { + if (false === this.showCc() && 0 < value.length) + { + this.showCc(true); + } + }); + + this.bcc.subscribe((value) => { + if (false === this.showBcc() && 0 < value.length) + { + this.showBcc(true); + } + }); + + this.replyTo.subscribe((value) => { + if (false === this.showReplyTo() && 0 < value.length) + { + this.showReplyTo(true); + } + }); + + this.draftFolder = ko.observable(''); + this.draftUid = ko.observable(''); + this.sending = ko.observable(false); + this.saving = ko.observable(false); + this.attachments = ko.observableArray([]); + + this.attachmentsInProcess = this.attachments.filter((item) => item && !item.complete()); + this.attachmentsInReady = this.attachments.filter((item) => item && item.complete()); + this.attachmentsInError = this.attachments.filter((item) => item && '' !== item.error()); + + this.attachmentsCount = ko.computed(() => this.attachments().length); + this.attachmentsInErrorCount = ko.computed(() => this.attachmentsInError().length); + this.attachmentsInProcessCount = ko.computed(() => this.attachmentsInProcess().length); + this.isDraftFolderMessage = ko.computed(() => '' !== this.draftFolder() && '' !== this.draftUid()); + + this.attachmentsPlace = ko.observable(false); + + this.attachments.subscribe(this.resizerTrigger); + this.attachmentsPlace.subscribe(this.resizerTrigger); + + this.attachmentsInErrorCount.subscribe((value) => { + if (0 === value) + { + this.attachmentsInErrorError(false); + } + }); + + 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 = IdentityStore.identities; + this.identitiesOptions = ko.computed( + () => _.map(IdentityStore.identities(), (item) => ({ + 'item': item, + 'optValue': item.id(), + 'optText': item.formattedName() + })) + ); + + this.currentIdentity = ko.observable( + this.identities()[0] ? this.identities()[0] : null); + + this.currentIdentity.extend({toggleSubscribe: [ + this, + (identity) => { + fEmailOutInHelper(this, identity, 'bcc'); + fEmailOutInHelper(this, identity, 'replyTo'); + }, + (identity) => { + fEmailOutInHelper(this, identity, 'bcc', true); + fEmailOutInHelper(this, identity, 'replyTo', true); + } + ]}); + + this.currentIdentityView = ko.computed(() => { + const item = this.currentIdentity(); + return item ? item.formattedName() : 'unknown'; + }); + + this.to.subscribe((value) => { + if (this.emptyToError() && 0 < value.length) + { + this.emptyToError(false); + } + }); + + this.attachmentsInProcess.subscribe((value) => { + if (this.attachmentsInProcessError() && isArray(value) && 0 === value.length) + { + this.attachmentsInProcessError(false); + } + }); + + this.resizer = ko.observable(false).extend({throttle: 50}); + + this.resizer.subscribe(() => { + if (this.oEditor) { + this.oEditor.resize(); + } + }); + + this.canBeSentOrSaved = ko.computed(() => !this.sending() && !this.saving()); + + this.deleteCommand = createCommand(() => { + const PopupsAskViewModel = require('View/Popup/Ask'); + if (!isPopupVisible(PopupsAskViewModel) && this.modalVisibility()) + { + showScreenPopup(PopupsAskViewModel, [i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'), () => { + if (this.modalVisibility()) + { + getApp().deleteMessagesFromFolderWithoutCheck(this.draftFolder(), [this.draftUid()]); + hideScreenPopup(ComposePopupView); + } + }]); + } + + }, () => this.isDraftFolderMessage()); + + this.sendMessageResponse = _.bind(this.sendMessageResponse, this); + this.saveMessageResponse = _.bind(this.saveMessageResponse, this); + + this.sendCommand = createCommand(() => { + + const + sTo = trim(this.to()), + sCc = trim(this.cc()), + sBcc = trim(this.bcc()); + let + sSentFolder = FolderStore.sentFolder(); + + this.attachmentsInProcessError(false); + this.attachmentsInErrorError(false); + this.emptyToError(false); + + if (0 < this.attachmentsInProcess().length) + { + this.attachmentsInProcessError(true); + this.attachmentsPlace(true); + } + else if (0 < this.attachmentsInError().length) + { + this.attachmentsInErrorError(true); + this.attachmentsPlace(true); + } + + if ('' === sTo && '' === sCc && '' === sBcc) + { + this.emptyToError(true); + } + + if (!this.emptyToError() && !this.attachmentsInErrorError() && !this.attachmentsInProcessError()) + { + if (SettingsStore.replySameFolder()) + { + if (isArray(this.aDraftInfo) && 3 === this.aDraftInfo.length && isNormal(this.aDraftInfo[2]) && 0 < this.aDraftInfo[2].length) + { + sSentFolder = this.aDraftInfo[2]; } } - sSentFolder = Consts.UNUSED_OPTION_VALUE === sSentFolder ? '' : sSentFolder; + if (!this.allowFolders) + { + sSentFolder = UNUSED_OPTION_VALUE; + } - Cache.setFolderHash(this.draftFolder(), ''); - Cache.setFolderHash(sSentFolder, ''); + if ('' === sSentFolder) + { + showScreenPopup(require('View/Popup/FolderSystem'), [SetSystemFoldersNotification.Sent]); + } + else + { + this.sendError(false); + this.sending(true); - Remote.sendMessage( - this.sendMessageResponse, + if (isArray(this.aDraftInfo) && 3 === this.aDraftInfo.length) + { + const flagsCache = getMessageFlagsFromCache(this.aDraftInfo[2], this.aDraftInfo[1]); + if (flagsCache) + { + if ('forward' === this.aDraftInfo[0]) + { + flagsCache[3] = true; + } + else + { + flagsCache[2] = true; + } + + setMessageFlagsToCache(this.aDraftInfo[2], this.aDraftInfo[1], flagsCache); + getApp().reloadFlagsCurrentMessageListAndMessageFromCache(); + setFolderHash(this.aDraftInfo[2], ''); + } + } + + sSentFolder = UNUSED_OPTION_VALUE === sSentFolder ? '' : sSentFolder; + + setFolderHash(this.draftFolder(), ''); + setFolderHash(sSentFolder, ''); + + Remote.sendMessage( + this.sendMessageResponse, + this.currentIdentity() ? this.currentIdentity().id() : '', + this.draftFolder(), + this.draftUid(), + sSentFolder, + sTo, + this.cc(), + this.bcc(), + this.replyTo(), + this.subject(), + this.oEditor ? this.oEditor.isHtml() : false, + this.oEditor ? this.oEditor.getData(true) : '', + this.prepearAttachmentsForSendOrSave(), + this.aDraftInfo, + this.sInReplyTo, + this.sReferences, + this.requestDsn(), + this.requestReadReceipt(), + this.markAsImportant() + ); + } + } + + }, this.canBeSentOrSaved); + + this.saveCommand = createCommand(() => { + + if (!this.allowFolders) + { + return false; + } + + if (FolderStore.draftFolderNotEnabled()) + { + showScreenPopup(require('View/Popup/FolderSystem'), [SetSystemFoldersNotification.Draft]); + } + else + { + this.savedError(false); + this.saving(true); + + this.autosaveStart(); + + setFolderHash(FolderStore.draftFolder(), ''); + + Remote.saveMessage( + this.saveMessageResponse, this.currentIdentity() ? this.currentIdentity().id() : '', this.draftFolder(), this.draftUid(), - sSentFolder, - sTo, + FolderStore.draftFolder(), + this.to(), this.cc(), this.bcc(), this.replyTo(), this.subject(), this.oEditor ? this.oEditor.isHtml() : false, - this.oEditor ? this.oEditor.getData(true, true) : '', + this.oEditor ? this.oEditor.getData(true) : '', this.prepearAttachmentsForSendOrSave(), this.aDraftInfo, this.sInReplyTo, this.sReferences, - this.requestDsn(), - this.requestReadReceipt(), this.markAsImportant() ); } - } - }, this.canBeSentOrSaved); + return true; - this.saveCommand = Utils.createCommand(this, function() { + }, this.canBeSentOrSaved); - if (!this.allowFolders) - { - return false; - } + this.skipCommand = createCommand(() => { - if (FolderStore.draftFolderNotEnabled()) - { - kn.showScreenPopup(require('View/Popup/FolderSystem'), [Enums.SetSystemFoldersNotification.Draft]); - } - else - { - this.savedError(false); - this.saving(true); + this.bSkipNextHide = true; - this.autosaveStart(); + if (this.modalVisibility() && !this.saving() && !this.sending() && + !FolderStore.draftFolderNotEnabled()) + { + this.saveCommand(); + } - Cache.setFolderHash(FolderStore.draftFolder(), ''); + this.tryToClosePopup(); - Remote.saveMessage( - this.saveMessageResponse, - this.currentIdentity() ? this.currentIdentity().id() : '', - this.draftFolder(), - this.draftUid(), - FolderStore.draftFolder(), - this.to(), - this.cc(), - this.bcc(), - this.replyTo(), - this.subject(), - this.oEditor ? this.oEditor.isHtml() : false, - this.oEditor ? this.oEditor.getData(true) : '', - this.prepearAttachmentsForSendOrSave(), - this.aDraftInfo, - this.sInReplyTo, - this.sReferences, - this.markAsImportant() - ); - } + }, this.canBeSentOrSaved); - return true; + this.contactsCommand = createCommand(() => { - }, this.canBeSentOrSaved); + if (this.allowContacts) + { + this.skipCommand(); + _.delay(() => { + showScreenPopup(require('View/Popup/Contacts'), [true, this.sLastFocusedField]); + }, Magics.Time200ms); + } - this.skipCommand = Utils.createCommand(this, function() { + }, () => this.allowContacts); - this.bSkipNextHide = true; + Events.sub('interval.2m', () => { + if (this.modalVisibility() && !FolderStore.draftFolderNotEnabled() && !this.isEmptyForm(false) && + !this.saving() && !this.sending() && !this.savedError()) + { + this.saveCommand(); + } + }); - if (this.modalVisibility() && !this.saving() && !this.sending() && - !FolderStore.draftFolderNotEnabled()) - { - this.saveCommand(); - } + this.showCc.subscribe(this.resizerTrigger); + this.showBcc.subscribe(this.resizerTrigger); + this.showReplyTo.subscribe(this.resizerTrigger); - this.tryToClosePopup(); + this.dropboxEnabled = SocialStore.dropbox.enabled; + this.dropboxApiKey = SocialStore.dropbox.apiKey; - }, this.canBeSentOrSaved); + this.dropboxCommand = createCommand(() => { - this.contactsCommand = Utils.createCommand(this, function() { + if (window.Dropbox) + { + window.Dropbox.choose({ + success: (files) => { + if (files && files[0] && files[0].link) + { + this.addDropboxAttachment(files[0]); + } + }, + linkType: 'direct', + multiselect: false + }); + } - if (this.allowContacts) - { - this.skipCommand(); - _.delay(function() { - kn.showScreenPopup(require('View/Popup/Contacts'), - [true, self.sLastFocusedField]); - }, Enums.Magics.Time200ms); - } + return true; - }, function() { - return this.allowContacts; - }); + }, () => this.dropboxEnabled()); - Events.sub('interval.2m', function() { + this.driveEnabled = ko.observable(bXMLHttpRequestSupported && + !!Settings.settingsGet('AllowGoogleSocial') && !!Settings.settingsGet('AllowGoogleSocialDrive') && + !!Settings.settingsGet('GoogleClientID') && !!Settings.settingsGet('GoogleApiKey')); + this.driveVisible = ko.observable(false); + + this.driveCommand = createCommand(() => { + this.driveOpenPopup(); + return true; + }, () => this.driveEnabled()); + + this.driveCallback = _.bind(this.driveCallback, this); + + this.onMessageUploadAttachments = _.bind(this.onMessageUploadAttachments, this); + + this.bDisabeCloseOnEsc = true; + this.sDefaultKeyScope = KeyState.Compose; + + this.tryToClosePopup = _.debounce(_.bind(this.tryToClosePopup, this), Magics.Time200ms); + + this.emailsSource = _.bind(this.emailsSource, this); + this.autosaveFunction = _.bind(this.autosaveFunction, this); + + this.iTimer = 0; + } + + autosaveFunction() { if (this.modalVisibility() && !FolderStore.draftFolderNotEnabled() && !this.isEmptyForm(false) && !this.saving() && !this.sending() && !this.savedError()) { this.saveCommand(); } - }, this); - this.showCc.subscribe(this.resizerTrigger); - this.showBcc.subscribe(this.resizerTrigger); - this.showReplyTo.subscribe(this.resizerTrigger); + this.autosaveStart(); + } - this.dropboxEnabled = SocialStore.dropbox.enabled; - this.dropboxApiKey = SocialStore.dropbox.apiKey; + autosaveStart() { + window.clearTimeout(this.iTimer); + this.iTimer = window.setTimeout(this.autosaveFunction, Magics.Time1m); + } - this.dropboxCommand = Utils.createCommand(this, function() { + autosaveStop() { + window.clearTimeout(this.iTimer); + } - if (window.Dropbox) + emailsSource(oData, fResponse) { + getApp().getAutocomplete(oData.term, (aData) => { + fResponse(_.map(aData, (oEmailItem) => oEmailItem.toLine(false))); + }); + } + + openOpenPgpPopup() { + if (PgpStore.capaOpenPGP() && this.oEditor && !this.oEditor.isHtml()) { - window.Dropbox.choose({ - 'success': function(files) { - if (files && files[0] && files[0].link) - { - self.addDropboxAttachment(files[0]); - } + showScreenPopup(require('View/Popup/ComposeOpenPgp'), [ + (result) => { + this.editor((editor) => { + editor.setPlain(result); + }); }, - 'linkType': 'direct', - 'multiselect': false - }); + this.oEditor.getData(false), + this.currentIdentity(), + this.to(), + this.cc(), + this.bcc() + ]); } - - return true; - - }, function() { - return this.dropboxEnabled(); - }); - - this.driveEnabled = ko.observable(Globals.bXMLHttpRequestSupported && - !!Settings.settingsGet('AllowGoogleSocial') && !!Settings.settingsGet('AllowGoogleSocialDrive') && - !!Settings.settingsGet('GoogleClientID') && !!Settings.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.onMessageUploadAttachments = _.bind(this.onMessageUploadAttachments, this); - - this.bDisabeCloseOnEsc = true; - this.sDefaultKeyScope = Enums.KeyState.Compose; - - this.tryToClosePopup = _.debounce(_.bind(this.tryToClosePopup, this), Enums.Magics.Time200ms); - - this.emailsSource = _.bind(this.emailsSource, this); - this.autosaveFunction = _.bind(this.autosaveFunction, this); - - this.iTimer = 0; - - kn.constructorEnd(this); -} - -kn.extendAsViewModel(['View/Popup/Compose', 'PopupsComposeViewModel'], ComposePopupView); -_.extend(ComposePopupView.prototype, AbstractView.prototype); - -ComposePopupView.prototype.autosaveFunction = function() -{ - if (this.modalVisibility() && !FolderStore.draftFolderNotEnabled() && !this.isEmptyForm(false) && - !this.saving() && !this.sending() && !this.savedError()) - { - this.saveCommand(); } - this.autosaveStart(); -}; - -ComposePopupView.prototype.autosaveStart = function() -{ - window.clearTimeout(this.iTimer); - this.iTimer = window.setTimeout(this.autosaveFunction, Enums.Magics.Time1m); -}; - -ComposePopupView.prototype.autosaveStop = function() -{ - window.clearTimeout(this.iTimer); -}; - -ComposePopupView.prototype.emailsSource = function(oData, fResponse) -{ - require('App/User').default.getAutocomplete(oData.term, function(aData) { - fResponse(_.map(aData, function(oEmailItem) { - return oEmailItem.toLine(false); - })); - }); -}; - -ComposePopupView.prototype.openOpenPgpPopup = function() -{ - if (PgpStore.capaOpenPGP() && this.oEditor && !this.oEditor.isHtml()) - { - var self = this; - kn.showScreenPopup(require('View/Popup/ComposeOpenPgp'), [ - function(sResult) { - self.editor(function(oEditor) { - oEditor.setPlain(sResult); - }); - }, - this.oEditor.getData(false, true), - this.currentIdentity(), - this.to(), - this.cc(), - this.bcc() - ]); - } -}; - -ComposePopupView.prototype.reloadDraftFolder = function() -{ - var - sDraftFolder = FolderStore.draftFolder(); - - if ('' !== sDraftFolder && Consts.UNUSED_OPTION_VALUE !== sDraftFolder) - { - Cache.setFolderHash(sDraftFolder, ''); - if (FolderStore.currentFolderFullNameRaw() === sDraftFolder) + reloadDraftFolder() { + const draftFolder = FolderStore.draftFolder(); + if ('' !== draftFolder && UNUSED_OPTION_VALUE !== draftFolder) { - require('App/User').default.reloadMessageList(true); - } - else - { - require('App/User').default.folderInformation(sDraftFolder); - } - } -}; - -ComposePopupView.prototype.findIdentityByMessage = function(sComposeType, oMessage) -{ - var - aIdentities = IdentityStore.identities(), - iResultIndex = 1000, - oResultIdentity = null, - oIdentitiesCache = {}, - - fEachHelper = function(oItem) { - - if (oItem && oItem.email && oIdentitiesCache[oItem.email]) + setFolderHash(draftFolder, ''); + if (FolderStore.currentFolderFullNameRaw() === draftFolder) { - if (!oResultIdentity || iResultIndex > oIdentitiesCache[oItem.email][1]) - { - oResultIdentity = oIdentitiesCache[oItem.email][0]; - iResultIndex = oIdentitiesCache[oItem.email][1]; - } + getApp().reloadMessageList(true); } - }; - - _.each(aIdentities, function(oItem, iIndex) { - oIdentitiesCache[oItem.email()] = [oItem, iIndex]; - }); - - 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: - _.each(_.union(oMessage.to, oMessage.cc, oMessage.bcc), fEachHelper); - if (!oResultIdentity) { - _.each(oMessage.deliveredTo, fEachHelper); - } - break; - case Enums.ComposeType.Draft: - _.each(_.union(oMessage.from, oMessage.replyTo), fEachHelper); - break; - // no default - } - } - - return oResultIdentity || aIdentities[0] || null; -}; - -ComposePopupView.prototype.selectIdentity = function(oIdentity) -{ - if (oIdentity && oIdentity.item) - { - this.currentIdentity(oIdentity.item); - this.setSignatureFromIdentity(oIdentity.item); - } -}; - -ComposePopupView.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); - this.savedErrorDesc(Utils.trim(Translator.i18n('COMPOSE/SAVED_ERROR_ON_SEND'))); - } - else - { - sMessage = Translator.getNotification(oData && oData.ErrorCode ? oData.ErrorCode : Enums.Notification.CantSendMessage, - oData && oData.ErrorMessage ? oData.ErrorMessage : ''); - - this.sendError(true); - this.sendErrorDesc(sMessage || Translator.getNotification(Enums.Notification.CantSendMessage)); - } - } - - this.reloadDraftFolder(); -}; - -ComposePopupView.prototype.saveMessageResponse = function(sResult, oData) -{ - var bResult = false; - - this.saving(false); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - if (oData.Result.NewFolder && oData.Result.NewUid) - { - bResult = true; - - if (this.bFromDraft) + else { - var oMessage = MessageStore.message(); - if (oMessage && this.draftFolder() === oMessage.folderFullNameRaw && this.draftUid() === oMessage.uid) - { - MessageStore.message(null); - } - } - - this.draftFolder(oData.Result.NewFolder); - this.draftUid(oData.Result.NewUid); - - this.savedTime(window.Math.round((new window.Date()).getTime() / 1000)); - - if (this.bFromDraft) - { - Cache.setFolderHash(this.draftFolder(), ''); + getApp().folderInformation(draftFolder); } } } - if (!bResult) - { - this.savedError(true); - this.savedErrorDesc(Translator.getNotification(Enums.Notification.CantSaveMessage)); - } + findIdentityByMessage(composeType, message) { - this.reloadDraftFolder(); -}; - -ComposePopupView.prototype.onHide = function() -{ - this.autosaveStop(); - - if (!this.bSkipNextHide) - { - AppStore.composeInEdit(false); - this.reset(); - } - - this.bSkipNextHide = false; - - this.to.focused(false); - - kn.routeOn(); -}; - -ComposePopupView.prototype.editor = function(fOnInit) -{ - if (fOnInit) - { - var self = this; - if (!this.oEditor && this.composeEditorArea()) - { -// _.delay(function() { - self.oEditor = new HtmlEditor(self.composeEditorArea(), null, function() { - fOnInit(self.oEditor); - self.resizerTrigger(); - }, function(bHtml) { - self.isHtml(!!bHtml); - }); -// }, 1000); - } - else if (this.oEditor) - { - fOnInit(this.oEditor); - this.resizerTrigger(); - } - } -}; - -ComposePopupView.prototype.converSignature = function(sSignature) -{ - var - iLimit = 10, - aMoments = [], - oMomentRegx = /{{MOMENT:([^}]+)}}/g, - sFrom = ''; - - sSignature = sSignature.replace(/[\r]/g, ''); - - sFrom = this.oLastMessage ? this.emailArrayToStringLineHelper(this.oLastMessage.from, true) : ''; - if ('' !== sFrom) - { - sSignature = sSignature.replace(/{{FROM-FULL}}/g, sFrom); - - if (-1 === sFrom.indexOf(' ') && 0 < sFrom.indexOf('@')) - { - sFrom = sFrom.replace(/@[\S]+/, ''); - } - - sSignature = sSignature.replace(/{{FROM}}/g, sFrom); - } - - sSignature = sSignature.replace(/[\s]{1,2}{{FROM}}/g, '{{FROM}}'); - sSignature = sSignature.replace(/[\s]{1,2}{{FROM-FULL}}/g, '{{FROM-FULL}}'); - - sSignature = sSignature.replace(/{{FROM}}/g, ''); - sSignature = sSignature.replace(/{{FROM-FULL}}/g, ''); - - if (-1 < sSignature.indexOf('{{DATE}}')) - { - sSignature = sSignature.replace(/{{DATE}}/g, Momentor.format(0, 'llll')); - } - - if (-1 < sSignature.indexOf('{{TIME}}')) - { - sSignature = sSignature.replace(/{{TIME}}/g, Momentor.format(0, 'LT')); - } - if (-1 < sSignature.indexOf('{{MOMENT:')) - { - try - { - var oMatch = null; - while (null !== (oMatch = oMomentRegx.exec(sSignature))) // eslint-disable-line no-cond-assign - { - if (oMatch && oMatch[0] && oMatch[1]) + let + resultIndex = 1000, + resultIdentity = null; + const + identities = IdentityStore.identities(), + identitiesCache = {}, + fEachHelper = (item) => { + if (item && item.email && identitiesCache[item.email]) { - aMoments.push([oMatch[0], oMatch[1]]); + if (!resultIdentity || resultIndex > identitiesCache[item.email][1]) + { + resultIdentity = identitiesCache[item.email][0]; + resultIndex = identitiesCache[item.email][1]; + } } + }; - iLimit -= 1; - if (0 === iLimit) - { + _.each(identities, (item, index) => { + identitiesCache[item.email()] = [item, index]; + }); + + if (message) + { + switch (composeType) + { + case ComposeType.Empty: break; - } + case ComposeType.Reply: + case ComposeType.ReplyAll: + case ComposeType.Forward: + case ComposeType.ForwardAsAttachment: + _.each(_.union(message.to, message.cc, message.bcc), fEachHelper); + if (!resultIdentity) { + _.each(message.deliveredTo, fEachHelper); + } + break; + case ComposeType.Draft: + _.each(_.union(message.from, message.replyTo), fEachHelper); + break; + // no default } - - if (aMoments && 0 < aMoments.length) - { - _.each(aMoments, function(aData) { - sSignature = sSignature.replace( - aData[0], Momentor.format(0, aData[1])); - }); - } - - sSignature = sSignature.replace(/{{MOMENT:[^}]+}}/g, ''); } - catch (e) {} // eslint-disable-line no-empty + + return resultIdentity || identities[0] || null; } - return sSignature; -}; + selectIdentity(identity) { + if (identity && identity.item) + { + this.currentIdentity(identity.item); + this.setSignatureFromIdentity(identity.item); + } + } -ComposePopupView.prototype.setSignatureFromIdentity = function(oIdentity) -{ - if (oIdentity) - { - var self = this; - this.editor(function(oEditor) { - var - bHtml = false, - sSignature = oIdentity.signature(); + sendMessageResponse(statusResult, data) { + let + result = false, + message = ''; - if ('' !== sSignature) + this.sending(false); + + if (StorageResultType.Success === statusResult && data && data.Result) + { + result = true; + if (this.modalVisibility()) { - if (':HTML:' === sSignature.substr(0, 6)) + delegateRun(this, 'closeCommand'); + } + } + + if (this.modalVisibility() && !result) + { + if (data && Notification.CantSaveMessage === data.ErrorCode) + { + this.sendSuccessButSaveError(true); + this.savedErrorDesc(trim(i18n('COMPOSE/SAVED_ERROR_ON_SEND'))); + } + else + { + message = getNotification(data && data.ErrorCode ? data.ErrorCode : Notification.CantSendMessage, + data && data.ErrorMessage ? data.ErrorMessage : ''); + + this.sendError(true); + this.sendErrorDesc(message || getNotification(Notification.CantSendMessage)); + } + } + + this.reloadDraftFolder(); + } + + saveMessageResponse(statusResult, oData) { + + let result = false; + + this.saving(false); + + if (StorageResultType.Success === statusResult && oData && oData.Result) + { + if (oData.Result.NewFolder && oData.Result.NewUid) + { + result = true; + + if (this.bFromDraft) { - bHtml = true; - sSignature = sSignature.substr(6); + const message = MessageStore.message(); + if (message && this.draftFolder() === message.folderFullNameRaw && this.draftUid() === message.uid) + { + MessageStore.message(null); + } + } + + this.draftFolder(oData.Result.NewFolder); + this.draftUid(oData.Result.NewUid); + + this.savedTime(window.Math.round((new window.Date()).getTime() / 1000)); + + if (this.bFromDraft) + { + setFolderHash(this.draftFolder(), ''); } } + } - oEditor.setSignature(self.converSignature(sSignature), - bHtml, !!oIdentity.signatureInsertBefore()); - }); - } -}; - -/** - * @param {string=} sType = Enums.ComposeType.Empty - * @param {?MessageModel|Array=} oMessageOrArray = null - * @param {Array=} aToEmails = null - * @param {Array=} aCcEmails = null - * @param {Array=} aBccEmails = null - * @param {string=} sCustomSubject = null - * @param {string=} sCustomPlainText = null - */ -ComposePopupView.prototype.onShow = function(sType, oMessageOrArray, - aToEmails, aCcEmails, aBccEmails, sCustomSubject, sCustomPlainText) -{ - kn.routeOff(); - - this.autosaveStart(); - - if (AppStore.composeInEdit()) - { - sType = sType || Enums.ComposeType.Empty; - - var self = this; - - if (Enums.ComposeType.Empty !== sType) + if (!result) { - kn.showScreenPopup(require('View/Popup/Ask'), [Translator.i18n('COMPOSE/DISCARD_UNSAVED_DATA'), function() { - self.initOnShow(sType, oMessageOrArray, aToEmails, aCcEmails, aBccEmails, sCustomSubject, sCustomPlainText); - }, null, null, null, false]); + this.savedError(true); + this.savedErrorDesc(getNotification(Notification.CantSaveMessage)); + } + + this.reloadDraftFolder(); + } + + onHide() { + this.autosaveStop(); + + if (!this.bSkipNextHide) + { + AppStore.composeInEdit(false); + this.reset(); + } + + this.bSkipNextHide = false; + + this.to.focused(false); + + routeOn(); + } + + editor(fOnInit) { + if (fOnInit) + { + if (!this.oEditor && this.composeEditorArea()) + { +// _.delay(() => { + this.oEditor = new HtmlEditor(this.composeEditorArea(), null, () => { + fOnInit(this.oEditor); + this.resizerTrigger(); + }, (bHtml) => { + this.isHtml(!!bHtml); + }); +// }, 1000); + } + else if (this.oEditor) + { + fOnInit(this.oEditor); + this.resizerTrigger(); + } + } + } + + converSignature(signature) { + let + limit = 10, + fromLine = ''; + + const + moments = [], + momentRegx = /{{MOMENT:([^}]+)}}/g; + + signature = signature.replace(/[\r]/g, ''); + + fromLine = this.oLastMessage ? this.emailArrayToStringLineHelper(this.oLastMessage.from, true) : ''; + if ('' !== fromLine) + { + signature = signature.replace(/{{FROM-FULL}}/g, fromLine); + + if (-1 === fromLine.indexOf(' ') && 0 < fromLine.indexOf('@')) + { + fromLine = fromLine.replace(/@[\S]+/, ''); + } + + signature = signature.replace(/{{FROM}}/g, fromLine); + } + + signature = signature.replace(/[\s]{1,2}{{FROM}}/g, '{{FROM}}'); + signature = signature.replace(/[\s]{1,2}{{FROM-FULL}}/g, '{{FROM-FULL}}'); + + signature = signature.replace(/{{FROM}}/g, ''); + signature = signature.replace(/{{FROM-FULL}}/g, ''); + + if (-1 < signature.indexOf('{{DATE}}')) + { + signature = signature.replace(/{{DATE}}/g, momentorFormat(0, 'llll')); + } + + if (-1 < signature.indexOf('{{TIME}}')) + { + signature = signature.replace(/{{TIME}}/g, momentorFormat(0, 'LT')); + } + if (-1 < signature.indexOf('{{MOMENT:')) + { + try + { + let match = null; + while (null !== (match = momentRegx.exec(signature))) // eslint-disable-line no-cond-assign + { + if (match && match[0] && match[1]) + { + moments.push([match[0], match[1]]); + } + + limit -= 1; + if (0 === limit) + { + break; + } + } + + if (moments && 0 < moments.length) + { + _.each(moments, (data) => { + signature = signature.replace(data[0], momentorFormat(0, data[1])); + }); + } + + signature = signature.replace(/{{MOMENT:[^}]+}}/g, ''); + } + catch (e) {} // eslint-disable-line no-empty + } + + return signature; + } + + setSignatureFromIdentity(oIdentity) { + if (oIdentity) + { + this.editor((editor) => { + let + isHtml = false, + signature = oIdentity.signature(); + + if ('' !== signature) + { + if (':HTML:' === signature.substr(0, 6)) + { + isHtml = true; + signature = signature.substr(6); + } + } + + editor.setSignature(this.converSignature(signature), isHtml, !!oIdentity.signatureInsertBefore()); + }); + } + } + + /** + * @param {string=} type = ComposeType.Empty + * @param {?MessageModel|Array=} oMessageOrArray = null + * @param {Array=} aToEmails = null + * @param {Array=} aCcEmails = null + * @param {Array=} aBccEmails = null + * @param {string=} sCustomSubject = null + * @param {string=} sCustomPlainText = null + */ + onShow(type, oMessageOrArray, aToEmails, aCcEmails, aBccEmails, sCustomSubject, sCustomPlainText) { + + routeOff(); + + this.autosaveStart(); + + if (AppStore.composeInEdit()) + { + type = type || ComposeType.Empty; + if (ComposeType.Empty !== type) + { + showScreenPopup(require('View/Popup/Ask'), [i18n('COMPOSE/DISCARD_UNSAVED_DATA'), () => { + this.initOnShow(type, oMessageOrArray, aToEmails, aCcEmails, aBccEmails, sCustomSubject, sCustomPlainText); + }, null, null, null, false]); + } + else + { + this.addEmailsTo(this.to, aToEmails); + this.addEmailsTo(this.cc, aCcEmails); + this.addEmailsTo(this.bcc, aBccEmails); + + if (isNormal(sCustomSubject) && '' !== sCustomSubject && '' === this.subject()) + { + this.subject(sCustomSubject); + } + } } else { - this.addEmailsTo(this.to, aToEmails); - this.addEmailsTo(this.cc, aCcEmails); - this.addEmailsTo(this.bcc, aBccEmails); - - if (Utils.isNormal(sCustomSubject) && '' !== sCustomSubject && - '' === this.subject()) - { - this.subject(sCustomSubject); - } + this.initOnShow(type, oMessageOrArray, aToEmails, aCcEmails, aBccEmails, sCustomSubject, sCustomPlainText); } } - else - { - this.initOnShow(sType, oMessageOrArray, aToEmails, aCcEmails, aBccEmails, sCustomSubject, sCustomPlainText); - } -}; -/** - * @param {Function} fKoValue - * @param {Array} emails - */ -ComposePopupView.prototype.addEmailsTo = function(fKoValue, emails) -{ - var value = Utils.trim(fKoValue()); - if (Utils.isNonEmptyArray(emails)) - { - var values = _.uniq(_.compact(_.map(emails, function(oItem) { - return oItem ? oItem.toLine(false) : null; - }))); - - fKoValue(value + ('' === value ? '' : ', ') + Utils.trim(values.join(', '))); - } -}; - -/** - * - * @param {Array} aList - * @param {boolean} bFriendly - * @returns {string} - */ -ComposePopupView.prototype.emailArrayToStringLineHelper = function(aList, bFriendly) -{ - bFriendly = !!bFriendly; - var aResult = _.map(aList, function(item) { - return item.toLine(bFriendly); - }); - - return aResult.join(', '); -}; - -/** - * @param {string=} sType = Enums.ComposeType.Empty - * @param {?MessageModel|Array=} oMessageOrArray = null - * @param {Array=} aToEmails = null - * @param {Array=} aCcEmails = null - * @param {Array=} aBccEmails = null - * @param {string=} sCustomSubject = null - * @param {string=} sCustomPlainText = null - */ -ComposePopupView.prototype.initOnShow = function(sType, oMessageOrArray, - aToEmails, aCcEmails, aBccEmails, sCustomSubject, sCustomPlainText) -{ - AppStore.composeInEdit(true); - - var - self = this, - sFrom = '', - sTo = '', - sCc = '', - sDate = '', - sSubject = '', - sText = '', - sReplyTitle = '', - oExcludeEmail = {}, - oIdentity = null, - mEmail = AccountStore.email(), - aDraftInfo = null, - oMessage = null, - sComposeType = sType || Enums.ComposeType.Empty; - - oMessageOrArray = oMessageOrArray || null; - if (oMessageOrArray && Utils.isNormal(oMessageOrArray)) - { - oMessage = Utils.isArray(oMessageOrArray) && 1 === oMessageOrArray.length ? oMessageOrArray[0] : - (!Utils.isArray(oMessageOrArray) ? oMessageOrArray : null); - } - - this.oLastMessage = oMessage; - - if (null !== mEmail) - { - oExcludeEmail[mEmail] = true; - } - - this.reset(); - - oIdentity = this.findIdentityByMessage(sComposeType, oMessage); - if (oIdentity) - { - oExcludeEmail[oIdentity.email()] = true; - } - - if (Utils.isNonEmptyArray(aToEmails)) - { - this.to(this.emailArrayToStringLineHelper(aToEmails)); - } - - if (Utils.isNonEmptyArray(aCcEmails)) - { - this.cc(this.emailArrayToStringLineHelper(aCcEmails)); - } - - if (Utils.isNonEmptyArray(aBccEmails)) - { - this.bcc(this.emailArrayToStringLineHelper(aBccEmails)); - } - - if ('' !== sComposeType && oMessage) - { - sDate = Momentor.format(oMessage.dateTimeStampInUTC(), 'FULL'); - sSubject = oMessage.subject(); - aDraftInfo = oMessage.aDraftInfo; - - var oText = $(oMessage.body).clone(); - if (oText) + onWarmUp() { + if (this.modalVisibility && !this.modalVisibility()) { - Utils.clearBqSwitcher(oText); + this.editor((editor) => editor.modeToggle(false)); + } + } - sText = oText.html(); + /** + * @param {Function} fKoValue + * @param {Array} emails + */ + addEmailsTo(fKoValue, emails) { + if (isNonEmptyArray(emails)) + { + const + value = trim(fKoValue()), + values = _.uniq(_.compact(_.map(emails, (item) => (item ? item.toLine(false) : null)))); + + fKoValue(value + ('' === value ? '' : ', ') + trim(values.join(', '))); + } + } + + /** + * + * @param {Array} aList + * @param {boolean} bFriendly + * @returns {string} + */ + emailArrayToStringLineHelper(aList, bFriendly) { + bFriendly = !!bFriendly; + return _.map(aList, (item) => item.toLine(bFriendly)).join(', '); + } + + /** + * @param {string=} sType = ComposeType.Empty + * @param {?MessageModel|Array=} oMessageOrArray = null + * @param {Array=} aToEmails = null + * @param {Array=} aCcEmails = null + * @param {Array=} aBccEmails = null + * @param {string=} sCustomSubject = null + * @param {string=} sCustomPlainText = null + */ + initOnShow(sType, oMessageOrArray, aToEmails, aCcEmails, aBccEmails, sCustomSubject, sCustomPlainText) + { + AppStore.composeInEdit(true); + + let + sFrom = '', + sTo = '', + sCc = '', + sDate = '', + sSubject = '', + sText = '', + sReplyTitle = '', + identity = null, + aDraftInfo = null, + message = null; + + const + excludeEmail = {}, + mEmail = AccountStore.email(), + lineComposeType = sType || ComposeType.Empty; + + oMessageOrArray = oMessageOrArray || null; + if (oMessageOrArray && isNormal(oMessageOrArray)) + { + message = isArray(oMessageOrArray) && + 1 === oMessageOrArray.length ? oMessageOrArray[0] : + (!isArray(oMessageOrArray) ? oMessageOrArray : null); } - switch (sComposeType) + this.oLastMessage = message; + + if (null !== mEmail) { - case Enums.ComposeType.Empty: - break; - - case Enums.ComposeType.Reply: - this.to(this.emailArrayToStringLineHelper(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: - var aResplyAllParts = oMessage.replyAllEmails(oExcludeEmail); - this.to(this.emailArrayToStringLineHelper(aResplyAllParts[0])); - this.cc(this.emailArrayToStringLineHelper(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(this.emailArrayToStringLineHelper(oMessage.to)); - this.cc(this.emailArrayToStringLineHelper(oMessage.cc)); - this.bcc(this.emailArrayToStringLineHelper(oMessage.bcc)); - this.replyTo(this.emailArrayToStringLineHelper(oMessage.replyTo)); - - 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(this.emailArrayToStringLineHelper(oMessage.to)); - this.cc(this.emailArrayToStringLineHelper(oMessage.cc)); - this.bcc(this.emailArrayToStringLineHelper(oMessage.bcc)); - this.replyTo(this.emailArrayToStringLineHelper(oMessage.replyTo)); - - 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; - // no default + excludeEmail[mEmail] = true; } - switch (sComposeType) + this.reset(); + + identity = this.findIdentityByMessage(lineComposeType, message); + if (identity) { - case Enums.ComposeType.Reply: - case Enums.ComposeType.ReplyAll: - sFrom = oMessage.fromToLine(false, true); - sReplyTitle = Translator.i18n('COMPOSE/REPLY_MESSAGE_TITLE', { - 'DATETIME': sDate, - 'EMAIL': sFrom - }); - - sText = '

' + sReplyTitle + ':' + - '
' + Utils.trim(sText) + '
'; -// '

' + Utils.trim(sText) + '

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

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

' + Utils.trim(sText) + '

'; - break; - - case Enums.ComposeType.ForwardAsAttachment: - sText = ''; - break; - // no default + excludeEmail[identity.email()] = true; } - this.editor(function(oEditor) { - - oEditor.setHtml(sText, false); - - if (Enums.EditorDefaultType.PlainForced === self.editorDefaultType() || - (!oMessage.isHtml() && Enums.EditorDefaultType.HtmlForced !== self.editorDefaultType())) - { - oEditor.modeToggle(false); - } - - if (oIdentity && Enums.ComposeType.Draft !== sComposeType && Enums.ComposeType.EditAsNew !== sComposeType) - { - self.setSignatureFromIdentity(oIdentity); - } - - self.setFocusInPopup(); - }); - } - else if (Enums.ComposeType.Empty === sComposeType) - { - this.subject(Utils.isNormal(sCustomSubject) ? '' + sCustomSubject : ''); - - sText = Utils.isNormal(sCustomPlainText) ? '' + sCustomPlainText : ''; - - this.editor(function(oEditor) { - - oEditor.setHtml(sText, false); - - if (Enums.EditorDefaultType.Html !== self.editorDefaultType() && - Enums.EditorDefaultType.HtmlForced !== self.editorDefaultType()) - { - oEditor.modeToggle(false); - } - - if (oIdentity) - { - self.setSignatureFromIdentity(oIdentity); - } - - self.setFocusInPopup(); - }); - } - else if (Utils.isNonEmptyArray(oMessageOrArray)) - { - _.each(oMessageOrArray, function(oItem) { - self.addMessageAsAttachment(oItem); - }); - - this.editor(function(oEditor) { - - oEditor.setHtml('', false); - - if (Enums.EditorDefaultType.Html !== self.editorDefaultType() && - Enums.EditorDefaultType.HtmlForced !== self.editorDefaultType()) - { - oEditor.modeToggle(false); - } - - if (oIdentity && Enums.ComposeType.Draft !== sComposeType && Enums.ComposeType.EditAsNew !== sComposeType) - { - self.setSignatureFromIdentity(oIdentity); - } - - self.setFocusInPopup(); - }); - } - else - { - this.setFocusInPopup(); - } - - var downloads = this.getAttachmentsDownloadsForUpload(); - if (Utils.isNonEmptyArray(downloads)) - { - Remote.messageUploadAttachments(this.onMessageUploadAttachments, downloads); - } - - if (oIdentity) - { - this.currentIdentity(oIdentity); - } - - this.resizerTrigger(); -}; - -ComposePopupView.prototype.onMessageUploadAttachments = function(sResult, oData) -{ - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - var self = this; - if (!this.viewModelVisibility()) + if (isNonEmptyArray(aToEmails)) { - _.each(oData.Result, function(id, tempName) { - var attachment = self.getAttachmentById(id); - if (attachment) + this.to(this.emailArrayToStringLineHelper(aToEmails)); + } + + if (isNonEmptyArray(aCcEmails)) + { + this.cc(this.emailArrayToStringLineHelper(aCcEmails)); + } + + if (isNonEmptyArray(aBccEmails)) + { + this.bcc(this.emailArrayToStringLineHelper(aBccEmails)); + } + + if ('' !== lineComposeType && message) + { + sDate = momentorFormat(message.dateTimeStampInUTC(), 'FULL'); + sSubject = message.subject(); + aDraftInfo = message.aDraftInfo; + + const clonedText = $(message.body).clone(); + if (clonedText) + { + clearBqSwitcher(clonedText); + + sText = clonedText.html(); + } + + let resplyAllParts = null; + switch (lineComposeType) + { + case ComposeType.Empty: + break; + + case ComposeType.Reply: + this.to(this.emailArrayToStringLineHelper(message.replyEmails(excludeEmail))); + this.subject(replySubjectAdd('Re', sSubject)); + this.prepearMessageAttachments(message, lineComposeType); + this.aDraftInfo = ['reply', message.uid, message.folderFullNameRaw]; + this.sInReplyTo = message.sMessageId; + this.sReferences = trim(this.sInReplyTo + ' ' + message.sReferences); + break; + + case ComposeType.ReplyAll: + resplyAllParts = message.replyAllEmails(excludeEmail); + this.to(this.emailArrayToStringLineHelper(resplyAllParts[0])); + this.cc(this.emailArrayToStringLineHelper(resplyAllParts[1])); + this.subject(replySubjectAdd('Re', sSubject)); + this.prepearMessageAttachments(message, lineComposeType); + this.aDraftInfo = ['reply', message.uid, message.folderFullNameRaw]; + this.sInReplyTo = message.sMessageId; + this.sReferences = trim(this.sInReplyTo + ' ' + message.references()); + break; + + case ComposeType.Forward: + this.subject(replySubjectAdd('Fwd', sSubject)); + this.prepearMessageAttachments(message, lineComposeType); + this.aDraftInfo = ['forward', message.uid, message.folderFullNameRaw]; + this.sInReplyTo = message.sMessageId; + this.sReferences = trim(this.sInReplyTo + ' ' + message.sReferences); + break; + + case ComposeType.ForwardAsAttachment: + this.subject(replySubjectAdd('Fwd', sSubject)); + this.prepearMessageAttachments(message, lineComposeType); + this.aDraftInfo = ['forward', message.uid, message.folderFullNameRaw]; + this.sInReplyTo = message.sMessageId; + this.sReferences = trim(this.sInReplyTo + ' ' + message.sReferences); + break; + + case ComposeType.Draft: + this.to(this.emailArrayToStringLineHelper(message.to)); + this.cc(this.emailArrayToStringLineHelper(message.cc)); + this.bcc(this.emailArrayToStringLineHelper(message.bcc)); + this.replyTo(this.emailArrayToStringLineHelper(message.replyTo)); + + this.bFromDraft = true; + + this.draftFolder(message.folderFullNameRaw); + this.draftUid(message.uid); + + this.subject(sSubject); + this.prepearMessageAttachments(message, lineComposeType); + + this.aDraftInfo = isNonEmptyArray(aDraftInfo) && 3 === aDraftInfo.length ? aDraftInfo : null; + this.sInReplyTo = message.sInReplyTo; + this.sReferences = message.sReferences; + break; + + case ComposeType.EditAsNew: + this.to(this.emailArrayToStringLineHelper(message.to)); + this.cc(this.emailArrayToStringLineHelper(message.cc)); + this.bcc(this.emailArrayToStringLineHelper(message.bcc)); + this.replyTo(this.emailArrayToStringLineHelper(message.replyTo)); + + this.subject(sSubject); + this.prepearMessageAttachments(message, lineComposeType); + + this.aDraftInfo = isNonEmptyArray(aDraftInfo) && 3 === aDraftInfo.length ? aDraftInfo : null; + this.sInReplyTo = message.sInReplyTo; + this.sReferences = message.sReferences; + break; + // no default + } + + switch (lineComposeType) + { + case ComposeType.Reply: + case ComposeType.ReplyAll: + sFrom = message.fromToLine(false, true); + sReplyTitle = i18n('COMPOSE/REPLY_MESSAGE_TITLE', { + 'DATETIME': sDate, + 'EMAIL': sFrom + }); + + sText = '

' + sReplyTitle + ':' + + '
' + trim(sText) + '
'; + // '

' + trim(sText) + '

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

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

' + trim(sText) + '

'; + break; + + case ComposeType.ForwardAsAttachment: + sText = ''; + break; + // no default + } + + this.editor((editor) => { + + editor.setHtml(sText, false); + + if (EditorDefaultType.PlainForced === this.editorDefaultType() || + (!message.isHtml() && EditorDefaultType.HtmlForced !== this.editorDefaultType())) { - attachment.tempName(tempName); - attachment.waiting(false).uploading(false).complete(true); + editor.modeToggle(false); + } + + if (identity && ComposeType.Draft !== lineComposeType && ComposeType.EditAsNew !== lineComposeType) + { + this.setSignatureFromIdentity(identity); + } + + this.setFocusInPopup(); + }); + } + else if (ComposeType.Empty === lineComposeType) + { + this.subject(isNormal(sCustomSubject) ? '' + sCustomSubject : ''); + + sText = isNormal(sCustomPlainText) ? '' + sCustomPlainText : ''; + + this.editor((editor) => { + + editor.setHtml(sText, false); + + if (EditorDefaultType.Html !== this.editorDefaultType() && + EditorDefaultType.HtmlForced !== this.editorDefaultType()) + { + editor.modeToggle(false); + } + + if (identity) + { + this.setSignatureFromIdentity(identity); + } + + this.setFocusInPopup(); + }); + } + else if (isNonEmptyArray(oMessageOrArray)) + { + _.each(oMessageOrArray, (item) => { + this.addMessageAsAttachment(item); + }); + + this.editor((editor) => { + + editor.setHtml('', false); + + if (EditorDefaultType.Html !== this.editorDefaultType() && + EditorDefaultType.HtmlForced !== this.editorDefaultType()) + { + editor.modeToggle(false); + } + + if (identity && ComposeType.Draft !== lineComposeType && ComposeType.EditAsNew !== lineComposeType) + { + this.setSignatureFromIdentity(identity); + } + + this.setFocusInPopup(); + }); + } + else + { + this.setFocusInPopup(); + } + + const downloads = this.getAttachmentsDownloadsForUpload(); + if (isNonEmptyArray(downloads)) + { + Remote.messageUploadAttachments(this.onMessageUploadAttachments, downloads); + } + + if (identity) + { + this.currentIdentity(identity); + } + + this.resizerTrigger(); + } + + onMessageUploadAttachments(sResult, oData) { + if (StorageResultType.Success === sResult && oData && oData.Result) + { + if (!this.viewModelVisibility()) + { + _.each(oData.Result, (id, tempName) => { + const attachment = this.getAttachmentById(id); + if (attachment) + { + attachment.tempName(tempName); + attachment.waiting(false).uploading(false).complete(true); + } + }); + } + } + else + { + this.setMessageAttachmentFailedDownloadText(); + } + } + + setFocusInPopup() { + if (!bMobileDevice) + { + _.delay(() => { + + if ('' === this.to()) + { + this.to.focused(true); + } + else if (this.oEditor) + { + if (!this.to.focused()) + { + this.oEditor.focus(); + } + } + + }, Magics.Time100ms); + } + } + + onShowWithDelay() { + this.resizerTrigger(); + } + + tryToClosePopup() { + const PopupsAskViewModel = require('View/Popup/Ask'); + if (!isPopupVisible(PopupsAskViewModel) && this.modalVisibility()) + { + if (this.bSkipNextHide || (this.isEmptyForm() && !this.draftUid())) + { + delegateRun(this, 'closeCommand'); + } + else + { + showScreenPopup(PopupsAskViewModel, [i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'), () => { + if (this.modalVisibility()) + { + delegateRun(this, 'closeCommand'); + } + }]); + } + } + } + + onBuild() { + this.initUploader(); + + key('ctrl+q, command+q, ctrl+w, command+w', KeyState.Compose, noopFalse); + + key('`', KeyState.Compose, () => { + if (this.oEditor && !this.oEditor.hasFocus() && !inFocus()) + { + this.identitiesDropdownTrigger(true); + return false; + } + + return true; + }); + + key('ctrl+`', KeyState.Compose, () => { + this.identitiesDropdownTrigger(true); + return false; + }); + + key('esc, ctrl+down, command+down', KeyState.Compose, () => { + this.skipCommand(); + return false; + }); + + if (this.allowFolders) + { + key('ctrl+s, command+s', KeyState.Compose, () => { + this.saveCommand(); + return false; + }); + } + + if (Settings.appSettingsGet('allowCtrlEnterOnCompose')) + { + key('ctrl+enter, command+enter', KeyState.Compose, () => { + this.sendCommand(); + return false; + }); + } + + key('shift+esc', KeyState.Compose, () => { + if (this.modalVisibility()) + { + this.tryToClosePopup(); + } + return false; + }); + + Events.sub('window.resize.real', this.resizerTrigger); + Events.sub('window.resize.real', _.debounce(this.resizerTrigger, Magics.Time50ms)); + + SocialStore.appendDropbox(); + + if (this.driveEnabled()) + { + $.getScript('https://apis.google.com/js/api.js', () => { + if (window.gapi) + { + this.driveVisible(true); + } + }); + } + + window.setInterval(() => { + if (this.modalVisibility() && this.oEditor) + { + this.oEditor.resize(); + } + }, Magics.Time5s); + } + + driveCallback(accessToken, data) { + if (data && window.XMLHttpRequest && window.google && + data[window.google.picker.Response.ACTION] === window.google.picker.Action.PICKED && + data[window.google.picker.Response.DOCUMENTS] && data[window.google.picker.Response.DOCUMENTS][0] && + data[window.google.picker.Response.DOCUMENTS][0].id) + { + const request = new window.XMLHttpRequest(); + request.open('GET', 'https://www.googleapis.com/drive/v2/files/' + data[window.google.picker.Response.DOCUMENTS][0].id); + request.setRequestHeader('Authorization', 'Bearer ' + accessToken); + request.addEventListener('load', () => { + if (request && request.responseText) + { + const + response = window.JSON.parse(request.responseText), + fExport = (item, mimeType, ext) => { + if (item && item.exportLinks) + { + if (item.exportLinks[mimeType]) + { + response.downloadUrl = item.exportLinks[mimeType]; + response.title = item.title + '.' + ext; + response.mimeType = mimeType; + } + else if (item.exportLinks['application/pdf']) + { + response.downloadUrl = item.exportLinks['application/pdf']; + response.title = item.title + '.pdf'; + response.mimeType = 'application/pdf'; + } + } + }; + + if (response && !response.downloadUrl && response.mimeType && response.exportLinks) + { + switch (response.mimeType.toString().toLowerCase()) + { + case 'application/vnd.google-apps.document': + fExport(response, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'docx'); + break; + case 'application/vnd.google-apps.spreadsheet': + fExport(response, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xlsx'); + break; + case 'application/vnd.google-apps.drawing': + fExport(response, 'image/png', 'png'); + break; + case 'application/vnd.google-apps.presentation': + fExport(response, 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'pptx'); + break; + default: + fExport(response, 'application/pdf', 'pdf'); + break; + } + } + + if (response && response.downloadUrl) + { + this.addDriveAttachment(response, accessToken); + } + } + }); + + request.send(); + } + } + + driveCreatePiker(authToken) { + if (window.gapi && authToken && authToken.access_token) + { + window.gapi.load('picker', { + callback: () => { + if (window.google && window.google.picker) + { + const drivePicker = new window.google.picker.PickerBuilder() + // .addView(window.google.picker.ViewId.FOLDERS) + .addView(window.google.picker.ViewId.DOCS) + .setAppId(Settings.settingsGet('GoogleClientID')) + .setOAuthToken(authToken.access_token) + .setCallback(_.bind(this.driveCallback, this, authToken.access_token)) + .enableFeature(window.google.picker.Feature.NAV_HIDDEN) + // .setOrigin(window.location.protocol + '//' + window.location.host) + .build(); + + drivePicker.setVisible(true); + } } }); } } - else - { - this.setMessageAttachmentFailedDownloadText(); - } -}; -ComposePopupView.prototype.setFocusInPopup = function() -{ - if (!Globals.bMobileDevice) - { - var self = this; - _.delay(function() { - - if ('' === self.to()) - { - self.to.focused(true); - } - else if (self.oEditor) - { - if (!self.to.focused()) - { - self.oEditor.focus(); - } - } - - }, Enums.Magics.Time100ms); - } -}; - -ComposePopupView.prototype.onShowWithDelay = function() -{ - this.resizerTrigger(); -}; - -ComposePopupView.prototype.tryToClosePopup = function() -{ - var - self = this, - PopupsAskViewModel = require('View/Popup/Ask'); - - if (!kn.isPopupVisible(PopupsAskViewModel) && this.modalVisibility()) - { - if (this.bSkipNextHide || (this.isEmptyForm() && !this.draftUid())) + driveOpenPopup() { + if (window.gapi) { - Utils.delegateRun(self, 'closeCommand'); - } - else - { - kn.showScreenPopup(PopupsAskViewModel, [Translator.i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'), function() { - if (self.modalVisibility()) - { - Utils.delegateRun(self, 'closeCommand'); - } - }]); - } - } -}; - -ComposePopupView.prototype.onBuild = function() -{ - this.initUploader(); - - var self = this; - - key('ctrl+q, command+q, ctrl+w, command+w', Enums.KeyState.Compose, Utils.noopFalse); - - key('`', Enums.KeyState.Compose, function() { - if (self.oEditor && !self.oEditor.hasFocus() && !Utils.inFocus()) - { - self.identitiesDropdownTrigger(true); - return false; - } - - return true; - }); - - key('ctrl+`', Enums.KeyState.Compose, function() { - self.identitiesDropdownTrigger(true); - return false; - }); - - key('esc, ctrl+down, command+down', Enums.KeyState.Compose, function() { - self.skipCommand(); - return false; - }); - - if (this.allowFolders) - { - key('ctrl+s, command+s', Enums.KeyState.Compose, function() { - self.saveCommand(); - return false; - }); - } - - if (Settings.appSettingsGet('allowCtrlEnterOnCompose')) - { - key('ctrl+enter, command+enter', Enums.KeyState.Compose, function() { - self.sendCommand(); - return false; - }); - } - - key('shift+esc', Enums.KeyState.Compose, function() { - if (self.modalVisibility()) - { - self.tryToClosePopup(); - } - return false; - }); - - Events.sub('window.resize.real', this.resizerTrigger); - Events.sub('window.resize.real', _.debounce(this.resizerTrigger, Enums.Magics.Time50ms)); - - if (this.dropboxEnabled() && this.dropboxApiKey() && !window.Dropbox) - { - var oScript = window.document.createElement('script'); - oScript.type = 'text/javascript'; - oScript.src = 'https://www.dropbox.com/static/api/2/dropins.js'; - $(oScript).attr('id', 'dropboxjs').attr('data-app-key', self.dropboxApiKey()); - - window.document.body.appendChild(oScript); - } - - if (this.driveEnabled()) - { - $.getScript('https://apis.google.com/js/api.js', function() { - if (window.gapi) - { - self.driveVisible(true); - } - }); - } - - window.setInterval(function() { - if (self.modalVisibility() && self.oEditor) - { - self.oEditor.resize(); - } - }, Enums.Magics.Time5s); -}; - -ComposePopupView.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 - oResponse = window.JSON.parse(oRequest.responseText), - fExport = function(oItem, sMimeType, sExt) { - if (oItem && oItem.exportLinks) - { - if (oItem.exportLinks[sMimeType]) + window.gapi.load('auth', { + callback: () => { + const + authToken = window.gapi.auth.getToken(), + fResult = (authResult) => { + if (authResult && !authResult.error) { - oResponse.downloadUrl = oItem.exportLinks[sMimeType]; - oResponse.title = oItem.title + '.' + sExt; - oResponse.mimeType = sMimeType; + const token = window.gapi.auth.getToken(); + if (token) + { + this.driveCreatePiker(token); + } + + return true; } - else if (oItem.exportLinks['application/pdf']) - { - oResponse.downloadUrl = oItem.exportLinks['application/pdf']; - oResponse.title = oItem.title + '.pdf'; - oResponse.mimeType = 'application/pdf'; - } - } - }; - if (oResponse && !oResponse.downloadUrl && oResponse.mimeType && oResponse.exportLinks) - { - switch (oResponse.mimeType.toString().toLowerCase()) - { - case 'application/vnd.google-apps.document': - fExport(oResponse, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'docx'); - break; - case 'application/vnd.google-apps.spreadsheet': - fExport(oResponse, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xlsx'); - break; - case 'application/vnd.google-apps.drawing': - fExport(oResponse, 'image/png', 'png'); - break; - case 'application/vnd.google-apps.presentation': - fExport(oResponse, 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'pptx'); - break; - default: - fExport(oResponse, 'application/pdf', 'pdf'); - break; - } - } + return false; + }; - if (oResponse && oResponse.downloadUrl) - { - self.addDriveAttachment(oResponse, sAccessToken); - } - } - }); - - oRequest.send(); - } -}; - -ComposePopupView.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(window.google.picker.ViewId.FOLDERS) - .addView(window.google.picker.ViewId.DOCS) - .setAppId(Settings.settingsGet('GoogleClientID')) - .setOAuthToken(oOauthToken.access_token) - .setCallback(_.bind(self.driveCallback, self, oOauthToken.access_token)) - .enableFeature(window.google.picker.Feature.NAV_HIDDEN) - // .setOrigin(window.location.protocol + '//' + window.location.host) - .build(); - - drivePicker.setVisible(true); - } - }}); - } -}; - -ComposePopupView.prototype.driveOpenPopup = function() -{ - if (window.gapi) - { - var self = this; - - window.gapi.load('auth', {'callback': function() { - - var - oAuthToken = window.gapi.auth.getToken(), - fResult = function(oAuthResult) { - if (oAuthResult && !oAuthResult.error) - { - var oToken = window.gapi.auth.getToken(); - if (oToken) - { - self.driveCreatePiker(oToken); - } - - return true; - } - - return false; - }; - - if (!oAuthToken) - { - window.gapi.auth.authorize({ - 'client_id': Settings.settingsGet('GoogleClientID'), - 'scope': 'https://www.googleapis.com/auth/drive.readonly', - 'immediate': true - }, function(oAuthResult) { - - if (!fResult(oAuthResult)) + if (!authToken) { window.gapi.auth.authorize({ 'client_id': Settings.settingsGet('GoogleClientID'), 'scope': 'https://www.googleapis.com/auth/drive.readonly', - 'immediate': false - }, fResult); + 'immediate': true + }, (authResult) => { + if (!fResult(authResult)) + { + window.gapi.auth.authorize({ + 'client_id': Settings.settingsGet('GoogleClientID'), + 'scope': 'https://www.googleapis.com/auth/drive.readonly', + 'immediate': false + }, fResult); + } + }); } - }); - } - else - { - self.driveCreatePiker(oAuthToken); - } - }}); - } -}; - -/** - * @param {string} sId - * @returns {?Object} - */ -ComposePopupView.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]; + else + { + this.driveCreatePiker(authToken); + } + } + }); } } - return null; -}; + /** + * @param {string} id + * @returns {?Object} + */ + getAttachmentById(id) { + return _.find(this.attachments(), (item) => item && id === item.id); + } -ComposePopupView.prototype.cancelAttachmentHelper = function(sId, oJua) { + cancelAttachmentHelper(id, oJua) { + return () => { + const attachment = _.find(this.attachments(), (item) => item && item.id === id); + if (attachment) + { + this.attachments.remove(attachment); + delegateRunOnDestroy(attachment); - var self = this; - return function() { + if (oJua) + { + oJua.cancel(id); + } + } + }; + } - var attachment = _.find(self.attachments(), function(oItem) { - return oItem && oItem.id === sId; - }); - - if (attachment) + initUploader() { + if (this.composeUploaderButton()) { - self.attachments.remove(attachment); - Utils.delegateRunOnDestroy(attachment); + const + uploadCache = {}, + attachmentSizeLimit = pInt(Settings.settingsGet('AttachmentLimit')), + oJua = new Jua({ + 'action': upload(), + 'name': 'uploader', + 'queueSize': 2, + 'multipleSizeLimit': 50, + 'clickElement': this.composeUploaderButton(), + 'dragAndDropElement': this.composeUploaderDropPlace() + }); if (oJua) { - oJua.cancel(sId); + oJua + // .on('onLimitReached', (limit) => { + // alert(limit); + // }) + .on('onDragEnter', () => { + this.dragAndDropOver(true); + }) + .on('onDragLeave', () => { + this.dragAndDropOver(false); + }) + .on('onBodyDragEnter', () => { + this.attachmentsPlace(true); + this.dragAndDropVisible(true); + }) + .on('onBodyDragLeave', () => { + this.dragAndDropVisible(false); + }) + .on('onProgress', (id, loaded, total) => { + + let item = uploadCache[id]; + if (!item) + { + item = this.getAttachmentById(id); + if (item) + { + uploadCache[id] = item; + } + } + + if (item) + { + item.progress(window.Math.floor(loaded / total * 100)); + } + + }) + .on('onSelect', (sId, oData) => { + + this.dragAndDropOver(false); + + const + fileName = isUnd(oData.FileName) ? '' : oData.FileName.toString(), + size = isNormal(oData.Size) ? pInt(oData.Size) : null, + attachment = new ComposeAttachmentModel(sId, fileName, size); + + attachment.cancel = this.cancelAttachmentHelper(sId, oJua); + + this.attachments.push(attachment); + + this.attachmentsPlace(true); + + if (0 < size && 0 < attachmentSizeLimit && attachmentSizeLimit < size) + { + attachment + .waiting(false).uploading(true).complete(true) + .error(i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG')); + + return false; + } + + return true; + }) + .on('onStart', (id) => { + + let item = uploadCache[id]; + if (!item) + { + item = this.getAttachmentById(id); + if (item) + { + uploadCache[id] = item; + } + } + + if (item) + { + item.waiting(false).uploading(true).complete(false); + } + }) + .on('onComplete', (id, result, data) => { + + const + attachment = this.getAttachmentById(id), + errorCode = data && data.Result && data.Result.ErrorCode ? data.Result.ErrorCode : null, + attachmentJson = result && data && data.Result && data.Result.Attachment ? data.Result.Attachment : null; + + let error = ''; + if (null !== errorCode) + { + error = getUploadErrorDescByCode(errorCode); + } + else if (!attachmentJson) + { + error = i18n('UPLOAD/ERROR_UNKNOWN'); + } + + if (attachment) + { + if ('' !== error && 0 < error.length) + { + attachment + .waiting(false) + .uploading(false) + .complete(true) + .error(error); + } + else if (attachmentJson) + { + attachment + .waiting(false) + .uploading(false) + .complete(true); + + attachment.initByUploadJson(attachmentJson); + } + + if (isUnd(uploadCache[id])) + { + delete (uploadCache[id]); + } + } + }); + + this + .addAttachmentEnabled(true) + .dragAndDropEnabled(oJua.isDragAndDropSupported()); } - } - }; - -}; - -ComposePopupView.prototype.initUploader = function() -{ - if (this.composeUploaderButton()) - { - var - oUploadCache = {}, - iAttachmentSizeLimit = Utils.pInt(Settings.settingsGet('AttachmentLimit')), - oJua = new Jua({ - 'action': Links.upload(), - 'name': 'uploader', - 'queueSize': 2, - 'multipleSizeLimit': 50, - '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.attachmentsPlace(true); - this.dragAndDropVisible(true); - }, this)) - .on('onBodyDragLeave', _.bind(function() { - this.dragAndDropVisible(false); - }, this)) - .on('onProgress', _.bind(function(sId, iLoaded, iTotal) { - - var oItem = oUploadCache[sId]; - if (!oItem) - { - oItem = this.getAttachmentById(sId); - if (oItem) - { - oUploadCache[sId] = oItem; - } - } - - if (oItem) - { - oItem.progress(window.Math.floor(iLoaded / iTotal * 100)); - } - - }, this)) - .on('onSelect', _.bind(function(sId, oData) { - - this.dragAndDropOver(false); - - var - self = 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 = self.cancelAttachmentHelper(sId, oJua); - - this.attachments.push(oAttachment); - - this.attachmentsPlace(true); - - if (0 < mSize && 0 < iAttachmentSizeLimit && iAttachmentSizeLimit < mSize) - { - oAttachment - .waiting(false).uploading(true).complete(true) - .error(Translator.i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG')); - - return false; - } - - return true; - - }, this)) - .on('onStart', _.bind(function(sId) { - - var oItem = oUploadCache[sId]; - if (!oItem) - { - oItem = this.getAttachmentById(sId); - if (oItem) - { - oUploadCache[sId] = oItem; - } - } - - if (oItem) - { - oItem.waiting(false).uploading(true).complete(false); - } - - }, this)) - .on('onComplete', _.bind(function(sId, bResult, oData) { - - var - sError = '', - oAttachment = this.getAttachmentById(sId), - mErrorCode = oData && oData.Result && oData.Result.ErrorCode ? oData.Result.ErrorCode : null, - oAttachmentJson = bResult && oData && oData.Result && oData.Result.Attachment ? oData.Result.Attachment : null; - - if (null !== mErrorCode) - { - sError = Translator.getUploadErrorDescByCode(mErrorCode); - } - else if (!oAttachmentJson) - { - sError = Translator.i18n('UPLOAD/ERROR_UNKNOWN'); - } - - if (oAttachment) - { - if ('' !== sError && 0 < sError.length) - { - oAttachment - .waiting(false) - .uploading(false) - .complete(true) - .error(sError); - } - else if (oAttachmentJson) - { - oAttachment - .waiting(false) - .uploading(false) - .complete(true); - - oAttachment.initByUploadJson(oAttachmentJson); - } - - if (Utils.isUnd(oUploadCache[sId])) - { - delete (oUploadCache[sId]); - } - } - - }, this)); - - this - .addAttachmentEnabled(true) - .dragAndDropEnabled(oJua.isDragAndDropSupported()); - } - else - { - this - .addAttachmentEnabled(false) - .dragAndDropEnabled(false); - } - } -}; - -/** - * @returns {Object} - */ -ComposePopupView.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 - */ -ComposePopupView.prototype.addMessageAsAttachment = function(oMessage) -{ - if (oMessage) - { - var sTemp = oMessage.subject(); - sTemp = '.eml' === sTemp.substr(-4).toLowerCase() ? sTemp : sTemp + '.eml'; - - var oAttachment = new ComposeAttachmentModel( - oMessage.requestHash, sTemp, oMessage.size() - ); - - oAttachment.fromMessage = true; - oAttachment.cancel = this.cancelAttachmentHelper(oMessage.requestHash); - oAttachment.waiting(false).uploading(true).complete(true); - - this.attachments.push(oAttachment); - } -}; - -/** - * @param {string} url - * @param {string} name - * @param {number} size - * @returns {ComposeAttachmentModel} - */ -ComposePopupView.prototype.addAttachmentHelper = function(url, name, size) -{ - var oAttachment = new ComposeAttachmentModel(url, name, size); - - oAttachment.fromMessage = false; - oAttachment.cancel = this.cancelAttachmentHelper(url); - oAttachment.waiting(false).uploading(true).complete(false); - - this.attachments.push(oAttachment); - - this.attachmentsPlace(true); - - return oAttachment; -}; - -/** - * @param {Object} oDropboxFile - * @returns {boolean} - */ -ComposePopupView.prototype.addDropboxAttachment = function(oDropboxFile) -{ - var - iAttachmentSizeLimit = Utils.pInt(Settings.settingsGet('AttachmentLimit')), - mSize = oDropboxFile.bytes, - oAttachment = this.addAttachmentHelper(oDropboxFile.link, oDropboxFile.name, mSize); - - if (0 < mSize && 0 < iAttachmentSizeLimit && iAttachmentSizeLimit < mSize) - { - oAttachment.uploading(false).complete(true); - oAttachment.error(Translator.i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG')); - return false; - } - - Remote.composeUploadExternals(function(sResult, oData) { - - var bResult = false; - oAttachment.uploading(false).complete(true); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - if (oData.Result[oAttachment.id]) + else { - bResult = true; - oAttachment.tempName(oData.Result[oAttachment.id]); + this + .addAttachmentEnabled(false) + .dragAndDropEnabled(false); } } - - if (!bResult) - { - oAttachment.error(Translator.getUploadErrorDescByCode(Enums.UploadErrorCode.FileNoUploaded)); - } - - }, [oDropboxFile.link]); - - return true; -}; - -/** - * @param {Object} oDriveFile - * @param {string} sAccessToken - * @returns {boolean} - */ -ComposePopupView.prototype.addDriveAttachment = function(oDriveFile, sAccessToken) -{ - var - iAttachmentSizeLimit = Utils.pInt(Settings.settingsGet('AttachmentLimit')), - mSize = oDriveFile.fileSize ? Utils.pInt(oDriveFile.fileSize) : 0, - oAttachment = this.addAttachmentHelper(oDriveFile.downloadUrl, oDriveFile.title, mSize); - - if (0 < mSize && 0 < iAttachmentSizeLimit && iAttachmentSizeLimit < mSize) - { - oAttachment.uploading(false).complete(true); - oAttachment.error(Translator.i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG')); - return false; } - Remote.composeUploadDrive(function(sResult, oData) { - - var bResult = false; - oAttachment.uploading(false).complete(true); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - if (oData.Result[oAttachment.id]) + /** + * @returns {Object} + */ + prepearAttachmentsForSendOrSave() { + const result = {}; + _.each(this.attachmentsInReady(), (item) => { + if (item && '' !== item.tempName() && item.enabled()) { - bResult = true; - oAttachment.tempName(oData.Result[oAttachment.id][0]); - oAttachment.size(Utils.pInt(oData.Result[oAttachment.id][1])); + result[item.tempName()] = [ + item.fileName(), + item.isInline ? '1' : '0', + item.CID, + item.contentLocation + ]; + } + }); + + return result; + } + + /** + * @param {MessageModel} message + */ + addMessageAsAttachment(message) { + if (message) + { + let temp = message.subject(); + temp = '.eml' === temp.substr(-4).toLowerCase() ? temp : temp + '.eml'; + + const attachment = new ComposeAttachmentModel( + message.requestHash, temp, message.size() + ); + + attachment.fromMessage = true; + attachment.cancel = this.cancelAttachmentHelper(message.requestHash); + attachment.waiting(false).uploading(true).complete(true); + + this.attachments.push(attachment); + } + } + + /** + * @param {string} url + * @param {string} name + * @param {number} size + * @returns {ComposeAttachmentModel} + */ + addAttachmentHelper(url, name, size) { + const attachment = new ComposeAttachmentModel(url, name, size); + + attachment.fromMessage = false; + attachment.cancel = this.cancelAttachmentHelper(url); + attachment.waiting(false).uploading(true).complete(false); + + this.attachments.push(attachment); + + this.attachmentsPlace(true); + + return attachment; + } + + /** + * @param {Object} dropboxFile + * @returns {boolean} + */ + addDropboxAttachment(dropboxFile) { + const + attachmentSizeLimit = pInt(Settings.settingsGet('AttachmentLimit')), + mSize = dropboxFile.bytes, + attachment = this.addAttachmentHelper(dropboxFile.link, dropboxFile.name, mSize); + + if (0 < mSize && 0 < attachmentSizeLimit && attachmentSizeLimit < mSize) + { + attachment.uploading(false).complete(true); + attachment.error(i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG')); + return false; + } + + Remote.composeUploadExternals((statusResult, data) => { + + let result = false; + attachment.uploading(false).complete(true); + + if (StorageResultType.Success === statusResult && data && data.Result) + { + if (data.Result[attachment.id]) + { + result = true; + attachment.tempName(data.Result[attachment.id]); + } + } + + if (!result) + { + attachment.error(getUploadErrorDescByCode(UploadErrorCode.FileNoUploaded)); + } + + }, [dropboxFile.link]); + + return true; + } + + /** + * @param {Object} driveFile + * @param {string} accessToken + * @returns {boolean} + */ + addDriveAttachment(driveFile, accessToken) { + const + attachmentSizeLimit = pInt(Settings.settingsGet('AttachmentLimit')), + size = driveFile.fileSize ? pInt(driveFile.fileSize) : 0, + attachment = this.addAttachmentHelper(driveFile.downloadUrl, driveFile.title, size); + + if (0 < size && 0 < attachmentSizeLimit && attachmentSizeLimit < size) + { + attachment.uploading(false).complete(true); + attachment.error(i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG')); + return false; + } + + Remote.composeUploadDrive((statusResult, data) => { + + let result = false; + attachment.uploading(false).complete(true); + + if (StorageResultType.Success === statusResult && data && data.Result) + { + if (data.Result[attachment.id]) + { + result = true; + attachment.tempName(data.Result[attachment.id][0]); + attachment.size(pInt(data.Result[attachment.id][1])); + } + } + + if (!result) + { + attachment.error(getUploadErrorDescByCode(UploadErrorCode.FileNoUploaded)); + } + + }, driveFile.downloadUrl, accessToken); + + return true; + } + + /** + * @param {MessageModel} message + * @param {string} type + */ + prepearMessageAttachments(message, type) { + if (message) + { + if (ComposeType.ForwardAsAttachment === type) + { + this.addMessageAsAttachment(message); + } + else + { + const attachments = message.attachments(); + _.each(isNonEmptyArray(attachments) ? attachments : [], (item) => { + let add = false; + switch (type) + { + case ComposeType.Reply: + case ComposeType.ReplyAll: + add = item.isLinked; + break; + + case ComposeType.Forward: + case ComposeType.Draft: + case ComposeType.EditAsNew: + add = true; + break; + // no default + } + + if (add) + { + const attachment = new ComposeAttachmentModel( + item.download, item.fileName, item.estimatedSize, + item.isInline, item.isLinked, item.cid, item.contentLocation + ); + + attachment.fromMessage = true; + attachment.cancel = this.cancelAttachmentHelper(item.download); + attachment.waiting(false).uploading(true).complete(false); + + this.attachments.push(attachment); + } + }); } } + } - if (!bResult) + removeLinkedAttachments() { + const arrachment = _.find(this.attachments(), (item) => item && item.isLinked); + if (arrachment) { - oAttachment.error(Translator.getUploadErrorDescByCode(Enums.UploadErrorCode.FileNoUploaded)); - } - - }, oDriveFile.downloadUrl, sAccessToken); - - return true; -}; - -/** - * @param {MessageModel} oMessage - * @param {string} sType - */ -ComposePopupView.prototype.prepearMessageAttachments = function(oMessage, sType) -{ - if (oMessage) - { - if (Enums.ComposeType.ForwardAsAttachment === sType) - { - this.addMessageAsAttachment(oMessage); - } - else - { - var aAttachments = oMessage.attachments(); - _.each(Utils.isNonEmptyArray(aAttachments) ? aAttachments : [], function(oItem) { - var 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; - // no default - } - - if (bAdd) - { - var oAttachment = new ComposeAttachmentModel( - oItem.download, oItem.fileName, oItem.estimatedSize, - oItem.isInline, oItem.isLinked, oItem.cid, oItem.contentLocation - ); - - oAttachment.fromMessage = true; - oAttachment.cancel = this.cancelAttachmentHelper(oItem.download); - oAttachment.waiting(false).uploading(true).complete(false); - - this.attachments.push(oAttachment); - } - }); + this.attachments.remove(arrachment); + delegateRunOnDestroy(arrachment); } } -}; -ComposePopupView.prototype.removeLinkedAttachments = function() -{ - var arrachment = _.find(this.attachments(), function(oItem) { - return oItem && oItem.isLinked; - }); - - if (arrachment) - { - this.attachments.remove(arrachment); - Utils.delegateRunOnDestroy(arrachment); + setMessageAttachmentFailedDownloadText() { + _.each(this.attachments(), (attachment) => { + if (attachment && attachment.fromMessage) + { + attachment + .waiting(false) + .uploading(false) + .complete(true) + .error(getUploadErrorDescByCode(UploadErrorCode.FileNoUploaded)); + } + }); } -}; -ComposePopupView.prototype.setMessageAttachmentFailedDownloadText = function() -{ - _.each(this.attachments(), function(oAttachment) { - if (oAttachment && oAttachment.fromMessage) + /** + * @param {boolean=} includeAttachmentInProgress = true + * @returns {boolean} + */ + isEmptyForm(includeAttachmentInProgress = true) { + + const withoutAttachment = includeAttachmentInProgress ? + 0 === this.attachments().length : 0 === this.attachmentsInReady().length; + + return 0 === this.to().length && + 0 === this.cc().length && + 0 === this.bcc().length && + 0 === this.replyTo().length && + 0 === this.subject().length && + withoutAttachment && + (!this.oEditor || '' === this.oEditor.getData()); + } + + reset() { + this.to(''); + this.cc(''); + this.bcc(''); + this.replyTo(''); + this.subject(''); + + this.requestDsn(false); + this.requestReadReceipt(false); + this.markAsImportant(false); + + this.attachmentsPlace(false); + + this.aDraftInfo = null; + this.sInReplyTo = ''; + this.bFromDraft = false; + this.sReferences = ''; + + this.sendError(false); + this.sendSuccessButSaveError(false); + this.savedError(false); + this.savedTime(0); + this.emptyToError(false); + this.attachmentsInProcessError(false); + + this.showCc(false); + this.showBcc(false); + this.showReplyTo(false); + + delegateRunOnDestroy(this.attachments()); + this.attachments([]); + + this.dragAndDropOver(false); + this.dragAndDropVisible(false); + + this.draftFolder(''); + this.draftUid(''); + + this.sending(false); + this.saving(false); + + if (this.oEditor) { - oAttachment - .waiting(false) - .uploading(false) - .complete(true) - .error(Translator.getUploadErrorDescByCode(Enums.UploadErrorCode.FileNoUploaded)); + this.oEditor.clear(false); } - }, this); -}; - -/** - * @param {boolean=} bIncludeAttachmentInProgress = true - * @returns {boolean} - */ -ComposePopupView.prototype.isEmptyForm = function(bIncludeAttachmentInProgress) -{ - bIncludeAttachmentInProgress = Utils.isUnd(bIncludeAttachmentInProgress) ? true : !!bIncludeAttachmentInProgress; - var bWithoutAttach = bIncludeAttachmentInProgress ? - 0 === this.attachments().length : 0 === this.attachmentsInReady().length; - - return 0 === this.to().length && - 0 === this.cc().length && - 0 === this.bcc().length && - 0 === this.replyTo().length && - 0 === this.subject().length && - bWithoutAttach && - (!this.oEditor || '' === this.oEditor.getData()); -}; - -ComposePopupView.prototype.reset = function() -{ - this.to(''); - this.cc(''); - this.bcc(''); - this.replyTo(''); - this.subject(''); - - this.requestDsn(false); - this.requestReadReceipt(false); - this.markAsImportant(false); - - this.attachmentsPlace(false); - - this.aDraftInfo = null; - this.sInReplyTo = ''; - this.bFromDraft = false; - this.sReferences = ''; - - this.sendError(false); - this.sendSuccessButSaveError(false); - this.savedError(false); - this.savedTime(0); - this.emptyToError(false); - this.attachmentsInProcessError(false); - - this.showCc(false); - this.showBcc(false); - this.showReplyTo(false); - - Utils.delegateRunOnDestroy(this.attachments()); - 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); } -}; -/** - * @returns {Array} - */ -ComposePopupView.prototype.getAttachmentsDownloadsForUpload = function() -{ - return _.map(_.filter(this.attachments(), function(oItem) { - return oItem && '' === oItem.tempName(); - }), function(oItem) { - return oItem.id; - }); -}; + /** + * @returns {Array} + */ + getAttachmentsDownloadsForUpload() { + return _.map(_.filter( + this.attachments(), (item) => item && '' === item.tempName(), + ), (item) => item.id); + } -ComposePopupView.prototype.resizerTrigger = function() -{ - this.resizer(!this.resizer()); -}; + resizerTrigger() { + this.resizer(!this.resizer()); + } +} module.exports = ComposePopupView; diff --git a/dev/View/Popup/ComposeOpenPgp.js b/dev/View/Popup/ComposeOpenPgp.js index d2e3603a6..4dc75df51 100644 --- a/dev/View/Popup/ComposeOpenPgp.js +++ b/dev/View/Popup/ComposeOpenPgp.js @@ -1,475 +1,460 @@ -var - _ = require('_'), - $ = require('$'), - ko = require('ko'), - key = require('key'), +import _ from '_'; +import $ from '$'; +import ko from 'ko'; +import key from 'key'; - Utils = require('Common/Utils'), - Enums = require('Common/Enums'), - Translator = require('Common/Translator'), +import { + inArray, createCommand, + pString, log, isUnd, trim, + defautOptionsAfterRender +} from 'Common/Utils'; - PgpStore = require('Stores/User/Pgp'), +import {Magics, KeyState} from 'Common/Enums'; +import {i18n} from 'Common/Translator'; - EmailModel = require('Model/Email').default, +import PgpStore from 'Stores/User/Pgp'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {EmailModel} from 'Model/Email'; -/** - * @constructor - * @extends AbstractView - */ -function ComposeOpenPgpPopupView() +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; + +@view({ + name: 'View/Popup/ComposeOpenPgp', + type: ViewType.Popup, + templateID: 'PopupsComposeOpenPgp' +}) +class ComposeOpenPgpPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsComposeOpenPgp'); + constructor() { + super(); - var self = this; + this.publicKeysOptionsCaption = i18n('PGP_NOTIFICATIONS/ADD_A_PUBLICK_KEY'); + this.privateKeysOptionsCaption = i18n('PGP_NOTIFICATIONS/SELECT_A_PRIVATE_KEY'); - this.publicKeysOptionsCaption = Translator.i18n('PGP_NOTIFICATIONS/ADD_A_PUBLICK_KEY'); - this.privateKeysOptionsCaption = Translator.i18n('PGP_NOTIFICATIONS/SELECT_A_PRIVATE_KEY'); + this.notification = ko.observable(''); - this.notification = ko.observable(''); + this.sign = ko.observable(false); + this.encrypt = ko.observable(false); - this.sign = ko.observable(false); - this.encrypt = ko.observable(false); + this.password = ko.observable(''); + this.password.focus = ko.observable(false); + this.buttonFocus = ko.observable(false); - this.password = ko.observable(''); - this.password.focus = ko.observable(false); - this.buttonFocus = ko.observable(false); + this.text = ko.observable(''); + this.selectedPrivateKey = ko.observable(null); + this.selectedPublicKey = ko.observable(null); - this.text = ko.observable(''); - this.selectedPrivateKey = ko.observable(null); - this.selectedPublicKey = ko.observable(null); + this.signKey = ko.observable(null); + this.encryptKeys = ko.observableArray([]); - this.signKey = ko.observable(null); - this.encryptKeys = ko.observableArray([]); + this.encryptKeysView = ko.computed( + () => _.compact(_.map(this.encryptKeys(), (oKey) => (oKey ? oKey.key : null))) + ); - this.encryptKeysView = ko.computed(function() { - return _.compact(_.map(this.encryptKeys(), function(oKey) { - return oKey ? oKey.key : null; - })); - }, this); - - this.privateKeysOptions = ko.computed(function() { - return _.compact(_.flatten(_.map(PgpStore.openpgpkeysPrivate(), function(oKey, iIndex) { - return self.signKey() && self.signKey().key.id === oKey.id ? null : _.map(oKey.users, function(sUser) { - return { + this.privateKeysOptions = ko.computed(() => { + const opts = _.map(PgpStore.openpgpkeysPrivate(), (oKey, iIndex) => { + if (this.signKey() && this.signKey().key.id === oKey.id) + { + return null; + } + return _.map(oKey.users, (user) => ({ 'id': oKey.guid, - 'name': '(' + oKey.id.substr(-8).toUpperCase() + ') ' + sUser, + 'name': '(' + oKey.id.substr(-8).toUpperCase() + ') ' + user, 'key': oKey, 'class': iIndex % 2 ? 'odd' : 'even' - }; - }); - }), true)); - }); - - this.publicKeysOptions = ko.computed(function() { - return _.compact(_.flatten(_.map(PgpStore.openpgpkeysPublic(), function(oKey, iIndex) { - return -1 < Utils.inArray(oKey, self.encryptKeysView()) ? null : _.map(oKey.users, function(sUser) { - return { - 'id': oKey.guid, - 'name': '(' + oKey.id.substr(-8).toUpperCase() + ') ' + sUser, - 'key': oKey, - 'class': iIndex % 2 ? 'odd' : 'even' - }; - }); - }), true)); - }); - - this.submitRequest = ko.observable(false); - - this.resultCallback = null; - - // commands - this.doCommand = Utils.createCommand(this, function() { - - var - bResult = true, - oPrivateKey = null, - aPublicKeys = []; - - this.submitRequest(true); - - if (bResult && this.sign()) - { - if (!this.signKey()) - { - this.notification(Translator.i18n('PGP_NOTIFICATIONS/NO_PRIVATE_KEY_FOUND')); - bResult = false; - } - else if (!this.signKey().key) - { - this.notification(Translator.i18n('PGP_NOTIFICATIONS/NO_PRIVATE_KEY_FOUND_FOR', { - 'EMAIL': this.signKey().email })); + }); - bResult = false; - } + return _.compact(_.flatten(opts, true)); + }); - if (bResult) - { - var aPrivateKeys = this.signKey().key.getNativeKeys(); - oPrivateKey = aPrivateKeys[0] || null; - - try + this.publicKeysOptions = ko.computed(() => { + const opts = _.map(PgpStore.openpgpkeysPublic(), (oKey, index) => { + if (-1 < inArray(oKey, this.encryptKeysView())) { - if (oPrivateKey) - { - oPrivateKey.decrypt(Utils.pString(this.password())); - } - } - catch (e) - { - oPrivateKey = null; + return null; } + return _.map(oKey.users, (user) => ({ + 'id': oKey.guid, + 'name': '(' + oKey.id.substr(-8).toUpperCase() + ') ' + user, + 'key': oKey, + 'class': index % 2 ? 'odd' : 'even' + })); + }); + return _.compact(_.flatten(opts, true)); + }); - if (!oPrivateKey) - { - this.notification(Translator.i18n('PGP_NOTIFICATIONS/NO_PRIVATE_KEY_FOUND')); - bResult = false; - } - } - } + this.submitRequest = ko.observable(false); - if (bResult && this.encrypt()) - { - if (0 === this.encryptKeys().length) - { - this.notification(Translator.i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND')); - bResult = false; - } - else if (this.encryptKeys()) - { + this.resultCallback = null; + + // commands + this.doCommand = createCommand(() => { + + let + result = true, + privateKey = null, aPublicKeys = []; - _.each(this.encryptKeys(), function(oKey) { - if (oKey && oKey.key) - { - aPublicKeys = aPublicKeys.concat(_.compact(_.flatten(oKey.key.getNativeKeys()))); - } - else if (oKey && oKey.email) - { - self.notification(Translator.i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND_FOR', { - 'EMAIL': oKey.email - })); + this.submitRequest(true); - bResult = false; - } - }); - - if (bResult && (0 === aPublicKeys.length || this.encryptKeys().length !== aPublicKeys.length)) + if (result && this.sign()) + { + if (!this.signKey()) { - bResult = false; + this.notification(i18n('PGP_NOTIFICATIONS/NO_PRIVATE_KEY_FOUND')); + result = false; } - } - } - - if (bResult && self.resultCallback) - { - _.delay(function() { - - var oPromise = null; - - try + else if (!this.signKey().key) { - if (oPrivateKey && 0 === aPublicKeys.length) - { - oPromise = PgpStore.openpgp.sign({ - data: self.text(), - privateKeys: [oPrivateKey] - }); - } - else if (oPrivateKey && 0 < aPublicKeys.length) - { - oPromise = PgpStore.openpgp.encrypt({ - data: self.text(), - publicKeys: aPublicKeys, - privateKeys: [oPrivateKey] - }); - } - else if (!oPrivateKey && 0 < aPublicKeys.length) - { - oPromise = PgpStore.openpgp.encrypt({ - data: self.text(), - publicKeys: aPublicKeys - }); - } - } - catch (e) - { - Utils.log(e); - - self.notification(Translator.i18n('PGP_NOTIFICATIONS/PGP_ERROR', { - 'ERROR': '' + e + this.notification(i18n('PGP_NOTIFICATIONS/NO_PRIVATE_KEY_FOUND_FOR', { + 'EMAIL': this.signKey().email })); + + result = false; } - if (oPromise) + if (result) { + const privateKeys = this.signKey().key.getNativeKeys(); + privateKey = privateKeys[0] || null; + try { - oPromise.then(function(mData) { - - self.resultCallback(mData.data); - self.cancelCommand(); - - }).then(null, function(e) { - self.notification(Translator.i18n('PGP_NOTIFICATIONS/PGP_ERROR', { - 'ERROR': '' + e - })); - }); + if (privateKey) + { + privateKey.decrypt(pString(this.password())); + } } catch (e) { - self.notification(Translator.i18n('PGP_NOTIFICATIONS/PGP_ERROR', { + privateKey = null; + } + + if (!privateKey) + { + this.notification(i18n('PGP_NOTIFICATIONS/NO_PRIVATE_KEY_FOUND')); + result = false; + } + } + } + + if (result && this.encrypt()) + { + if (0 === this.encryptKeys().length) + { + this.notification(i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND')); + result = false; + } + else if (this.encryptKeys()) + { + aPublicKeys = []; + + _.each(this.encryptKeys(), (oKey) => { + if (oKey && oKey.key) + { + aPublicKeys = aPublicKeys.concat(_.compact(_.flatten(oKey.key.getNativeKeys()))); + } + else if (oKey && oKey.email) + { + this.notification(i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND_FOR', { + 'EMAIL': oKey.email + })); + + result = false; + } + }); + + if (result && (0 === aPublicKeys.length || this.encryptKeys().length !== aPublicKeys.length)) + { + result = false; + } + } + } + + if (result && this.resultCallback) + { + _.delay(() => { + + let pgpPromise = null; + + try + { + if (privateKey && 0 === aPublicKeys.length) + { + pgpPromise = PgpStore.openpgp.sign({ + data: this.text(), + privateKeys: [privateKey] + }); + } + else if (privateKey && 0 < aPublicKeys.length) + { + pgpPromise = PgpStore.openpgp.encrypt({ + data: this.text(), + publicKeys: aPublicKeys, + privateKeys: [privateKey] + }); + } + else if (!privateKey && 0 < aPublicKeys.length) + { + pgpPromise = PgpStore.openpgp.encrypt({ + data: this.text(), + publicKeys: aPublicKeys + }); + } + } + catch (e) + { + log(e); + + this.notification(i18n('PGP_NOTIFICATIONS/PGP_ERROR', { 'ERROR': '' + e })); } - } - self.submitRequest(false); + if (pgpPromise) + { + try + { + pgpPromise.then((mData) => { + this.resultCallback(mData.data); + this.cancelCommand(); + }).catch((e) => { + this.notification(i18n('PGP_NOTIFICATIONS/PGP_ERROR', { + 'ERROR': '' + e + })); + }); + } + catch (e) + { + this.notification(i18n('PGP_NOTIFICATIONS/PGP_ERROR', { + 'ERROR': '' + e + })); + } + } - }, Enums.Magics.Time20ms); + this.submitRequest(false); + + }, Magics.Time20ms); + } + else + { + this.submitRequest(false); + } + + return result; + + }, () => !this.submitRequest() && (this.sign() || this.encrypt())); + + this.selectCommand = createCommand(() => { + + const + keyId = this.selectedPrivateKey(), + option = keyId ? _.find(this.privateKeysOptions(), (oItem) => oItem && keyId === oItem.id) : null; + + if (option) + { + this.signKey({ + 'empty': !option.key, + 'selected': ko.observable(!!option.key), + 'users': option.key.users, + 'hash': option.key.id.substr(-8).toUpperCase(), + 'key': option.key + }); + } + }); + + this.addCommand = createCommand(() => { + + const + keyId = this.selectedPublicKey(), + keys = this.encryptKeys(), + option = keyId ? _.find(this.publicKeysOptions(), (item) => (item && keyId === item.id)) : null; + + if (option) + { + keys.push({ + 'empty': !option.key, + 'selected': ko.observable(!!option.key), + 'removable': ko.observable(!this.sign() || !this.signKey() || this.signKey().key.id !== option.key.id), + 'users': option.key.users, + 'hash': option.key.id.substr(-8).toUpperCase(), + 'key': option.key + }); + + this.encryptKeys(keys); + } + }); + + this.updateCommand = createCommand(() => { + _.each(this.encryptKeys(), (oKey) => { + oKey.removable(!this.sign() || !this.signKey() || this.signKey().key.id !== oKey.key.id); + }); + }); + + this.selectedPrivateKey.subscribe((value) => { + if (value) + { + this.selectCommand(); + this.updateCommand(); + } + }); + + this.selectedPublicKey.subscribe((value) => { + if (value) + { + this.addCommand(); + } + }); + + this.sDefaultKeyScope = KeyState.PopupComposeOpenPGP; + + this.defautOptionsAfterRender = defautOptionsAfterRender; + + this.addOptionClass = (domOption, item) => { + + this.defautOptionsAfterRender(domOption, item); + + if (item && !isUnd(item.class) && domOption) + { + $(domOption).addClass(item.class); + } + }; + + this.deletePublickKey = _.bind(this.deletePublickKey, this); + } + + deletePublickKey(publicKey) { + this.encryptKeys.remove(publicKey); + } + + clearPopup() { + this.notification(''); + + this.sign(false); + this.encrypt(false); + + this.password(''); + this.password.focus(false); + this.buttonFocus(false); + + this.signKey(null); + this.encryptKeys([]); + this.text(''); + + this.resultCallback = null; + } + + onBuild() { + key('tab,shift+tab', KeyState.PopupComposeOpenPGP, () => { + switch (true) + { + case this.password.focus(): + this.buttonFocus(true); + break; + case this.buttonFocus(): + this.password.focus(true); + break; + // no default + } + return false; + }); + } + + onHideWithDelay() { + this.clearPopup(); + } + + onShowWithDelay() { + if (this.sign()) + { + this.password.focus(true); } else { - self.submitRequest(false); - } - - return bResult; - - }, function() { - return !this.submitRequest() && (this.sign() || this.encrypt()); - }); - - this.selectCommand = Utils.createCommand(this, function() { - - var - sKeyId = this.selectedPrivateKey(), - oOption = sKeyId ? _.find(this.privateKeysOptions(), function(oItem) { - return oItem && sKeyId === oItem.id; - }) : null; - - if (oOption) - { - this.signKey({ - 'empty': !oOption.key, - 'selected': ko.observable(!!oOption.key), - 'users': oOption.key.users, - 'hash': oOption.key.id.substr(-8).toUpperCase(), - 'key': oOption.key - }); - } - }); - - this.addCommand = Utils.createCommand(this, function() { - - var - sKeyId = this.selectedPublicKey(), - aKeys = this.encryptKeys(), - oOption = sKeyId ? _.find(this.publicKeysOptions(), function(oItem) { - return oItem && sKeyId === oItem.id; - }) : null; - - if (oOption) - { - aKeys.push({ - 'empty': !oOption.key, - 'selected': ko.observable(!!oOption.key), - 'removable': ko.observable(!this.sign() || !this.signKey() || this.signKey().key.id !== oOption.key.id), - 'users': oOption.key.users, - 'hash': oOption.key.id.substr(-8).toUpperCase(), - 'key': oOption.key - }); - - this.encryptKeys(aKeys); - } - }); - - this.updateCommand = Utils.createCommand(this, function() { - _.each(this.encryptKeys(), function(oKey) { - oKey.removable(!self.sign() || !self.signKey() || self.signKey().key.id !== oKey.key.id); - }); - }); - - this.selectedPrivateKey.subscribe(function(sValue) { - if (sValue) - { - this.selectCommand(); - this.updateCommand(); - } - }, this); - - this.selectedPublicKey.subscribe(function(sValue) { - if (sValue) - { - this.addCommand(); - } - }, this); - - this.sDefaultKeyScope = Enums.KeyState.PopupComposeOpenPGP; - - this.defautOptionsAfterRender = Utils.defautOptionsAfterRender; - - this.addOptionClass = function(oDomOption, oItem) { - - self.defautOptionsAfterRender(oDomOption, oItem); - - if (oItem && !Utils.isUnd(oItem.class) && oDomOption) - { - $(oDomOption).addClass(oItem.class); - } - }; - - this.deletePublickKey = _.bind(this.deletePublickKey, this); - - kn.constructorEnd(this); -} - -kn.extendAsViewModel(['View/Popup/ComposeOpenPgp', 'PopupsComposeOpenPgpViewModel'], ComposeOpenPgpPopupView); -_.extend(ComposeOpenPgpPopupView.prototype, AbstractView.prototype); - -ComposeOpenPgpPopupView.prototype.deletePublickKey = function(oKey) -{ - this.encryptKeys.remove(oKey); -}; - -ComposeOpenPgpPopupView.prototype.clearPopup = function() -{ - this.notification(''); - - this.sign(false); - this.encrypt(false); - - this.password(''); - this.password.focus(false); - this.buttonFocus(false); - - this.signKey(null); - this.encryptKeys([]); - this.text(''); - - this.resultCallback = null; -}; - -ComposeOpenPgpPopupView.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; - // no default - } - - return false; - - }, this)); -}; - -ComposeOpenPgpPopupView.prototype.onHideWithDelay = function() -{ - this.clearPopup(); -}; - -ComposeOpenPgpPopupView.prototype.onShowWithDelay = function() -{ - if (this.sign()) - { - this.password.focus(true); - } - else - { - this.buttonFocus(true); - } -}; - -ComposeOpenPgpPopupView.prototype.onShow = function(fCallback, sText, oIdentity, sTo, sCc, sBcc) -{ - this.clearPopup(); - - var - self = this, - aRec = [], - sEmail = '', - oEmail = new EmailModel(); - - this.resultCallback = fCallback; - - 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; - })); - - if (oIdentity && oIdentity.email()) - { - sEmail = oIdentity.email(); - aRec.unshift(sEmail); - - var aKeys = PgpStore.findAllPrivateKeysByEmailNotNative(sEmail); - if (aKeys && aKeys[0]) - { - this.signKey({ - 'users': aKeys[0].users || [sEmail], - 'hash': aKeys[0].id.substr(-8).toUpperCase(), - 'key': aKeys[0] - }); + this.buttonFocus(true); } } - if (this.signKey()) - { - this.sign(true); - } + onShow(fCallback, sText, identity, sTo, sCc, sBcc) { - if (aRec && 0 < aRec.length) - { - this.encryptKeys(_.uniq(_.compact(_.flatten(_.map(aRec, function(sRecEmail) { - var keys = PgpStore.findAllPublicKeysByEmailNotNative(sRecEmail); - return keys ? _.map(keys, function(oKey) { - return { - 'empty': !oKey, - 'selected': ko.observable(!!oKey), - 'removable': ko.observable(!self.sign() || !self.signKey() || self.signKey().key.id !== oKey.id), - 'users': oKey ? (oKey.users || [sRecEmail]) : [sRecEmail], - 'hash': oKey ? oKey.id.substr(-8).toUpperCase() : '', - 'key': oKey - }; - }) : []; - }), true)), function(oEncryptKey) { - return oEncryptKey.hash; + this.clearPopup(); + + let + rec = [], + emailLine = ''; + + const email = new EmailModel(); + + this.resultCallback = fCallback; + + if ('' !== sTo) + { + rec.push(sTo); + } + + if ('' !== sCc) + { + rec.push(sCc); + } + + if ('' !== sBcc) + { + rec.push(sBcc); + } + + rec = rec.join(', ').split(','); + rec = _.compact(_.map(rec, (value) => { + email.clear(); + email.mailsoParse(trim(value)); + return '' === email.email ? false : email.email; })); - if (0 < this.encryptKeys().length) + if (identity && identity.email()) { - this.encrypt(true); - } - } + emailLine = identity.email(); + rec.unshift(emailLine); - this.text(sText); -}; + const keys = PgpStore.findAllPrivateKeysByEmailNotNative(emailLine); + if (keys && keys[0]) + { + this.signKey({ + 'users': keys[0].users || [emailLine], + 'hash': keys[0].id.substr(-8).toUpperCase(), + 'key': keys[0] + }); + } + } + + if (this.signKey()) + { + this.sign(true); + } + + if (rec && 0 < rec.length) + { + this.encryptKeys(_.uniq(_.compact(_.flatten(_.map(rec, (recEmail) => { + const keys = PgpStore.findAllPublicKeysByEmailNotNative(recEmail); + return keys ? _.map(keys, (oKey) => ({ + 'empty': !oKey, + 'selected': ko.observable(!!oKey), + 'removable': ko.observable(!this.sign() || !this.signKey() || this.signKey().key.id !== oKey.id), + 'users': oKey ? (oKey.users || [recEmail]) : [recEmail], + 'hash': oKey ? oKey.id.substr(-8).toUpperCase() : '', + 'key': oKey + })) : []; + }), true)), (encryptKey) => encryptKey.hash)); + + if (0 < this.encryptKeys().length) + { + this.encrypt(true); + } + } + + this.text(sText); + } +} module.exports = ComposeOpenPgpPopupView; diff --git a/dev/View/Popup/Contacts.js b/dev/View/Popup/Contacts.js index be6e77ed5..5edbdb7da 100644 --- a/dev/View/Popup/Contacts.js +++ b/dev/View/Popup/Contacts.js @@ -1,777 +1,725 @@ -var - window = require('window'), - _ = require('_'), - $ = require('$'), - ko = require('ko'), - key = require('key'), +import window from 'window'; +import _ from '_'; +import $ from '$'; +import ko from 'ko'; +import key from 'key'; +import Jua from 'Jua'; - Jua = require('Jua'), +import { + SaveSettingsStep, ContactPropertyType, ComposeType, + Capa, Magics, StorageResultType, Notification, KeyState +} from 'Common/Enums'; - Enums = require('Common/Enums'), - Consts = require('Common/Consts'), - Globals = require('Common/Globals'), - Utils = require('Common/Utils'), - Selector = require('Common/Selector'), - Links = require('Common/Links'), - Translator = require('Common/Translator'), +import { + delegateRunOnDestroy, computedPagenatorHelper, + inArray, trim, windowResizeCallback, createCommand, + isNonEmptyArray, fakeMd5, pInt, isUnd +} from 'Common/Utils'; - SettingsStore = require('Stores/User/Settings'), - ContactStore = require('Stores/User/Contact'), +import {CONTACTS_PER_PAGE} from 'Common/Consts'; +import {bMobileDevice} from 'Common/Globals'; - Settings = require('Storage/Settings'), +import {Selector} from 'Common/Selector'; +import {exportContactsVcf, exportContactsCsv, uploadContacts} from 'Common/Links'; +import {i18n, getNotification} from 'Common/Translator'; - Remote = require('Remote/User/Ajax'), +import SettingsStore from 'Stores/User/Settings'; +import ContactStore from 'Stores/User/Contact'; - EmailModel = require('Model/Email').default, - ContactModel = require('Model/Contact').default, - ContactPropertyModel = require('Model/ContactProperty').default, +import Remote from 'Remote/User/Ajax'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import * as Settings from 'Storage/Settings'; -/** - * @constructor - * @extends AbstractView - */ -function ContactsPopupView() +import {EmailModel} from 'Model/Email'; +import {ContactModel} from 'Model/Contact'; +import {ContactPropertyModel} from 'Model/ContactProperty'; + +import {getApp} from 'Helper/Apps/User'; + +import {view, ViewType, showScreenPopup, hideScreenPopup, routeOn, routeOff} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; + +@view({ + name: 'View/Popup/Contacts', + type: ViewType.Popup, + templateID: 'PopupsContacts' +}) +class ContactsPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsContacts'); + constructor() { + super(); - var - self = this, - fFastClearEmptyListHelper = function(aList) { - if (aList && 0 < aList.length) { - self.viewProperties.removeAll(aList); - Utils.delegateRunOnDestroy(aList); - } - }; - - this.bBackToCompose = false; - this.sLastComposeFocusedField = ''; - - this.allowContactsSync = ContactStore.allowContactsSync; - this.enableContactsSync = ContactStore.enableContactsSync; - this.allowExport = !Globals.bMobileDevice; - - this.search = ko.observable(''); - this.contactsCount = ko.observable(0); - this.contacts = ContactStore.contacts; - - this.currentContact = ko.observable(null); - - this.importUploaderButton = ko.observable(null); - - this.contactsPage = ko.observable(1); - this.contactsPageCount = ko.computed(function() { - var iPage = window.Math.ceil(this.contactsCount() / Consts.CONTACTS_PER_PAGE); - return 0 >= iPage ? 1 : iPage; - }, this); - - this.contactsPagenator = ko.computed(Utils.computedPagenatorHelper(this.contactsPage, this.contactsPageCount)); - - this.emptySelection = ko.observable(true); - this.viewClearSearch = ko.observable(false); - - this.viewID = ko.observable(''); - this.viewReadOnly = ko.observable(false); - this.viewProperties = ko.observableArray([]); - - this.viewSaveTrigger = ko.observable(Enums.SaveSettingsStep.Idle); - - this.viewPropertiesNames = this.viewProperties.filter(function(oProperty) { - return -1 < Utils.inArray(oProperty.type(), [ - Enums.ContactPropertyType.FirstName, Enums.ContactPropertyType.LastName - ]); - }); - - this.viewPropertiesOther = this.viewProperties.filter(function(oProperty) { - return -1 < Utils.inArray(oProperty.type(), [ - Enums.ContactPropertyType.Note - ]); - }); - - this.viewPropertiesOther = ko.computed(function() { - - var aList = _.filter(this.viewProperties(), function(oProperty) { - return -1 < Utils.inArray(oProperty.type(), [ - Enums.ContactPropertyType.Nick - ]); - }); - - return _.sortBy(aList, function(oProperty) { - return oProperty.type(); - }); - - }, this); - - this.viewPropertiesEmails = this.viewProperties.filter(function(oProperty) { - return Enums.ContactPropertyType.Email === oProperty.type(); - }); - - this.viewPropertiesWeb = this.viewProperties.filter(function(oProperty) { - return Enums.ContactPropertyType.Web === oProperty.type(); - }); - - this.viewHasNonEmptyRequaredProperties = ko.computed(function() { - - var - aNames = this.viewPropertiesNames(), - aEmail = this.viewPropertiesEmails(), - fHelper = function(oProperty) { - return '' !== Utils.trim(oProperty.value()); + const + fFastClearEmptyListHelper = (list) => { + if (list && 0 < list.length) { + this.viewProperties.removeAll(list); + delegateRunOnDestroy(list); + } }; - return !!(_.find(aNames, fHelper) || _.find(aEmail, fHelper)); - }, this); + this.bBackToCompose = false; + this.sLastComposeFocusedField = ''; - this.viewPropertiesPhones = this.viewProperties.filter(function(oProperty) { - return Enums.ContactPropertyType.Phone === oProperty.type(); - }); + this.allowContactsSync = ContactStore.allowContactsSync; + this.enableContactsSync = ContactStore.enableContactsSync; + this.allowExport = !bMobileDevice; - this.viewPropertiesEmailsNonEmpty = this.viewPropertiesNames.filter(function(oProperty) { - return '' !== Utils.trim(oProperty.value()); - }); + this.search = ko.observable(''); + this.contactsCount = ko.observable(0); + this.contacts = ContactStore.contacts; - this.viewPropertiesEmailsEmptyAndOnFocused = this.viewPropertiesEmails.filter(function(oProperty) { - var bF = oProperty.focused(); - return '' === Utils.trim(oProperty.value()) && !bF; - }); + this.currentContact = ko.observable(null); - this.viewPropertiesPhonesEmptyAndOnFocused = this.viewPropertiesPhones.filter(function(oProperty) { - var bF = oProperty.focused(); - return '' === Utils.trim(oProperty.value()) && !bF; - }); + this.importUploaderButton = ko.observable(null); - this.viewPropertiesWebEmptyAndOnFocused = this.viewPropertiesWeb.filter(function(oProperty) { - var bF = oProperty.focused(); - return '' === Utils.trim(oProperty.value()) && !bF; - }); - - this.viewPropertiesOtherEmptyAndOnFocused = ko.computed(function() { - return _.filter(this.viewPropertiesOther(), 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 = SettingsStore.useCheckboxesInList; - - this.search.subscribe(function() { - this.reloadContactList(); - }, this); - - this.contacts.subscribe(Utils.windowResizeCallback); - this.viewProperties.subscribe(Utils.windowResizeCallback); - - 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.Selector(this.contacts, this.currentContact, null, - '.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); - }, function() { - return 0 < this.contactsCheckedOrSelected().length; - }); - - this.newMessageCommand = Utils.createCommand(this, function() { - - if (!Settings.capa(Enums.Capa.Composer)) - { - return false; - } - - var - aE = [], - aC = this.contactsCheckedOrSelected(), - aToEmails = null, - aCcEmails = null, - aBccEmails = null; - - 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()) - { - return oEmail; - } - } - - return null; - }); - - aE = _.compact(aE); - } - - if (Utils.isNonEmptyArray(aE)) - { - self.bBackToCompose = false; - - kn.hideScreenPopup(require('View/Popup/Contacts')); - - switch (self.sLastComposeFocusedField) - { - case 'cc': - aCcEmails = aE; - break; - case 'bcc': - aBccEmails = aE; - break; - case 'to': - default: - aToEmails = aE; - break; - } - - self.sLastComposeFocusedField = ''; - - _.delay(function() { - kn.showScreenPopup(require('View/Popup/Compose'), - [Enums.ComposeType.Empty, null, aToEmails, aCcEmails, aBccEmails]); - }, Enums.Magics.Time200ms); - } - - return true; - - }, 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()]); - } + this.contactsPage = ko.observable(1); + this.contactsPageCount = ko.computed(() => { + const iPage = window.Math.ceil(this.contactsCount() / CONTACTS_PER_PAGE); + return 0 >= iPage ? 1 : iPage; }); - Remote.contactSave(function(sResult, oData) { + this.contactsPagenator = ko.computed(computedPagenatorHelper(this.contactsPage, this.contactsPageCount)); - var bRes = false; - self.viewSaving(false); + this.emptySelection = ko.observable(true); + this.viewClearSearch = ko.observable(false); - if (Enums.StorageResultType.Success === sResult && oData && oData.Result && - oData.Result.RequestUid === sRequestUid && 0 < Utils.pInt(oData.Result.ResultID)) - { - if ('' === self.viewID()) - { - self.viewID(Utils.pInt(oData.Result.ResultID)); - } + this.viewID = ko.observable(''); + this.viewReadOnly = ko.observable(false); + this.viewProperties = ko.observableArray([]); - self.reloadContactList(); - bRes = true; - } + this.viewSaveTrigger = ko.observable(SaveSettingsStep.Idle); - _.delay(function() { - self.viewSaveTrigger(bRes ? Enums.SaveSettingsStep.TrueResult : Enums.SaveSettingsStep.FalseResult); - }, Enums.Magics.Time350ms); - - if (bRes) - { - self.watchDirty(false); - - _.delay(function() { - self.viewSaveTrigger(Enums.SaveSettingsStep.Idle); - }, Enums.Magics.Time1s); - } - - }, sRequestUid, this.viewID(), aProperties); - - }, function() { - var - bV = this.viewHasNonEmptyRequaredProperties(), - bReadOnly = this.viewReadOnly(); - return !this.viewSaving() && bV && !bReadOnly; - }); - - this.syncCommand = Utils.createCommand(this, function() { - - require('App/User').default.contactsSync(function(sResult, oData) { - if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) - { - window.alert(Translator.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 '' + _.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(['View/Popup/Contacts', 'PopupsContactsViewModel'], ContactsPopupView); -_.extend(ContactsPopupView.prototype, AbstractView.prototype); - -ContactsPopupView.prototype.getPropertyPlaceholder = 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; - // no default - } - - return sResult; -}; - -ContactsPopupView.prototype.addNewProperty = function(sType, sTypeStr) -{ - this.viewProperties.push(new ContactPropertyModel(sType, sTypeStr || '', '', true, this.getPropertyPlaceholder(sType))); -}; - -ContactsPopupView.prototype.addNewOrFocusProperty = function(sType, sTypeStr) -{ - var oItem = _.find(this.viewProperties(), function(oProp) { - return sType === oProp.type(); - }); - - if (oItem) - { - oItem.focused(true); - } - else - { - this.addNewProperty(sType, sTypeStr); - } -}; - -ContactsPopupView.prototype.addNewEmail = function() -{ - this.addNewProperty(Enums.ContactPropertyType.Email, 'Home'); -}; - -ContactsPopupView.prototype.addNewPhone = function() -{ - this.addNewProperty(Enums.ContactPropertyType.Phone, 'Mobile'); -}; - -ContactsPopupView.prototype.addNewWeb = function() -{ - this.addNewProperty(Enums.ContactPropertyType.Web); -}; - -ContactsPopupView.prototype.addNewNickname = function() -{ - this.addNewOrFocusProperty(Enums.ContactPropertyType.Nick); -}; - -ContactsPopupView.prototype.addNewNotes = function() -{ - this.addNewOrFocusProperty(Enums.ContactPropertyType.Note); -}; - -ContactsPopupView.prototype.addNewBirthday = function() -{ - this.addNewOrFocusProperty(Enums.ContactPropertyType.Birthday); -}; - -ContactsPopupView.prototype.exportVcf = function() -{ - require('App/User').default.download(Links.exportContactsVcf()); -}; - -ContactsPopupView.prototype.exportCsv = function() -{ - require('App/User').default.download(Links.exportContactsCsv()); -}; - -ContactsPopupView.prototype.initUploader = function() -{ - if (this.importUploaderButton()) - { - var - oJua = new Jua({ - 'action': Links.uploadContacts(), - 'name': 'uploader', - 'queueSize': 1, - 'multipleSizeLimit': 1, - '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(Translator.i18n('CONTACTS/ERROR_IMPORT_FILE')); - } - - }, this)); - } - } -}; - -ContactsPopupView.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 -= 1; - }); - - if (0 >= iCount) - { - this.bDropPageAfterDelete = true; - } - - _.delay(function() { - _.each(aContacts, function(oContact) { - oKoContacts.remove(oContact); - Utils.delegateRunOnDestroy(oContact); - }); - }, Enums.Magics.Time500ms); - } -}; - -ContactsPopupView.prototype.deleteSelectedContacts = function() -{ - if (0 < this.contactsCheckedOrSelected().length) - { - Remote.contactsDelete( - _.bind(this.deleteResponse, this), - this.contactsCheckedOrSelectedUids() + this.viewPropertiesNames = this.viewProperties.filter( + (property) => -1 < inArray(property.type(), [ContactPropertyType.FirstName, ContactPropertyType.LastName]) ); - this.removeCheckedOrSelectedContactsFromList(); - } -}; + this.viewPropertiesOther = this.viewProperties.filter( + (property) => -1 < inArray(property.type(), [ContactPropertyType.Note]) + ); -/** - * @param {string} sResult - * @param {AjaxJsonDefaultResponse} oData - */ -ContactsPopupView.prototype.deleteResponse = function(sResult, oData) -{ - if (Enums.Magics.Time500ms < (Enums.StorageResultType.Success === sResult && oData && oData.Time ? Utils.pInt(oData.Time) : 0)) - { - this.reloadContactList(this.bDropPageAfterDelete); - } - else - { - var self = this; - _.delay(function() { - self.reloadContactList(self.bDropPageAfterDelete); - }, Enums.Magics.Time500ms); - } -}; + this.viewPropertiesOther = ko.computed(() => { + const list = _.filter(this.viewProperties(), + (property) => -1 < inArray(property.type(), [ContactPropertyType.Nick]) + ); + return _.sortBy(list, (property) => property.type()); + }); -ContactsPopupView.prototype.removeProperty = function(oProp) -{ - this.viewProperties.remove(oProp); - Utils.delegateRunOnDestroy(oProp); -}; + this.viewPropertiesEmails = this.viewProperties.filter( + (property) => ContactPropertyType.Email === property.type() + ); -/** - * @param {?ContactModel} oContact - */ -ContactsPopupView.prototype.populateViewContact = function(oContact) -{ - var - sId = '', - sLastName = '', - sFirstName = '', - aList = []; + this.viewPropertiesWeb = this.viewProperties.filter( + (property) => ContactPropertyType.Web === property.type() + ); - this.watchHash(false); + this.viewHasNonEmptyRequaredProperties = ko.computed(() => { + const + names = this.viewPropertiesNames(), + emails = this.viewPropertiesEmails(), + fFilter = (property) => '' !== trim(property.value()); - this.emptySelection(false); - this.viewReadOnly(false); + return !!(_.find(names, fFilter) || _.find(emails, fFilter)); + }); - 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.viewPropertiesPhones = this.viewProperties.filter( + (property) => ContactPropertyType.Phone === property.type() + ); - this.viewReadOnly(!!oContact.readOnly); - } + this.viewPropertiesEmailsNonEmpty = this.viewPropertiesNames.filter( + (property) => '' !== trim(property.value()) + ); - aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.LastName, '', sLastName, false, - this.getPropertyPlaceholder(Enums.ContactPropertyType.LastName))); + this.viewPropertiesEmailsEmptyAndOnFocused = this.viewPropertiesEmails.filter((property) => { + const foc = property.focused(); + return '' === trim(property.value()) && !foc; + }); - aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.FirstName, '', sFirstName, !oContact, - this.getPropertyPlaceholder(Enums.ContactPropertyType.FirstName))); + this.viewPropertiesPhonesEmptyAndOnFocused = this.viewPropertiesPhones.filter((property) => { + const foc = property.focused(); + return '' === trim(property.value()) && !foc; + }); - this.viewID(sId); + this.viewPropertiesWebEmptyAndOnFocused = this.viewPropertiesWeb.filter((property) => { + const foc = property.focused(); + return '' === trim(property.value()) && !foc; + }); - Utils.delegateRunOnDestroy(this.viewProperties()); + this.viewPropertiesOtherEmptyAndOnFocused = ko.computed( + () => _.filter(this.viewPropertiesOther(), (property) => { + const foc = property.focused(); + return '' === trim(property.value()) && !foc; + }) + ); - this.viewProperties([]); - this.viewProperties(aList); + this.viewPropertiesEmailsEmptyAndOnFocused.subscribe((list) => { + fFastClearEmptyListHelper(list); + }); - this.watchDirty(false); - this.watchHash(true); -}; + this.viewPropertiesPhonesEmptyAndOnFocused.subscribe((list) => { + fFastClearEmptyListHelper(list); + }); -/** - * @param {boolean=} bDropPagePosition = false - */ -ContactsPopupView.prototype.reloadContactList = function(bDropPagePosition) -{ - var - self = this, - iOffset = (this.contactsPage() - 1) * Consts.CONTACTS_PER_PAGE; + this.viewPropertiesWebEmptyAndOnFocused.subscribe((list) => { + fFastClearEmptyListHelper(list); + }); - this.bDropPageAfterDelete = false; + this.viewPropertiesOtherEmptyAndOnFocused.subscribe((list) => { + fFastClearEmptyListHelper(list); + }); - if (Utils.isUnd(bDropPagePosition) ? false : !!bDropPagePosition) - { - this.contactsPage(1); - iOffset = 0; - } + this.viewSaving = ko.observable(false); - this.contacts.loading(true); - Remote.contacts(function(sResult, oData) { + this.useCheckboxesInList = SettingsStore.useCheckboxesInList; - var - iCount = 0, - aList = []; + this.search.subscribe(() => { + this.reloadContactList(); + }); - if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result.List) - { - if (Utils.isNonEmptyArray(oData.Result.List)) + this.contacts.subscribe(windowResizeCallback); + this.viewProperties.subscribe(windowResizeCallback); + + this.contactsChecked = ko.computed( + () => _.filter(this.contacts(), (item) => item.checked()) + ); + + this.contactsCheckedOrSelected = ko.computed(() => { + const + checked = this.contactsChecked(), + selected = this.currentContact(); + + return _.union(checked, selected ? [selected] : []); + }); + + this.contactsCheckedOrSelectedUids = ko.computed( + () => _.map(this.contactsCheckedOrSelected(), (contact) => contact.idContact) + ); + + this.selector = new Selector( + this.contacts, this.currentContact, null, + '.e-contact-item .actionHandle', '.e-contact-item.selected', + '.e-contact-item .checkboxItem', '.e-contact-item.focused'); + + this.selector.on('onItemSelect', (contact) => { + this.populateViewContact(contact ? contact : null); + if (!contact) { - 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; - } - } - - self.contactsCount(iCount); - - Utils.delegateRunOnDestroy(self.contacts()); - self.contacts(aList); - - self.contacts.loading(false); - self.viewClearSearch('' !== self.search()); - - }, iOffset, Consts.CONTACTS_PER_PAGE, this.search()); -}; - -ContactsPopupView.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; - }); - - key('c, w', Enums.KeyState.ContactList, function() { - self.newMessageCommand(); - 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.emptySelection(true); } }); - this.initUploader(); -}; + this.selector.on('onItemGetUid', (contact) => (contact ? contact.generateUid() : '')); -ContactsPopupView.prototype.onShow = function(bBackToCompose, sLastComposeFocusedField) -{ - this.bBackToCompose = Utils.isUnd(bBackToCompose) ? false : !!bBackToCompose; - this.sLastComposeFocusedField = Utils.isUnd(sLastComposeFocusedField) ? '' : sLastComposeFocusedField; + this.newCommand = createCommand(() => { + this.populateViewContact(null); + this.currentContact(null); + }); - kn.routeOff(); - this.reloadContactList(true); -}; + this.deleteCommand = createCommand(() => { + this.deleteSelectedContacts(); + this.emptySelection(true); + }, () => 0 < this.contactsCheckedOrSelected().length); -ContactsPopupView.prototype.onHide = function() -{ - kn.routeOn(); + this.newMessageCommand = createCommand(() => { - this.currentContact(null); - this.emptySelection(true); - this.search(''); - this.contactsCount(0); + if (!Settings.capa(Capa.Composer)) + { + return false; + } - Utils.delegateRunOnDestroy(this.contacts()); - this.contacts([]); + let + aE = [], + toEmails = null, + ccEmails = null, + bccEmails = null; - this.sLastComposeFocusedField = ''; + const aC = this.contactsCheckedOrSelected(); + if (isNonEmptyArray(aC)) + { + aE = _.map(aC, (oItem) => { + if (oItem) + { + const + data = oItem.getNameAndEmailHelper(), + email = data ? new EmailModel(data[0], data[1]) : null; - if (this.bBackToCompose) - { - this.bBackToCompose = false; + if (email && email.validate()) + { + return email; + } + } - if (Settings.capa(Enums.Capa.Composer)) + return null; + }); + + aE = _.compact(aE); + } + + if (isNonEmptyArray(aE)) + { + this.bBackToCompose = false; + + hideScreenPopup(require('View/Popup/Contacts')); + + switch (this.sLastComposeFocusedField) + { + case 'cc': + ccEmails = aE; + break; + case 'bcc': + bccEmails = aE; + break; + case 'to': + default: + toEmails = aE; + break; + } + + this.sLastComposeFocusedField = ''; + + _.delay(() => { + showScreenPopup(require('View/Popup/Compose'), [ComposeType.Empty, null, toEmails, ccEmails, bccEmails]); + }, Magics.Time200ms); + } + + return true; + + }, () => 0 < this.contactsCheckedOrSelected().length); + + this.clearCommand = createCommand(() => { + this.search(''); + }); + + this.saveCommand = createCommand(() => { + + this.viewSaving(true); + this.viewSaveTrigger(SaveSettingsStep.Animate); + + const + requestUid = fakeMd5(), + properties = []; + + _.each(this.viewProperties(), (oItem) => { + if (oItem.type() && '' !== trim(oItem.value())) + { + properties.push([oItem.type(), oItem.value(), oItem.typeStr()]); + } + }); + + Remote.contactSave((sResult, oData) => { + + let res = false; + this.viewSaving(false); + + if (StorageResultType.Success === sResult && oData && oData.Result && + oData.Result.RequestUid === requestUid && 0 < pInt(oData.Result.ResultID)) + { + if ('' === this.viewID()) + { + this.viewID(pInt(oData.Result.ResultID)); + } + + this.reloadContactList(); + res = true; + } + + _.delay(() => { + this.viewSaveTrigger(res ? SaveSettingsStep.TrueResult : SaveSettingsStep.FalseResult); + }, Magics.Time350ms); + + if (res) + { + this.watchDirty(false); + + _.delay(() => { + this.viewSaveTrigger(SaveSettingsStep.Idle); + }, Magics.Time1s); + } + + }, requestUid, this.viewID(), properties); + + }, () => { + const + bV = this.viewHasNonEmptyRequaredProperties(), + bReadOnly = this.viewReadOnly(); + return !this.viewSaving() && bV && !bReadOnly; + }); + + this.syncCommand = createCommand(() => { + + getApp().contactsSync((result, data) => { + if (StorageResultType.Success !== result || !data || !data.Result) + { + window.alert(getNotification( + data && data.ErrorCode ? data.ErrorCode : Notification.ContactsSyncError)); + } + + this.reloadContactList(true); + }); + + }, () => !this.contacts.syncing() && !this.contacts.importing()); + + this.bDropPageAfterDelete = false; + + this.watchDirty = ko.observable(false); + this.watchHash = ko.observable(false); + + this.viewHash = ko.computed(() => '' + _.map(this.viewProperties(), (oItem) => oItem.value()).join('')); + + // this.saveCommandDebounce = _.debounce(_.bind(this.saveCommand, this), 1000); + + this.viewHash.subscribe(() => { + if (this.watchHash() && !this.viewReadOnly() && !this.watchDirty()) + { + this.watchDirty(true); + } + }); + + this.sDefaultKeyScope = KeyState.ContactList; + } + + getPropertyPlaceholder(type) { + let result = ''; + switch (type) { - kn.showScreenPopup(require('View/Popup/Compose')); + case ContactPropertyType.LastName: + result = 'CONTACTS/PLACEHOLDER_ENTER_LAST_NAME'; + break; + case ContactPropertyType.FirstName: + result = 'CONTACTS/PLACEHOLDER_ENTER_FIRST_NAME'; + break; + case ContactPropertyType.Nick: + result = 'CONTACTS/PLACEHOLDER_ENTER_NICK_NAME'; + break; + // no default + } + + return result; + } + + addNewProperty(type, typeStr) { + this.viewProperties.push(new ContactPropertyModel(type, typeStr || '', '', true, this.getPropertyPlaceholder(type))); + } + + addNewOrFocusProperty(type, typeStr) { + const item = _.find(this.viewProperties(), (prop) => type === prop.type()); + if (item) + { + item.focused(true); + } + else + { + this.addNewProperty(type, typeStr); } } -}; + + addNewEmail() { + this.addNewProperty(ContactPropertyType.Email, 'Home'); + } + + addNewPhone() { + this.addNewProperty(ContactPropertyType.Phone, 'Mobile'); + } + + addNewWeb() { + this.addNewProperty(ContactPropertyType.Web); + } + + addNewNickname() { + this.addNewOrFocusProperty(ContactPropertyType.Nick); + } + + addNewNotes() { + this.addNewOrFocusProperty(ContactPropertyType.Note); + } + + addNewBirthday() { + this.addNewOrFocusProperty(ContactPropertyType.Birthday); + } + + exportVcf() { + getApp().download(exportContactsVcf()); + } + + exportCsv() { + getApp().download(exportContactsCsv()); + } + + initUploader() { + if (this.importUploaderButton()) + { + const + j = new Jua({ + 'action': uploadContacts(), + 'name': 'uploader', + 'queueSize': 1, + 'multipleSizeLimit': 1, + 'disableDragAndDrop': true, + 'disableMultiple': true, + 'disableDocumentDropPrevent': true, + 'clickElement': this.importUploaderButton() + }); + + if (j) + { + j + .on('onStart', () => { + this.contacts.importing(true); + }) + .on('onComplete', (id, result, data) => { + this.contacts.importing(false); + this.reloadContactList(); + if (!id || !result || !data || !data.Result) + { + window.alert(i18n('CONTACTS/ERROR_IMPORT_FILE')); + } + }); + } + } + } + + removeCheckedOrSelectedContactsFromList() { + const + koContacts = this.contacts, + contacts = this.contactsCheckedOrSelected(); + + let + currentContact = this.currentContact(), + count = this.contacts().length; + + if (0 < contacts.length) + { + _.each(contacts, (contact) => { + + if (currentContact && currentContact.idContact === contact.idContact) + { + currentContact = null; + this.currentContact(null); + } + + contact.deleted(true); + count -= 1; + }); + + if (0 >= count) + { + this.bDropPageAfterDelete = true; + } + + _.delay(() => { + _.each(contacts, (contact) => { + koContacts.remove(contact); + delegateRunOnDestroy(contact); + }); + }, Magics.Time500ms); + } + } + + deleteSelectedContacts() { + if (0 < this.contactsCheckedOrSelected().length) + { + Remote.contactsDelete( + _.bind(this.deleteResponse, this), + this.contactsCheckedOrSelectedUids() + ); + + this.removeCheckedOrSelectedContactsFromList(); + } + } + + /** + * @param {string} sResult + * @param {AjaxJsonDefaultResponse} oData + */ + deleteResponse(sResult, oData) { + if (Magics.Time500ms < (StorageResultType.Success === sResult && oData && oData.Time ? pInt(oData.Time) : 0)) + { + this.reloadContactList(this.bDropPageAfterDelete); + } + else + { + _.delay(() => { + this.reloadContactList(this.bDropPageAfterDelete); + }, Magics.Time500ms); + } + } + + removeProperty(oProp) { + this.viewProperties.remove(oProp); + delegateRunOnDestroy(oProp); + } + + /** + * @param {?ContactModel} contact + */ + populateViewContact(contact) { + let + id = '', + lastName = '', + firstName = ''; + const + list = []; + + this.watchHash(false); + + this.emptySelection(false); + this.viewReadOnly(false); + + if (contact) + { + id = contact.idContact; + if (isNonEmptyArray(contact.properties)) + { + _.each(contact.properties, (property) => { + if (property && property[0]) + { + if (ContactPropertyType.LastName === property[0]) + { + lastName = property[1]; + } + else if (ContactPropertyType.FirstName === property[0]) + { + firstName = property[1]; + } + else + { + list.push(new ContactPropertyModel(property[0], property[2] || '', property[1])); + } + } + }); + } + + this.viewReadOnly(!!contact.readOnly); + } + + list.unshift(new ContactPropertyModel(ContactPropertyType.LastName, '', lastName, false, + this.getPropertyPlaceholder(ContactPropertyType.LastName))); + + list.unshift(new ContactPropertyModel(ContactPropertyType.FirstName, '', firstName, !contact, + this.getPropertyPlaceholder(ContactPropertyType.FirstName))); + + this.viewID(id); + + delegateRunOnDestroy(this.viewProperties()); + + this.viewProperties([]); + this.viewProperties(list); + + this.watchDirty(false); + this.watchHash(true); + } + + /** + * @param {boolean=} dropPagePosition = false + */ + reloadContactList(dropPagePosition = false) { + + let offset = (this.contactsPage() - 1) * CONTACTS_PER_PAGE; + + this.bDropPageAfterDelete = false; + + if (dropPagePosition) + { + this.contactsPage(1); + offset = 0; + } + + this.contacts.loading(true); + Remote.contacts((result, data) => { + + let + count = 0, + list = []; + + if (StorageResultType.Success === result && data && data.Result && data.Result.List) + { + if (isNonEmptyArray(data.Result.List)) + { + list = _.map(data.Result.List, (item) => { + const contact = new ContactModel(); + return contact.parse(item) ? contact : null; + }); + + list = _.compact(list); + + count = pInt(data.Result.Count); + count = 0 < count ? count : 0; + } + } + + this.contactsCount(count); + + delegateRunOnDestroy(this.contacts()); + this.contacts(list); + + this.contacts.loading(false); + this.viewClearSearch('' !== this.search()); + + }, offset, CONTACTS_PER_PAGE, this.search()); + } + + onBuild(dom) { + this.oContentVisible = $('.b-list-content', dom); + this.oContentScrollable = $('.content', this.oContentVisible); + + this.selector.init(this.oContentVisible, this.oContentScrollable, KeyState.ContactList); + + key('delete', KeyState.ContactList, () => { + this.deleteCommand(); + return false; + }); + + key('c, w', KeyState.ContactList, () => { + this.newMessageCommand(); + return false; + }); + + const self = this; + + dom + .on('click', '.e-pagenator .e-page', function() { // eslint-disable-line prefer-arrow-callback + const page = ko.dataFor(this); // eslint-disable-line no-invalid-this + if (page) + { + self.contactsPage(pInt(page.value)); + self.reloadContactList(); + } + }); + + this.initUploader(); + } + + onShow(bBackToCompose, sLastComposeFocusedField) { + this.bBackToCompose = isUnd(bBackToCompose) ? false : !!bBackToCompose; + this.sLastComposeFocusedField = isUnd(sLastComposeFocusedField) ? '' : sLastComposeFocusedField; + + routeOff(); + this.reloadContactList(true); + } + + onHide() { + routeOn(); + + this.currentContact(null); + this.emptySelection(true); + this.search(''); + this.contactsCount(0); + + delegateRunOnDestroy(this.contacts()); + this.contacts([]); + + this.sLastComposeFocusedField = ''; + + if (this.bBackToCompose) + { + this.bBackToCompose = false; + + if (Settings.capa(Capa.Composer)) + { + showScreenPopup(require('View/Popup/Compose')); + } + } + } +} module.exports = ContactsPopupView; diff --git a/dev/View/Popup/Domain.js b/dev/View/Popup/Domain.js index 4d016da3d..10b19de10 100644 --- a/dev/View/Popup/Domain.js +++ b/dev/View/Popup/Domain.js @@ -1,483 +1,465 @@ -var - _ = require('_'), - ko = require('ko'), +import _ from '_'; +import ko from 'ko'; - Enums = require('Common/Enums'), - Consts = require('Common/Consts'), - Globals = require('Common/Globals'), - Utils = require('Common/Utils'), +import {StorageResultType, ServerSecure, Ports, Notification} from 'Common/Enums'; +import {IMAP_DEFAULT_PORT, SIEVE_DEFAULT_PORT, SMTP_DEFAULT_PORT} from 'Common/Consts'; +import {bMobileDevice} from 'Common/Globals'; +import {createCommand, trim, pInt, pString} from 'Common/Utils'; +import {i18n} from 'Common/Translator'; - Translator = require('Common/Translator'), +import CapaAdminStore from 'Stores/Admin/Capa'; - CapaAdminStore = require('Stores/Admin/Capa'), +import Remote from 'Remote/Admin/Ajax'; - Remote = require('Remote/Admin/Ajax'), +import {getApp} from 'Helper/Apps/Admin'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function DomainPopupView() +@view({ + name: 'View/Popup/Domain', + type: ViewType.Popup, + templateID: 'PopupsDomain' +}) +class DomainPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsDomain'); + constructor() { + super(); - this.edit = ko.observable(false); - this.saving = ko.observable(false); - this.savingError = ko.observable(''); - this.page = ko.observable('main'); - this.sieveSettings = ko.observable(false); + this.edit = ko.observable(false); + this.saving = ko.observable(false); + this.savingError = ko.observable(''); + this.page = ko.observable('main'); + this.sieveSettings = ko.observable(false); - this.testing = ko.observable(false); - this.testingDone = ko.observable(false); - this.testingImapError = ko.observable(false); - this.testingSieveError = ko.observable(false); - this.testingSmtpError = ko.observable(false); - this.testingImapErrorDesc = ko.observable(''); - this.testingSieveErrorDesc = ko.observable(''); - this.testingSmtpErrorDesc = ko.observable(''); + this.testing = ko.observable(false); + this.testingDone = ko.observable(false); + this.testingImapError = ko.observable(false); + this.testingSieveError = ko.observable(false); + this.testingSmtpError = ko.observable(false); + this.testingImapErrorDesc = ko.observable(''); + this.testingSieveErrorDesc = ko.observable(''); + this.testingSmtpErrorDesc = ko.observable(''); - this.testingImapError.subscribe(function(bValue) { - if (!bValue) - { - this.testingImapErrorDesc(''); - } - }, this); - - this.testingSieveError.subscribe(function(bValue) { - if (!bValue) - { - this.testingSieveErrorDesc(''); - } - }, this); - - this.testingSmtpError.subscribe(function(bValue) { - if (!bValue) - { - this.testingSmtpErrorDesc(''); - } - }, this); - - this.imapServerFocus = ko.observable(false); - this.sieveServerFocus = 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.IMAP_DEFAULT_PORT); - this.imapSecure = ko.observable(Enums.ServerSecure.None); - this.imapShortLogin = ko.observable(false); - this.useSieve = ko.observable(false); - this.sieveAllowRaw = ko.observable(false); - this.sieveServer = ko.observable(''); - this.sievePort = ko.observable('' + Consts.SIEVE_DEFAULT_PORT); - this.sieveSecure = ko.observable(Enums.ServerSecure.None); - this.smtpServer = ko.observable(''); - this.smtpPort = ko.observable('' + Consts.SMTP_DEFAULT_PORT); - this.smtpSecure = ko.observable(Enums.ServerSecure.None); - this.smtpShortLogin = ko.observable(false); - this.smtpAuth = ko.observable(true); - this.smtpPhpMail = ko.observable(false); - this.whiteList = ko.observable(''); - this.aliasName = ko.observable(''); - - this.enableSmartPorts = ko.observable(false); - - this.allowSieve = ko.computed(function() { - return CapaAdminStore.filters() && CapaAdminStore.sieve(); - }, this); - - this.headerText = ko.computed(function() { - - var - sName = this.name(), - sAliasName = this.aliasName(), - sResult = ''; - - if (this.edit()) - { - sResult = Translator.i18n('POPUPS_DOMAIN/TITLE_EDIT_DOMAIN', {'NAME': sName}); - if (sAliasName) + this.testingImapError.subscribe((value) => { + if (!value) { - sResult += ' ← ' + sAliasName; + this.testingImapErrorDesc(''); } - } - else - { - sResult = ('' === sName ? Translator.i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN') : - Translator.i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN_WITH_NAME', {'NAME': sName})); - } + }); - return sResult; - - }, this); - - this.domainDesc = ko.computed(function() { - var sName = this.name(); - return !this.edit() && sName ? Translator.i18n('POPUPS_DOMAIN/NEW_DOMAIN_DESC', {'NAME': '*@' + sName}) : ''; - }, this); - - this.domainIsComputed = ko.computed(function() { - - var - bPhpMail = this.smtpPhpMail(), - bAllowSieve = this.allowSieve(), - bUseSieve = this.useSieve(); - - return '' !== this.name() && - '' !== this.imapServer() && - '' !== this.imapPort() && - (bAllowSieve && bUseSieve ? ('' !== this.sieveServer() && '' !== this.sievePort()) : true) && - (('' !== this.smtpServer() && '' !== this.smtpPort()) || bPhpMail); - - }, 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.useSieve(), - this.sieveAllowRaw(), - this.sieveServer(), - Utils.pInt(this.sievePort()), - this.sieveSecure(), - - this.smtpServer(), - Utils.pInt(this.smtpPort()), - this.smtpSecure(), - this.smtpShortLogin(), - this.smtpAuth(), - this.smtpPhpMail(), - - this.whiteList() - ); - }, this.canBeSaved); - - this.testConnectionCommand = Utils.createCommand(this, function() { - - this.page('main'); - - this.testingDone(false); - this.testingImapError(false); - this.testingSieveError(false); - this.testingSmtpError(false); - this.testing(true); - - Remote.testConnectionForDomain( - _.bind(this.onTestConnectionResponse, this), - this.name(), - - this.imapServer(), - Utils.pInt(this.imapPort()), - this.imapSecure(), - - this.useSieve(), - this.sieveServer(), - Utils.pInt(this.sievePort()), - this.sieveSecure(), - - this.smtpServer(), - Utils.pInt(this.smtpPort()), - this.smtpSecure(), - this.smtpAuth(), - this.smtpPhpMail() - ); - }, this.canBeTested); - - this.whiteListCommand = Utils.createCommand(this, function() { - this.page('white-list'); - }); - - this.backCommand = Utils.createCommand(this, function() { - this.page('main'); - }); - - this.sieveCommand = Utils.createCommand(this, function() { - this.sieveSettings(!this.sieveSettings()); - this.clearTesting(); - }); - - this.page.subscribe(function() { - this.sieveSettings(false); - }, this); - - // smart form improvements - this.imapServerFocus.subscribe(function(bValue) { - if (bValue && '' !== this.name() && '' === this.imapServer()) - { - this.imapServer(this.name().replace(/[.]?[*][.]?/g, '')); - } - }, this); - - this.sieveServerFocus.subscribe(function(bValue) { - if (bValue && '' !== this.imapServer() && '' === this.sieveServer()) - { - this.sieveServer(this.imapServer()); - } - }, 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) { - if (this.enableSmartPorts()) - { - var iPort = Utils.pInt(this.imapPort()); - switch (Utils.pString(sValue)) + this.testingSieveError.subscribe((value) => { + if (!value) { - case '0': - if (Enums.Ports.ImapSsl === iPort) - { - this.imapPort(Utils.pString(Enums.Ports.Imap)); - } - break; - case '1': - if (Enums.Ports.Imap === iPort) - { - this.imapPort(Utils.pString(Enums.Ports.ImapSsl)); - } - break; - // no default + this.testingSieveErrorDesc(''); } - } - }, this); + }); - this.smtpSecure.subscribe(function(sValue) { - if (this.enableSmartPorts()) - { - var iPort = Utils.pInt(this.smtpPort()); - switch (Utils.pString(sValue)) + this.testingSmtpError.subscribe((value) => { + if (!value) { - case '0': - if (Enums.Ports.SmtpSsl === iPort || Enums.Ports.SmtpStartTls === iPort) - { - this.smtpPort(Utils.pString(Enums.Ports.Smtp)); - } - break; - case '1': - if (Enums.Ports.Smtp === iPort || Enums.Ports.SmtpStartTls === iPort) - { - this.smtpPort(Utils.pString(Enums.Ports.SmtpSsl)); - } - break; - case '2': - if (Enums.Ports.Smtp === iPort || Enums.Ports.SmtpSsl === iPort) - { - this.smtpPort(Utils.pString(Enums.Ports.SmtpStartTls)); - } - break; - // no default + this.testingSmtpErrorDesc(''); } - } - }, this); + }); - kn.constructorEnd(this); -} + this.imapServerFocus = ko.observable(false); + this.sieveServerFocus = ko.observable(false); + this.smtpServerFocus = ko.observable(false); -kn.extendAsViewModel(['View/Popup/Domain', 'PopupsDomainViewModel'], DomainPopupView); -_.extend(DomainPopupView.prototype, AbstractView.prototype); + this.name = ko.observable(''); + this.name.focused = ko.observable(false); -DomainPopupView.prototype.onTestConnectionResponse = function(sResult, oData) -{ - this.testing(false); - if (Enums.StorageResultType.Success === sResult && oData.Result) - { - var - bImap = false, - bSieve = false; + this.imapServer = ko.observable(''); + this.imapPort = ko.observable('' + IMAP_DEFAULT_PORT); + this.imapSecure = ko.observable(ServerSecure.None); + this.imapShortLogin = ko.observable(false); + this.useSieve = ko.observable(false); + this.sieveAllowRaw = ko.observable(false); + this.sieveServer = ko.observable(''); + this.sievePort = ko.observable('' + SIEVE_DEFAULT_PORT); + this.sieveSecure = ko.observable(ServerSecure.None); + this.smtpServer = ko.observable(''); + this.smtpPort = ko.observable('' + SMTP_DEFAULT_PORT); + this.smtpSecure = ko.observable(ServerSecure.None); + this.smtpShortLogin = ko.observable(false); + this.smtpAuth = ko.observable(true); + this.smtpPhpMail = ko.observable(false); + this.whiteList = ko.observable(''); + this.aliasName = ko.observable(''); - this.testingDone(true); - this.testingImapError(true !== oData.Result.Imap); - this.testingSieveError(true !== oData.Result.Sieve); - this.testingSmtpError(true !== oData.Result.Smtp); + this.enableSmartPorts = ko.observable(false); - if (this.testingImapError() && oData.Result.Imap) - { - bImap = true; - this.testingImapErrorDesc(''); - this.testingImapErrorDesc(oData.Result.Imap); - } + this.allowSieve = ko.computed(() => CapaAdminStore.filters() && CapaAdminStore.sieve()); - if (this.testingSieveError() && oData.Result.Sieve) - { - bSieve = true; - this.testingSieveErrorDesc(''); - this.testingSieveErrorDesc(oData.Result.Sieve); - } + this.headerText = ko.computed(() => { - if (this.testingSmtpError() && oData.Result.Smtp) - { - this.testingSmtpErrorDesc(''); - this.testingSmtpErrorDesc(oData.Result.Smtp); - } + const + name = this.name(), + aliasName = this.aliasName(); - if (this.sieveSettings()) - { - if (!bSieve && bImap) + let result = ''; + + if (this.edit()) { - this.sieveSettings(false); + result = i18n('POPUPS_DOMAIN/TITLE_EDIT_DOMAIN', {'NAME': name}); + if (aliasName) + { + result += ' ← ' + aliasName; + } } - } - else + else + { + result = ('' === name ? i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN') : + i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN_WITH_NAME', {'NAME': name})); + } + + return result; + + }); + + this.domainDesc = ko.computed(() => { + const name = this.name(); + return !this.edit() && name ? i18n('POPUPS_DOMAIN/NEW_DOMAIN_DESC', {'NAME': '*@' + name}) : ''; + }); + + this.domainIsComputed = ko.computed(() => { + + const + usePhpMail = this.smtpPhpMail(), + allowSieve = this.allowSieve(), + useSieve = this.useSieve(); + + return '' !== this.name() && + '' !== this.imapServer() && + '' !== this.imapPort() && + (allowSieve && useSieve ? ('' !== this.sieveServer() && '' !== this.sievePort()) : true) && + (('' !== this.smtpServer() && '' !== this.smtpPort()) || usePhpMail); + + }); + + this.canBeTested = ko.computed(() => !this.testing() && this.domainIsComputed()); + this.canBeSaved = ko.computed(() => !this.saving() && this.domainIsComputed()); + + this.createOrAddCommand = createCommand(() => { + this.saving(true); + Remote.createOrUpdateDomain( + _.bind(this.onDomainCreateOrSaveResponse, this), + !this.edit(), + this.name(), + + this.imapServer(), + pInt(this.imapPort()), + this.imapSecure(), + this.imapShortLogin(), + + this.useSieve(), + this.sieveAllowRaw(), + this.sieveServer(), + pInt(this.sievePort()), + this.sieveSecure(), + + this.smtpServer(), + pInt(this.smtpPort()), + this.smtpSecure(), + this.smtpShortLogin(), + this.smtpAuth(), + this.smtpPhpMail(), + + this.whiteList() + ); + }, this.canBeSaved); + + this.testConnectionCommand = createCommand(() => { + + this.page('main'); + + this.testingDone(false); + this.testingImapError(false); + this.testingSieveError(false); + this.testingSmtpError(false); + this.testing(true); + + Remote.testConnectionForDomain( + _.bind(this.onTestConnectionResponse, this), + this.name(), + + this.imapServer(), + pInt(this.imapPort()), + this.imapSecure(), + + this.useSieve(), + this.sieveServer(), + pInt(this.sievePort()), + this.sieveSecure(), + + this.smtpServer(), + pInt(this.smtpPort()), + this.smtpSecure(), + this.smtpAuth(), + this.smtpPhpMail() + ); + }, this.canBeTested); + + this.whiteListCommand = createCommand(() => { + this.page('white-list'); + }); + + this.backCommand = createCommand(() => { + this.page('main'); + }); + + this.sieveCommand = createCommand(() => { + this.sieveSettings(!this.sieveSettings()); + this.clearTesting(); + }); + + this.page.subscribe(() => { + this.sieveSettings(false); + }); + + // smart form improvements + this.imapServerFocus.subscribe((value) => { + if (value && '' !== this.name() && '' === this.imapServer()) + { + this.imapServer(this.name().replace(/[.]?[*][.]?/g, '')); + } + }); + + this.sieveServerFocus.subscribe((value) => { + if (value && '' !== this.imapServer() && '' === this.sieveServer()) + { + this.sieveServer(this.imapServer()); + } + }); + + this.smtpServerFocus.subscribe((value) => { + if (value && '' !== this.imapServer() && '' === this.smtpServer()) + { + this.smtpServer(this.imapServer().replace(/imap/ig, 'smtp')); + } + }); + + this.imapSecure.subscribe((value) => { + if (this.enableSmartPorts()) + { + const port = pInt(this.imapPort()); + switch (pString(value)) + { + case '0': + if (Ports.ImapSsl === port) + { + this.imapPort(pString(Ports.Imap)); + } + break; + case '1': + if (Ports.Imap === port) + { + this.imapPort(pString(Ports.ImapSsl)); + } + break; + // no default + } + } + }); + + this.smtpSecure.subscribe((value) => { + if (this.enableSmartPorts()) + { + const port = pInt(this.smtpPort()); + switch (pString(value)) + { + case '0': + if (Ports.SmtpSsl === port || Ports.SmtpStartTls === port) + { + this.smtpPort(pString(Ports.Smtp)); + } + break; + case '1': + if (Ports.Smtp === port || Ports.SmtpStartTls === port) + { + this.smtpPort(pString(Ports.SmtpSsl)); + } + break; + case '2': + if (Ports.Smtp === port || Ports.SmtpSsl === port) + { + this.smtpPort(pString(Ports.SmtpStartTls)); + } + break; + // no default + } + } + }); + } + + onTestConnectionResponse(sResult, oData) { + this.testing(false); + if (StorageResultType.Success === sResult && oData.Result) { - if (bSieve && !bImap) + let + bImap = false, + bSieve = false; + + this.testingDone(true); + this.testingImapError(true !== oData.Result.Imap); + this.testingSieveError(true !== oData.Result.Sieve); + this.testingSmtpError(true !== oData.Result.Smtp); + + if (this.testingImapError() && oData.Result.Imap) + { + bImap = true; + this.testingImapErrorDesc(''); + this.testingImapErrorDesc(oData.Result.Imap); + } + + if (this.testingSieveError() && oData.Result.Sieve) + { + bSieve = true; + this.testingSieveErrorDesc(''); + this.testingSieveErrorDesc(oData.Result.Sieve); + } + + if (this.testingSmtpError() && oData.Result.Smtp) + { + this.testingSmtpErrorDesc(''); + this.testingSmtpErrorDesc(oData.Result.Smtp); + } + + if (this.sieveSettings()) + { + if (!bSieve && bImap) + { + this.sieveSettings(false); + } + } + else if (bSieve && !bImap) { this.sieveSettings(true); } } + else + { + this.testingImapError(true); + this.testingSieveError(true); + this.testingSmtpError(true); + this.sieveSettings(false); + } } - else - { - this.testingImapError(true); - this.testingSieveError(true); - this.testingSmtpError(true); + + onDomainCreateOrSaveResponse(sResult, oData) { + this.saving(false); + if (StorageResultType.Success === sResult && oData) + { + if (oData.Result) + { + getApp().reloadDomainList(); + this.closeCommand(); + } + else if (Notification.DomainAlreadyExists === oData.ErrorCode) + { + this.savingError(i18n('ERRORS/DOMAIN_ALREADY_EXISTS')); + } + } + else + { + this.savingError(i18n('ERRORS/UNKNOWN_ERROR')); + } + } + + clearTesting() { + this.testing(false); + this.testingDone(false); + this.testingImapError(false); + this.testingSieveError(false); + this.testingSmtpError(false); + } + + onHide() { + this.page('main'); this.sieveSettings(false); } -}; -DomainPopupView.prototype.onDomainCreateOrSaveResponse = function(sResult, oData) -{ - this.saving(false); - if (Enums.StorageResultType.Success === sResult && oData) - { - if (oData.Result) + onShow(oDomain) { + this.saving(false); + + this.page('main'); + this.sieveSettings(false); + + this.clearTesting(); + + this.clearForm(); + if (oDomain) { - require('App/Admin').default.reloadDomainList(); - this.closeCommand(); - } - else if (Enums.Notification.DomainAlreadyExists === oData.ErrorCode) - { - this.savingError(Translator.i18n('ERRORS/DOMAIN_ALREADY_EXISTS')); + this.enableSmartPorts(false); + + this.edit(true); + + this.name(trim(oDomain.Name)); + this.imapServer(trim(oDomain.IncHost)); + this.imapPort('' + pInt(oDomain.IncPort)); + this.imapSecure(trim(oDomain.IncSecure)); + this.imapShortLogin(!!oDomain.IncShortLogin); + this.useSieve(!!oDomain.UseSieve); + this.sieveAllowRaw(!!oDomain.SieveAllowRaw); + this.sieveServer(trim(oDomain.SieveHost)); + this.sievePort('' + pInt(oDomain.SievePort)); + this.sieveSecure(trim(oDomain.SieveSecure)); + this.smtpServer(trim(oDomain.OutHost)); + this.smtpPort('' + pInt(oDomain.OutPort)); + this.smtpSecure(trim(oDomain.OutSecure)); + this.smtpShortLogin(!!oDomain.OutShortLogin); + this.smtpAuth(!!oDomain.OutAuth); + this.smtpPhpMail(!!oDomain.OutUsePhpMail); + this.whiteList(trim(oDomain.WhiteList)); + this.aliasName(trim(oDomain.AliasName)); + + this.enableSmartPorts(true); } } - else - { - this.savingError(Translator.i18n('ERRORS/UNKNOWN_ERROR')); + + onShowWithDelay() { + if ('' === this.name() && !bMobileDevice) + { + this.name.focused(true); + } } -}; -DomainPopupView.prototype.clearTesting = function() -{ - this.testing(false); - this.testingDone(false); - this.testingImapError(false); - this.testingSieveError(false); - this.testingSmtpError(false); -}; + clearForm() { + this.edit(false); -DomainPopupView.prototype.onHide = function() -{ - this.page('main'); - this.sieveSettings(false); -}; + this.page('main'); + this.sieveSettings(false); -DomainPopupView.prototype.onShow = function(oDomain) -{ - this.saving(false); - - this.page('main'); - this.sieveSettings(false); - - this.clearTesting(); - - this.clearForm(); - if (oDomain) - { this.enableSmartPorts(false); - this.edit(true); + this.savingError(''); - 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.useSieve(!!oDomain.UseSieve); - this.sieveAllowRaw(!!oDomain.SieveAllowRaw); - this.sieveServer(Utils.trim(oDomain.SieveHost)); - this.sievePort('' + Utils.pInt(oDomain.SievePort)); - this.sieveSecure(Utils.trim(oDomain.SieveSecure)); - 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.smtpPhpMail(!!oDomain.OutUsePhpMail); - this.whiteList(Utils.trim(oDomain.WhiteList)); - this.aliasName(Utils.trim(oDomain.AliasName)); + this.name(''); + this.name.focused(false); + this.imapServer(''); + this.imapPort('' + IMAP_DEFAULT_PORT); + this.imapSecure(ServerSecure.None); + this.imapShortLogin(false); + + this.useSieve(false); + this.sieveAllowRaw(false); + this.sieveServer(''); + this.sievePort('' + SIEVE_DEFAULT_PORT); + this.sieveSecure(ServerSecure.None); + + this.smtpServer(''); + this.smtpPort('' + SMTP_DEFAULT_PORT); + this.smtpSecure(ServerSecure.None); + this.smtpShortLogin(false); + this.smtpAuth(true); + this.smtpPhpMail(false); + + this.whiteList(''); + this.aliasName(''); this.enableSmartPorts(true); } -}; - -DomainPopupView.prototype.onShowWithDelay = function() -{ - if ('' === this.name() && !Globals.bMobile) - { - this.name.focused(true); - } -}; - -DomainPopupView.prototype.clearForm = function() -{ - this.edit(false); - - this.page('main'); - this.sieveSettings(false); - - this.enableSmartPorts(false); - - this.savingError(''); - - this.name(''); - this.name.focused(false); - - this.imapServer(''); - this.imapPort('' + Consts.IMAP_DEFAULT_PORT); - this.imapSecure(Enums.ServerSecure.None); - this.imapShortLogin(false); - - this.useSieve(false); - this.sieveAllowRaw(false); - this.sieveServer(''); - this.sievePort('' + Consts.SIEVE_DEFAULT_PORT); - this.sieveSecure(Enums.ServerSecure.None); - - this.smtpServer(''); - this.smtpPort('' + Consts.SMTP_DEFAULT_PORT); - this.smtpSecure(Enums.ServerSecure.None); - this.smtpShortLogin(false); - this.smtpAuth(true); - this.smtpPhpMail(false); - - this.whiteList(''); - this.aliasName(''); - this.enableSmartPorts(true); -}; +} module.exports = DomainPopupView; diff --git a/dev/View/Popup/DomainAlias.js b/dev/View/Popup/DomainAlias.js index 624b9dafa..589b8ca27 100644 --- a/dev/View/Popup/DomainAlias.js +++ b/dev/View/Popup/DomainAlias.js @@ -1,110 +1,99 @@ -var - _ = require('_'), - ko = require('ko'), +import _ from '_'; +import ko from 'ko'; - Enums = require('Common/Enums'), - Globals = require('Common/Globals'), - Utils = require('Common/Utils'), +import {StorageResultType, Notification} from 'Common/Enums'; +import {bMobileDevice} from 'Common/Globals'; +import {createCommand} from 'Common/Utils'; +import {i18n} from 'Common/Translator'; - Translator = require('Common/Translator'), +import DomainStore from 'Stores/Admin/Domain'; - DomainStore = require('Stores/Admin/Domain'), +import Remote from 'Remote/Admin/Ajax'; - Remote = require('Remote/Admin/Ajax'), +import {getApp} from 'Helper/Apps/Admin'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function DomainAliasPopupView() +@view({ + name: 'View/Popup/DomainAlias', + type: ViewType.Popup, + templateID: 'PopupsDomainAlias' +}) +class DomainAliasPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsDomainAlias'); + constructor() { + super(); - this.saving = ko.observable(false); - this.savingError = ko.observable(''); + this.saving = ko.observable(false); + this.savingError = ko.observable(''); - this.name = ko.observable(''); - this.name.focused = ko.observable(false); + this.name = ko.observable(''); + this.name.focused = ko.observable(false); - this.alias = ko.observable(''); + this.alias = ko.observable(''); - this.domains = DomainStore.domainsWithoutAliases; + this.domains = DomainStore.domainsWithoutAliases; - this.domainsOptions = ko.computed(function() { - return _.map(this.domains(), function(item) { - return { - optValue: item.name, - optText: item.name - }; - }); - }, this); - - this.canBeSaved = ko.computed(function() { - return !this.saving() && '' !== this.name() && '' !== this.alias(); - }, this); - - this.createCommand = Utils.createCommand(this, function() { - this.saving(true); - Remote.createDomainAlias( - _.bind(this.onDomainAliasCreateOrSaveResponse, this), - this.name(), - this.alias() + this.domainsOptions = ko.computed( + () => _.map(this.domains(), (item) => ({optValue: item.name, optText: item.name})) ); - }, this.canBeSaved); - kn.constructorEnd(this); + this.canBeSaved = ko.computed(() => !this.saving() && '' !== this.name() && '' !== this.alias()); + + this.createCommand = createCommand(() => { + this.saving(true); + Remote.createDomainAlias( + this.onDomainAliasCreateOrSaveResponse, + this.name(), + this.alias() + ); + }, this.canBeSaved); + + this.onDomainAliasCreateOrSaveResponse = _.bind(this.onDomainAliasCreateOrSaveResponse, this); + } + + onDomainAliasCreateOrSaveResponse(result, data) { + this.saving(false); + if (StorageResultType.Success === result && data) + { + if (data.Result) + { + getApp().reloadDomainList(); + this.closeCommand(); + } + else if (Notification.DomainAlreadyExists === data.ErrorCode) + { + this.savingError(i18n('ERRORS/DOMAIN_ALREADY_EXISTS')); + } + } + else + { + this.savingError(i18n('ERRORS/UNKNOWN_ERROR')); + } + } + + onShow() { + this.clearForm(); + } + + onShowWithDelay() { + if ('' === this.name() && !bMobileDevice) + { + this.name.focused(true); + } + } + + clearForm() { + this.saving(false); + this.savingError(''); + + this.name(''); + this.name.focused(false); + + this.alias(''); + } } -kn.extendAsViewModel(['View/Popup/DomainAlias', 'PopupsDomainAliasViewModel'], DomainAliasPopupView); -_.extend(DomainAliasPopupView.prototype, AbstractView.prototype); - -DomainAliasPopupView.prototype.onDomainAliasCreateOrSaveResponse = function(sResult, oData) -{ - this.saving(false); - if (Enums.StorageResultType.Success === sResult && oData) - { - if (oData.Result) - { - require('App/Admin').default.reloadDomainList(); - this.closeCommand(); - } - else if (Enums.Notification.DomainAlreadyExists === oData.ErrorCode) - { - this.savingError(Translator.i18n('ERRORS/DOMAIN_ALREADY_EXISTS')); - } - } - else - { - this.savingError(Translator.i18n('ERRORS/UNKNOWN_ERROR')); - } -}; - -DomainAliasPopupView.prototype.onShow = function() -{ - this.clearForm(); -}; - -DomainAliasPopupView.prototype.onShowWithDelay = function() -{ - if ('' === this.name() && !Globals.bMobile) - { - this.name.focused(true); - } -}; - -DomainAliasPopupView.prototype.clearForm = function() -{ - this.saving(false); - this.savingError(''); - - this.name(''); - this.name.focused(false); - - this.alias(''); -}; - module.exports = DomainAliasPopupView; diff --git a/dev/View/Popup/Filter.js b/dev/View/Popup/Filter.js index 6ce4ac8fb..bf0558f98 100644 --- a/dev/View/Popup/Filter.js +++ b/dev/View/Popup/Filter.js @@ -1,202 +1,194 @@ -var - _ = require('_'), - ko = require('ko'), +import _ from '_'; +import ko from 'ko'; - Enums = require('Common/Enums'), - Globals = require('Common/Globals'), - Utils = require('Common/Utils'), - Translator = require('Common/Translator'), +import {FiltersAction, FilterConditionField, FilterConditionType} from 'Common/Enums'; +import {bMobileDevice} from 'Common/Globals'; +import {defautOptionsAfterRender, createCommand, delegateRun} from 'Common/Utils'; +import {i18n, initOnStartOrLangChange} from 'Common/Translator'; - FilterStore = require('Stores/User/Filter'), - FolderStore = require('Stores/User/Folder'), +import FilterStore from 'Stores/User/Filter'; +import FolderStore from 'Stores/User/Folder'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function FilterPopupView() +@view({ + name: 'View/Popup/Filter', + type: ViewType.Popup, + templateID: 'PopupsFilter' +}) +class FilterPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsFilter'); + constructor() { + super(); - this.isNew = ko.observable(true); + this.isNew = ko.observable(true); - this.modules = FilterStore.modules; + this.modules = FilterStore.modules; - this.fTrueCallback = null; - this.filter = ko.observable(null); + this.fTrueCallback = null; + this.filter = ko.observable(null); - this.allowMarkAsRead = ko.observable(false); + this.allowMarkAsRead = ko.observable(false); - this.defautOptionsAfterRender = Utils.defautOptionsAfterRender; - this.folderSelectList = FolderStore.folderMenuForFilters; - this.selectedFolderValue = ko.observable(''); + this.defautOptionsAfterRender = defautOptionsAfterRender; + this.folderSelectList = FolderStore.folderMenuForFilters; + this.selectedFolderValue = ko.observable(''); - this.selectedFolderValue.subscribe(function() { - if (this.filter()) + this.selectedFolderValue.subscribe(() => { + if (this.filter()) + { + this.filter().actionValue.error(false); + } + }); + + this.saveFilter = createCommand(() => { + + if (this.filter()) + { + if (FiltersAction.MoveTo === this.filter().actionType()) + { + this.filter().actionValue(this.selectedFolderValue()); + } + + if (!this.filter().verify()) + { + return false; + } + + if (this.fTrueCallback) + { + this.fTrueCallback(this.filter()); + } + + if (this.modalVisibility()) + { + delegateRun(this, 'closeCommand'); + } + } + + return true; + }); + + this.actionTypeOptions = ko.observableArray([]); + this.fieldOptions = ko.observableArray([]); + this.typeOptions = ko.observableArray([]); + this.typeOptionsSize = ko.observableArray([]); + + initOnStartOrLangChange(_.bind(this.populateOptions, this)); + + this.modules.subscribe(this.populateOptions, this); + } + + populateOptions() { + this.actionTypeOptions([]); + + // this.actionTypeOptions.push({'id': FiltersAction.None, + // 'name': i18n('POPUPS_FILTER/SELECT_ACTION_NONE')}); + + const modules = this.modules(); + if (modules) { - this.filter().actionValue.error(false); - } - }, this); - - this.saveFilter = Utils.createCommand(this, function() { - - if (this.filter()) - { - if (Enums.FiltersAction.MoveTo === this.filter().actionType()) + if (modules.markasread) { - this.filter().actionValue(this.selectedFolderValue()); + this.allowMarkAsRead(true); } - if (!this.filter().verify()) + if (modules.moveto) { - return false; + this.actionTypeOptions.push({'id': FiltersAction.MoveTo, + 'name': i18n('POPUPS_FILTER/SELECT_ACTION_MOVE_TO')}); } - if (this.fTrueCallback) + if (modules.redirect) { - this.fTrueCallback(this.filter()); + this.actionTypeOptions.push({'id': FiltersAction.Forward, + 'name': i18n('POPUPS_FILTER/SELECT_ACTION_FORWARD_TO')}); } - if (this.modalVisibility()) + if (modules.reject) { - Utils.delegateRun(this, 'closeCommand'); + this.actionTypeOptions.push({'id': FiltersAction.Reject, + 'name': i18n('POPUPS_FILTER/SELECT_ACTION_REJECT')}); + } + + if (modules.vacation) + { + this.actionTypeOptions.push({'id': FiltersAction.Vacation, + 'name': i18n('POPUPS_FILTER/SELECT_ACTION_VACATION_MESSAGE')}); + } } - return true; - }); + this.actionTypeOptions.push({'id': FiltersAction.Discard, + 'name': i18n('POPUPS_FILTER/SELECT_ACTION_DISCARD')}); - this.actionTypeOptions = ko.observableArray([]); - this.fieldOptions = ko.observableArray([]); - this.typeOptions = ko.observableArray([]); - this.typeOptionsSize = ko.observableArray([]); + this.fieldOptions([ + {'id': FilterConditionField.From, 'name': i18n('POPUPS_FILTER/SELECT_FIELD_FROM')}, + {'id': FilterConditionField.Recipient, 'name': i18n('POPUPS_FILTER/SELECT_FIELD_RECIPIENTS')}, + {'id': FilterConditionField.Subject, 'name': i18n('POPUPS_FILTER/SELECT_FIELD_SUBJECT')}, + {'id': FilterConditionField.Size, 'name': i18n('POPUPS_FILTER/SELECT_FIELD_SIZE')}, + {'id': FilterConditionField.Header, 'name': i18n('POPUPS_FILTER/SELECT_FIELD_HEADER')} + ]); - Translator.initOnStartOrLangChange(_.bind(this.populateOptions, this)); + this.typeOptions([ + {'id': FilterConditionType.Contains, 'name': i18n('POPUPS_FILTER/SELECT_TYPE_CONTAINS')}, + {'id': FilterConditionType.NotContains, 'name': i18n('POPUPS_FILTER/SELECT_TYPE_NOT_CONTAINS')}, + {'id': FilterConditionType.EqualTo, 'name': i18n('POPUPS_FILTER/SELECT_TYPE_EQUAL_TO')}, + {'id': FilterConditionType.NotEqualTo, 'name': i18n('POPUPS_FILTER/SELECT_TYPE_NOT_EQUAL_TO')} + ]); - this.modules.subscribe(this.populateOptions, this); + if (modules && modules.regex) + { + this.typeOptions.push({'id': FilterConditionType.Regex, 'name': 'Regex'}); + } - kn.constructorEnd(this); + this.typeOptionsSize([ + {'id': FilterConditionType.Over, 'name': i18n('POPUPS_FILTER/SELECT_TYPE_OVER')}, + {'id': FilterConditionType.Under, 'name': i18n('POPUPS_FILTER/SELECT_TYPE_UNDER')} + ]); + } + + removeCondition(oConditionToDelete) { + if (this.filter()) + { + this.filter().removeCondition(oConditionToDelete); + } + } + + clearPopup() { + this.isNew(true); + + this.fTrueCallback = null; + this.filter(null); + } + + onShow(oFilter, fTrueCallback, bEdit) { + this.clearPopup(); + + this.fTrueCallback = fTrueCallback; + this.filter(oFilter); + + if (oFilter) + { + this.selectedFolderValue(oFilter.actionValue()); + } + + this.isNew(!bEdit); + + if (!bEdit && oFilter) + { + oFilter.name.focused(true); + } + } + + onShowWithDelay() { + if (this.isNew() && this.filter() && !bMobileDevice) + { + this.filter().name.focused(true); + } + } } -kn.extendAsViewModel(['View/Popup/Filter', 'PopupsFilterViewModel'], FilterPopupView); -_.extend(FilterPopupView.prototype, AbstractView.prototype); - -FilterPopupView.prototype.populateOptions = function() -{ - this.actionTypeOptions([]); - -// this.actionTypeOptions.push({'id': Enums.FiltersAction.None, -// 'name': Translator.i18n('POPUPS_FILTER/SELECT_ACTION_NONE')}); - - var oModules = this.modules(); - if (oModules) - { - if (oModules.markasread) - { - this.allowMarkAsRead(true); - } - - if (oModules.moveto) - { - this.actionTypeOptions.push({'id': Enums.FiltersAction.MoveTo, - 'name': Translator.i18n('POPUPS_FILTER/SELECT_ACTION_MOVE_TO')}); - } - - if (oModules.redirect) - { - this.actionTypeOptions.push({'id': Enums.FiltersAction.Forward, - 'name': Translator.i18n('POPUPS_FILTER/SELECT_ACTION_FORWARD_TO')}); - } - - if (oModules.reject) - { - this.actionTypeOptions.push({'id': Enums.FiltersAction.Reject, - 'name': Translator.i18n('POPUPS_FILTER/SELECT_ACTION_REJECT')}); - } - - if (oModules.vacation) - { - this.actionTypeOptions.push({'id': Enums.FiltersAction.Vacation, - 'name': Translator.i18n('POPUPS_FILTER/SELECT_ACTION_VACATION_MESSAGE')}); - - } - } - - this.actionTypeOptions.push({'id': Enums.FiltersAction.Discard, - 'name': Translator.i18n('POPUPS_FILTER/SELECT_ACTION_DISCARD')}); - - this.fieldOptions([ - {'id': Enums.FilterConditionField.From, 'name': Translator.i18n('POPUPS_FILTER/SELECT_FIELD_FROM')}, - {'id': Enums.FilterConditionField.Recipient, 'name': Translator.i18n('POPUPS_FILTER/SELECT_FIELD_RECIPIENTS')}, - {'id': Enums.FilterConditionField.Subject, 'name': Translator.i18n('POPUPS_FILTER/SELECT_FIELD_SUBJECT')}, - {'id': Enums.FilterConditionField.Size, 'name': Translator.i18n('POPUPS_FILTER/SELECT_FIELD_SIZE')}, - {'id': Enums.FilterConditionField.Header, 'name': Translator.i18n('POPUPS_FILTER/SELECT_FIELD_HEADER')} - ]); - - this.typeOptions([ - {'id': Enums.FilterConditionType.Contains, 'name': Translator.i18n('POPUPS_FILTER/SELECT_TYPE_CONTAINS')}, - {'id': Enums.FilterConditionType.NotContains, 'name': Translator.i18n('POPUPS_FILTER/SELECT_TYPE_NOT_CONTAINS')}, - {'id': Enums.FilterConditionType.EqualTo, 'name': Translator.i18n('POPUPS_FILTER/SELECT_TYPE_EQUAL_TO')}, - {'id': Enums.FilterConditionType.NotEqualTo, 'name': Translator.i18n('POPUPS_FILTER/SELECT_TYPE_NOT_EQUAL_TO')} - ]); - - if (oModules && oModules.regex) - { - this.typeOptions.push({'id': Enums.FilterConditionType.Regex, 'name': 'Regex'}); - } - - this.typeOptionsSize([ - {'id': Enums.FilterConditionType.Over, 'name': Translator.i18n('POPUPS_FILTER/SELECT_TYPE_OVER')}, - {'id': Enums.FilterConditionType.Under, 'name': Translator.i18n('POPUPS_FILTER/SELECT_TYPE_UNDER')} - ]); -}; - -FilterPopupView.prototype.removeCondition = function(oConditionToDelete) -{ - if (this.filter()) - { - this.filter().removeCondition(oConditionToDelete); - } -}; - -FilterPopupView.prototype.clearPopup = function() -{ - this.isNew(true); - - this.fTrueCallback = null; - this.filter(null); -}; - -FilterPopupView.prototype.onShow = function(oFilter, fTrueCallback, bEdit) -{ - this.clearPopup(); - - this.fTrueCallback = fTrueCallback; - this.filter(oFilter); - - if (oFilter) - { - this.selectedFolderValue(oFilter.actionValue()); - } - - this.isNew(!bEdit); - - if (!bEdit && oFilter) - { - oFilter.name.focused(true); - } -}; - -FilterPopupView.prototype.onShowWithDelay = function() -{ - if (this.isNew() && this.filter() && !Globals.bMobile) - { - this.filter().name.focused(true); - } -}; - module.exports = FilterPopupView; diff --git a/dev/View/Popup/FolderClear.js b/dev/View/Popup/FolderClear.js index 3daeb8336..c0ba3a0ae 100644 --- a/dev/View/Popup/FolderClear.js +++ b/dev/View/Popup/FolderClear.js @@ -1,118 +1,106 @@ -var - _ = require('_'), - ko = require('ko'), +import ko from 'ko'; - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Translator = require('Common/Translator'), +import {StorageResultType, Notification} from 'Common/Enums'; +import {createCommand} from 'Common/Utils'; +import {i18n, getNotification} from 'Common/Translator'; +import {setFolderHash} from 'Common/Cache'; - Cache = require('Common/Cache'), +import MessageStore from 'Stores/User/Message'; - MessageStore = require('Stores/User/Message'), +import Remote from 'Remote/User/Ajax'; - Remote = require('Remote/User/Ajax'), +import {getApp} from 'Helper/Apps/User'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function FolderClearPopupView() +@view({ + name: 'View/Popup/FolderClear', + type: ViewType.Popup, + templateID: 'PopupsFolderClear' +}) +class FolderClearPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsFolderClear'); + constructor() { + super(); - this.selectedFolder = ko.observable(null); - this.clearingProcess = ko.observable(false); - this.clearingError = ko.observable(''); + 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 Translator.i18n('POPUPS_CLEAR_FOLDER/DANGER_DESC_HTML_1', { - 'FOLDER': this.folderNameForClear() + this.folderFullNameForClear = ko.computed(() => { + const folder = this.selectedFolder(); + return folder ? folder.printableFullName() : ''; }); - }, this); - this.clearCommand = Utils.createCommand(this, function() { + this.folderNameForClear = ko.computed(() => { + const folder = this.selectedFolder(); + return folder ? folder.localName() : ''; + }); - var - self = this, - oFolderToClear = this.selectedFolder(); + this.dangerDescHtml = ko.computed( + () => i18n('POPUPS_CLEAR_FOLDER/DANGER_DESC_HTML_1', {'FOLDER': this.folderNameForClear()}) + ); - if (oFolderToClear) - { - MessageStore.message(null); - MessageStore.messageList([]); + this.clearCommand = createCommand(() => { - this.clearingProcess(true); + const folderToClear = this.selectedFolder(); + if (folderToClear) + { + MessageStore.message(null); + MessageStore.messageList([]); - oFolderToClear.messageCountAll(0); - oFolderToClear.messageCountUnread(0); + this.clearingProcess(true); - Cache.setFolderHash(oFolderToClear.fullNameRaw, ''); + folderToClear.messageCountAll(0); + folderToClear.messageCountUnread(0); - Remote.folderClear(function(sResult, oData) { + setFolderHash(folderToClear.fullNameRaw, ''); - self.clearingProcess(false); - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - require('App/User').default.reloadMessageList(true); - self.cancelCommand(); - } - else - { - if (oData && oData.ErrorCode) + Remote.folderClear((result, data) => { + + this.clearingProcess(false); + if (StorageResultType.Success === result && data && data.Result) { - self.clearingError(Translator.getNotification(oData.ErrorCode)); + getApp().reloadMessageList(true); + this.cancelCommand(); } else { - self.clearingError(Translator.getNotification(Enums.Notification.MailServerError)); + if (data && data.ErrorCode) + { + this.clearingError(getNotification(data.ErrorCode)); + } + else + { + this.clearingError(getNotification(Notification.MailServerError)); + } } - } - }, oFolderToClear.fullNameRaw); + }, folderToClear.fullNameRaw); + } + + }, () => { + const + folder = this.selectedFolder(), + isClearing = this.clearingProcess(); + + return !isClearing && null !== folder; + }); + } + + clearPopup() { + this.clearingProcess(false); + this.selectedFolder(null); + } + + onShow(folder) { + this.clearPopup(); + if (folder) + { + this.selectedFolder(folder); } - - }, function() { - - var - oFolder = this.selectedFolder(), - bIsClearing = this.clearingProcess(); - - return !bIsClearing && null !== oFolder; - - }); - - kn.constructorEnd(this); + } } -kn.extendAsViewModel(['View/Popup/FolderClear', 'PopupsFolderClearViewModel'], FolderClearPopupView); -_.extend(FolderClearPopupView.prototype, AbstractView.prototype); - -FolderClearPopupView.prototype.clearPopup = function() -{ - this.clearingProcess(false); - this.selectedFolder(null); -}; - -FolderClearPopupView.prototype.onShow = function(oFolder) -{ - this.clearPopup(); - if (oFolder) - { - this.selectedFolder(oFolder); - } -}; - module.exports = FolderClearPopupView; diff --git a/dev/View/Popup/FolderCreate.js b/dev/View/Popup/FolderCreate.js index f10f1e40f..3e28a823f 100644 --- a/dev/View/Popup/FolderCreate.js +++ b/dev/View/Popup/FolderCreate.js @@ -1,111 +1,95 @@ -var - _ = require('_'), - ko = require('ko'), +import ko from 'ko'; - Enums = require('Common/Enums'), - Consts = require('Common/Consts'), - Globals = require('Common/Globals'), - Utils = require('Common/Utils'), +import {Notification} from 'Common/Enums'; +import {UNUSED_OPTION_VALUE} from 'Common/Consts'; +import {bMobileDevice} from 'Common/Globals'; +import {trim, createCommand, defautOptionsAfterRender, folderListOptionsBuilder} from 'Common/Utils'; - FolderStore = require('Stores/User/Folder'), +import FolderStore from 'Stores/User/Folder'; - Promises = require('Promises/User/Ajax'), +import Promises from 'Promises/User/Ajax'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {getApp} from 'Helper/Apps/User'; -/** - * @constructor - * @extends AbstractView - */ -function FolderCreateView() +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; + +@view({ + name: 'View/Popup/FolderCreate', + type: ViewType.Popup, + templateID: 'PopupsFolderCreate' +}) +class FolderCreateView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsFolderCreate'); + constructor() { + super(); - this.folderName = ko.observable(''); - this.folderName.focused = ko.observable(false); + this.folderName = ko.observable(''); + this.folderName.focused = ko.observable(false); - this.selectedParentValue = ko.observable(Consts.UNUSED_OPTION_VALUE); + this.selectedParentValue = ko.observable(UNUSED_OPTION_VALUE); - this.parentFolderSelectList = ko.computed(function() { + this.parentFolderSelectList = ko.computed(() => { - var - aTop = [], - fDisableCallback = null, - fVisibleCallback = null, - aList = FolderStore.folderList(), - fRenameCallback = function(oItem) { - return oItem ? (oItem.isSystemFolder() ? oItem.name() + ' ' + oItem.manageFolderSystemName() : oItem.name()) : ''; - }; + const + top = [], + list = FolderStore.folderList(), + fRenameCallback = (oItem) => (oItem ? (oItem.isSystemFolder() ? oItem.name() + ' ' + oItem.manageFolderSystemName() : oItem.name()) : ''); - aTop.push(['', '']); + top.push(['', '']); - if ('' !== FolderStore.namespace) - { - fDisableCallback = function(oItem) + let fDisableCallback = null; + if ('' !== FolderStore.namespace) { - return FolderStore.namespace !== oItem.fullNameRaw.substr(0, FolderStore.namespace.length); - }; - } + fDisableCallback = (item) => FolderStore.namespace !== item.fullNameRaw.substr(0, FolderStore.namespace.length); + } - return Utils.folderListOptionsBuilder([], aList, [], aTop, null, fDisableCallback, fVisibleCallback, fRenameCallback); + return folderListOptionsBuilder([], list, [], top, null, fDisableCallback, null, fRenameCallback); - }, this); + }); - // commands - this.createFolder = Utils.createCommand(this, function() { + // commands + this.createFolder = createCommand(() => { - var - sParentFolderName = this.selectedParentValue(); + let parentFolderName = this.selectedParentValue(); + if ('' === parentFolderName && 1 < FolderStore.namespace.length) + { + parentFolderName = FolderStore.namespace.substr(0, FolderStore.namespace.length - 1); + } - if ('' === sParentFolderName && 1 < FolderStore.namespace.length) + getApp().foldersPromisesActionHelper( + Promises.folderCreate(this.folderName(), parentFolderName, FolderStore.foldersCreating), + Notification.CantCreateFolder + ); + + this.cancelCommand(); + + }, () => this.simpleFolderNameValidation(this.folderName())); + + this.defautOptionsAfterRender = defautOptionsAfterRender; + } + + simpleFolderNameValidation(sName) { + return (/^[^\\\/]+$/g).test(trim(sName)); + } + + clearPopup() { + this.folderName(''); + this.selectedParentValue(''); + this.folderName.focused(false); + } + + onShow() { + this.clearPopup(); + } + + onShowWithDelay() { + if (!bMobileDevice) { - sParentFolderName = FolderStore.namespace.substr(0, FolderStore.namespace.length - 1); + this.folderName.focused(true); } - - require('App/User').default.foldersPromisesActionHelper( - Promises.folderCreate(this.folderName(), sParentFolderName, FolderStore.foldersCreating), - Enums.Notification.CantCreateFolder - ); - - this.cancelCommand(); - - }, function() { - return this.simpleFolderNameValidation(this.folderName()); - }); - - this.defautOptionsAfterRender = Utils.defautOptionsAfterRender; - - kn.constructorEnd(this); + } } -kn.extendAsViewModel(['View/Popup/FolderCreate', 'PopupsFolderCreateViewModel'], FolderCreateView); -_.extend(FolderCreateView.prototype, AbstractView.prototype); - -FolderCreateView.prototype.simpleFolderNameValidation = function(sName) -{ - return (/^[^\\\/]+$/g).test(Utils.trim(sName)); -}; - -FolderCreateView.prototype.clearPopup = function() -{ - this.folderName(''); - this.selectedParentValue(''); - this.folderName.focused(false); -}; - -FolderCreateView.prototype.onShow = function() -{ - this.clearPopup(); -}; - -FolderCreateView.prototype.onShowWithDelay = function() -{ - if (!Globals.bMobile) - { - this.folderName.focused(true); - } -}; - module.exports = FolderCreateView; diff --git a/dev/View/Popup/FolderSystem.js b/dev/View/Popup/FolderSystem.js index 231a1921e..28c7eb56e 100644 --- a/dev/View/Popup/FolderSystem.js +++ b/dev/View/Popup/FolderSystem.js @@ -1,126 +1,113 @@ -var - _ = require('_'), - ko = require('ko'), +import _ from '_'; +import ko from 'ko'; - Enums = require('Common/Enums'), - Consts = require('Common/Consts'), - Utils = require('Common/Utils'), - Translator = require('Common/Translator'), +import {SetSystemFoldersNotification, Magics} from 'Common/Enums'; +import {UNUSED_OPTION_VALUE} from 'Common/Consts'; +import {folderListOptionsBuilder, noop, defautOptionsAfterRender} from 'Common/Utils'; +import {initOnStartOrLangChange, i18n} from 'Common/Translator'; - FolderStore = require('Stores/User/Folder'), +import FolderStore from 'Stores/User/Folder'; - Settings = require('Storage/Settings'), - Remote = require('Remote/User/Ajax'), +import * as Settings from 'Storage/Settings'; +import Remote from 'Remote/User/Ajax'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function FolderSystemPopupView() +@view({ + name: 'View/Popup/FolderSystem', + type: ViewType.Popup, + templateID: 'PopupsFolderSystem' +}) +class FolderSystemPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsFolderSystem'); + constructor() { + super(); - Translator.initOnStartOrLangChange(_.bind(function() { - this.sChooseOnText = Translator.i18n('POPUPS_SYSTEM_FOLDERS/SELECT_CHOOSE_ONE'); - this.sUnuseText = Translator.i18n('POPUPS_SYSTEM_FOLDERS/SELECT_UNUSE_NAME'); - }, this)); + this.sChooseOnText = ''; + this.sUnuseText = ''; - this.notification = ko.observable(''); + initOnStartOrLangChange(() => { + this.sChooseOnText = i18n('POPUPS_SYSTEM_FOLDERS/SELECT_CHOOSE_ONE'); + this.sUnuseText = i18n('POPUPS_SYSTEM_FOLDERS/SELECT_UNUSE_NAME'); + }); - this.folderSelectList = ko.computed(function() { - return Utils.folderListOptionsBuilder([], FolderStore.folderList(), FolderStore.folderListSystemNames(), [ - ['', this.sChooseOnText], - [Consts.UNUSED_OPTION_VALUE, this.sUnuseText] - ], null, null, null, null, null, true); - }, this); + this.notification = ko.observable(''); - this.sentFolder = FolderStore.sentFolder; - this.draftFolder = FolderStore.draftFolder; - this.spamFolder = FolderStore.spamFolder; - this.trashFolder = FolderStore.trashFolder; - this.archiveFolder = FolderStore.archiveFolder; + this.folderSelectList = ko.computed( + () => folderListOptionsBuilder([], FolderStore.folderList(), FolderStore.folderListSystemNames(), [ + ['', this.sChooseOnText], [UNUSED_OPTION_VALUE, this.sUnuseText] + ], null, null, null, null, null, true) + ); - var - fSaveSystemFolders = _.debounce(function() { - Settings.settingsSet('SentFolder', FolderStore.sentFolder()); - Settings.settingsSet('DraftFolder', FolderStore.draftFolder()); - Settings.settingsSet('SpamFolder', FolderStore.spamFolder()); - Settings.settingsSet('TrashFolder', FolderStore.trashFolder()); - Settings.settingsSet('ArchiveFolder', FolderStore.archiveFolder()); + this.sentFolder = FolderStore.sentFolder; + this.draftFolder = FolderStore.draftFolder; + this.spamFolder = FolderStore.spamFolder; + this.trashFolder = FolderStore.trashFolder; + this.archiveFolder = FolderStore.archiveFolder; - Remote.saveSystemFolders(Utils.noop, { - 'SentFolder': FolderStore.sentFolder(), - 'DraftFolder': FolderStore.draftFolder(), - 'SpamFolder': FolderStore.spamFolder(), - 'TrashFolder': FolderStore.trashFolder(), - 'ArchiveFolder': FolderStore.archiveFolder(), - 'NullFolder': 'NullFolder' - }); + const + fSetSystemFolders = () => { + Settings.settingsSet('SentFolder', FolderStore.sentFolder()); + Settings.settingsSet('DraftFolder', FolderStore.draftFolder()); + Settings.settingsSet('SpamFolder', FolderStore.spamFolder()); + Settings.settingsSet('TrashFolder', FolderStore.trashFolder()); + Settings.settingsSet('ArchiveFolder', FolderStore.archiveFolder()); + }, + fSaveSystemFolders = _.debounce(() => { + fSetSystemFolders(); + Remote.saveSystemFolders(noop, { + SentFolder: FolderStore.sentFolder(), + DraftFolder: FolderStore.draftFolder(), + SpamFolder: FolderStore.spamFolder(), + TrashFolder: FolderStore.trashFolder(), + ArchiveFolder: FolderStore.archiveFolder(), + NullFolder: 'NullFolder' + }); + }, Magics.Time1s), + fCallback = () => { + fSetSystemFolders(); + fSaveSystemFolders(); + }; - }, Enums.Magics.Time1s); + FolderStore.sentFolder.subscribe(fCallback); + FolderStore.draftFolder.subscribe(fCallback); + FolderStore.spamFolder.subscribe(fCallback); + FolderStore.trashFolder.subscribe(fCallback); + FolderStore.archiveFolder.subscribe(fCallback); - var - fCallback = function() { - Settings.settingsSet('SentFolder', FolderStore.sentFolder()); - Settings.settingsSet('DraftFolder', FolderStore.draftFolder()); - Settings.settingsSet('SpamFolder', FolderStore.spamFolder()); - Settings.settingsSet('TrashFolder', FolderStore.trashFolder()); - Settings.settingsSet('ArchiveFolder', FolderStore.archiveFolder()); - - fSaveSystemFolders(); - }; - - FolderStore.sentFolder.subscribe(fCallback); - FolderStore.draftFolder.subscribe(fCallback); - FolderStore.spamFolder.subscribe(fCallback); - FolderStore.trashFolder.subscribe(fCallback); - FolderStore.archiveFolder.subscribe(fCallback); - - this.defautOptionsAfterRender = Utils.defautOptionsAfterRender; - - kn.constructorEnd(this); -} - -kn.extendAsViewModel(['View/Popup/FolderSystem', 'PopupsFolderSystemViewModel'], FolderSystemPopupView); -_.extend(FolderSystemPopupView.prototype, AbstractView.prototype); - -FolderSystemPopupView.prototype.sChooseOnText = ''; -FolderSystemPopupView.prototype.sUnuseText = ''; - -/** - * @param {number=} iNotificationType = Enums.SetSystemFoldersNotification.None - */ -FolderSystemPopupView.prototype.onShow = function(iNotificationType) -{ - var sNotification = ''; - - iNotificationType = Utils.isUnd(iNotificationType) ? Enums.SetSystemFoldersNotification.None : iNotificationType; - - switch (iNotificationType) - { - case Enums.SetSystemFoldersNotification.Sent: - sNotification = Translator.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_SENT'); - break; - case Enums.SetSystemFoldersNotification.Draft: - sNotification = Translator.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_DRAFTS'); - break; - case Enums.SetSystemFoldersNotification.Spam: - sNotification = Translator.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_SPAM'); - break; - case Enums.SetSystemFoldersNotification.Trash: - sNotification = Translator.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_TRASH'); - break; - case Enums.SetSystemFoldersNotification.Archive: - sNotification = Translator.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_ARCHIVE'); - break; - // no default + this.defautOptionsAfterRender = defautOptionsAfterRender; } - this.notification(sNotification); -}; + /** + * @param {number=} notificationType = SetSystemFoldersNotification.None + */ + onShow(notificationType = SetSystemFoldersNotification.None) { + + let notification = ''; + switch (notificationType) + { + case SetSystemFoldersNotification.Sent: + notification = i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_SENT'); + break; + case SetSystemFoldersNotification.Draft: + notification = i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_DRAFTS'); + break; + case SetSystemFoldersNotification.Spam: + notification = i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_SPAM'); + break; + case SetSystemFoldersNotification.Trash: + notification = i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_TRASH'); + break; + case SetSystemFoldersNotification.Archive: + notification = i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_ARCHIVE'); + break; + // no default + } + + this.notification(notification); + } +} module.exports = FolderSystemPopupView; diff --git a/dev/View/Popup/Identity.js b/dev/View/Popup/Identity.js index 5f1891ea3..d74db0c54 100644 --- a/dev/View/Popup/Identity.js +++ b/dev/View/Popup/Identity.js @@ -1,197 +1,187 @@ -var - _ = require('_'), - ko = require('ko'), +import ko from 'ko'; - Enums = require('Common/Enums'), - Globals = require('Common/Globals'), - Utils = require('Common/Utils'), - Translator = require('Common/Translator'), +import {StorageResultType, Notification} from 'Common/Enums'; +import {bMobileDevice} from 'Common/Globals'; +import {createCommand, trim, fakeMd5} from 'Common/Utils'; +import {getNotification} from 'Common/Translator'; - Remote = require('Remote/User/Ajax'), +import Remote from 'Remote/User/Ajax'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {getApp} from 'Helper/Apps/User'; -/** - * @constructor - * @extends AbstractView - */ -function IdentityPopupView() +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; + +@view({ + name: 'View/Popup/Identity', + type: ViewType.Popup, + templateID: 'PopupsIdentity' +}) +class IdentityPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsIdentity'); + constructor() { + super(); - var self = this; + this.id = ''; + this.edit = ko.observable(false); + this.owner = ko.observable(false); - 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 = 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.signature = ko.observable(''); + this.signatureInsertBefore = ko.observable(false); - this.signature = ko.observable(''); - this.signatureInsertBefore = ko.observable(false); + this.showBcc = ko.observable(false); + this.showReplyTo = ko.observable(false); - this.showBcc = ko.observable(false); - this.showReplyTo = ko.observable(false); + this.submitRequest = ko.observable(false); + this.submitError = ko.observable(''); - this.submitRequest = ko.observable(false); - this.submitError = ko.observable(''); - - this.bcc.subscribe(function(aValue) { - if (false === self.showBcc() && 0 < aValue.length) - { - self.showBcc(true); - } - }, this); - - this.replyTo.subscribe(function(aValue) { - if (false === self.showReplyTo() && 0 < aValue.length) - { - self.showReplyTo(true); - } - }, this); - - this.addOrEditIdentityCommand = Utils.createCommand(this, function() { - - if (this.signature && this.signature.__fetchEditorValue) - { - this.signature.__fetchEditorValue(); - } - - if (!this.email.hasError()) - { - this.email.hasError('' === Utils.trim(this.email())); - } - - if (this.email.hasError()) - { - if (!this.owner()) + this.bcc.subscribe((value) => { + if (false === this.showBcc() && 0 < value.length) { - this.email.focused(true); + this.showBcc(true); + } + }); + + this.replyTo.subscribe((value) => { + if (false === this.showReplyTo() && 0 < value.length) + { + this.showReplyTo(true); + } + }); + + this.addOrEditIdentityCommand = createCommand(() => { + + if (this.signature && this.signature.__fetchEditorValue) + { + this.signature.__fetchEditorValue(); } - return false; - } - - if (this.replyTo.hasError()) - { - this.replyTo.focused(true); - return false; - } - - if (this.bcc.hasError()) - { - this.bcc.focused(true); - return false; - } - - this.submitRequest(true); - - Remote.identityUpdate(_.bind(function(sResult, oData) { - - this.submitRequest(false); - if (Enums.StorageResultType.Success === sResult && oData) + if (!this.email.hasError()) { - if (oData.Result) + this.email.hasError('' === trim(this.email())); + } + + if (this.email.hasError()) + { + if (!this.owner()) { - require('App/User').default.accountsAndIdentities(); - this.cancelCommand(); - } - else if (oData.ErrorCode) - { - this.submitError(Translator.getNotification(oData.ErrorCode)); + this.email.focused(true); } + + return false; } - else + + if (this.replyTo.hasError()) { - this.submitError(Translator.getNotification(Enums.Notification.UnknownError)); + this.replyTo.focused(true); + return false; } - }, this), this.id, this.email(), this.name(), this.replyTo(), this.bcc(), - this.signature(), this.signatureInsertBefore()); + if (this.bcc.hasError()) + { + this.bcc.focused(true); + return false; + } - return true; + this.submitRequest(true); - }, function() { - return !this.submitRequest(); - }); + Remote.identityUpdate((result, data) => { - kn.constructorEnd(this); + this.submitRequest(false); + if (StorageResultType.Success === result && data) + { + if (data.Result) + { + getApp().accountsAndIdentities(); + this.cancelCommand(); + } + else if (data.ErrorCode) + { + this.submitError(getNotification(data.ErrorCode)); + } + } + else + { + this.submitError(getNotification(Notification.UnknownError)); + } + + }, this.id, this.email(), this.name(), this.replyTo(), this.bcc(), this.signature(), this.signatureInsertBefore()); + + return true; + + }, () => !this.submitRequest()); + } + + clearPopup() { + this.id = ''; + this.edit(false); + this.owner(false); + + this.name(''); + this.email(''); + this.replyTo(''); + this.bcc(''); + this.signature(''); + this.signatureInsertBefore(false); + + this.email.hasError(false); + this.replyTo.hasError(false); + this.bcc.hasError(false); + + this.showBcc(false); + this.showReplyTo(false); + + this.submitRequest(false); + this.submitError(''); + } + + /** + * @param {?IdentityModel} oIdentity + */ + onShow(identity) { + + this.clearPopup(); + + if (identity) + { + this.edit(true); + + this.id = identity.id() || ''; + this.name(identity.name()); + this.email(identity.email()); + this.replyTo(identity.replyTo()); + this.bcc(identity.bcc()); + this.signature(identity.signature()); + this.signatureInsertBefore(identity.signatureInsertBefore()); + + this.owner('' === this.id); + } + else + { + this.id = fakeMd5(); + } + } + + onShowWithDelay() { + if (!this.owner() && !bMobileDevice) + { + this.email.focused(true); + } + } + + onHideWithDelay() { + this.clearPopup(); + } } -kn.extendAsViewModel(['View/Popup/Identity', 'PopupsIdentityViewModel'], IdentityPopupView); -_.extend(IdentityPopupView.prototype, AbstractView.prototype); - -IdentityPopupView.prototype.clearPopup = function() -{ - this.id = ''; - this.edit(false); - this.owner(false); - - this.name(''); - this.email(''); - this.replyTo(''); - this.bcc(''); - this.signature(''); - this.signatureInsertBefore(false); - - this.email.hasError(false); - this.replyTo.hasError(false); - this.bcc.hasError(false); - - this.showBcc(false); - this.showReplyTo(false); - - this.submitRequest(false); - this.submitError(''); -}; - -/** - * @param {?IdentityModel} oIdentity - */ -IdentityPopupView.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.signature(oIdentity.signature()); - this.signatureInsertBefore(oIdentity.signatureInsertBefore()); - - this.owner('' === this.id); - } - else - { - this.id = Utils.fakeMd5(); - } -}; - -IdentityPopupView.prototype.onShowWithDelay = function() -{ - if (!this.owner() && !Globals.bMobile) - { - this.email.focused(true); - } -}; - -IdentityPopupView.prototype.onHideWithDelay = function() -{ - this.clearPopup(); -}; - module.exports = IdentityPopupView; diff --git a/dev/View/Popup/KeyboardShortcutsHelp.js b/dev/View/Popup/KeyboardShortcutsHelp.js index d20650f32..b61108907 100644 --- a/dev/View/Popup/KeyboardShortcutsHelp.js +++ b/dev/View/Popup/KeyboardShortcutsHelp.js @@ -1,60 +1,55 @@ -var - _ = require('_'), - key = require('key'), +import _ from '_'; +import key from 'key'; - Enums = require('Common/Enums'), +import {KeyState, Magics} from 'Common/Enums'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function KeyboardShortcutsHelpPopupView() +@view({ + name: 'View/Popup/KeyboardShortcutsHelp', + type: ViewType.Popup, + templateID: 'PopupsKeyboardShortcutsHelp' +}) +class KeyboardShortcutsHelpPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsKeyboardShortcutsHelp'); + constructor() { + super(); + this.sDefaultKeyScope = KeyState.PopupKeyboardShortcutsHelp; + } - this.sDefaultKeyScope = Enums.KeyState.PopupKeyboardShortcutsHelp; + onBuild(dom) { + key('tab, shift+tab, left, right', KeyState.PopupKeyboardShortcutsHelp, _.throttle((event, handler) => { - kn.constructorEnd(this); + if (event && handler) + { + const + $tabs = dom.find('.nav.nav-tabs > li'), + isNext = handler && ('tab' === handler.shortcut || 'right' === handler.shortcut); + + let index = $tabs.index($tabs.filter('.active')); + if (!isNext && 0 < index) + { + index -= 1; + } + else if (isNext && index < $tabs.length - 1) + { + index += 1; + } + else + { + index = isNext ? 0 : $tabs.length - 1; + } + + $tabs.eq(index).find('a[data-toggle="tab"]').tab('show'); + return false; + } + + return true; + + }, Magics.Time100ms)); + } } -kn.extendAsViewModel(['View/Popup/KeyboardShortcutsHelp', 'PopupsKeyboardShortcutsHelpViewModel'], KeyboardShortcutsHelpPopupView); -_.extend(KeyboardShortcutsHelpPopupView.prototype, AbstractView.prototype); - -KeyboardShortcutsHelpPopupView.prototype.onBuild = function(oDom) -{ - key('tab, shift+tab, left, right', Enums.KeyState.PopupKeyboardShortcutsHelp, _.throttle(function(event, handler) { - - if (event && handler) - { - var - $tabs = oDom.find('.nav.nav-tabs > li'), - isNext = handler && ('tab' === handler.shortcut || 'right' === handler.shortcut), - index = $tabs.index($tabs.filter('.active')); - - if (!isNext && 0 < index) - { - index -= 1; - } - else if (isNext && index < $tabs.length - 1) - { - index += 1; - } - else - { - index = isNext ? 0 : $tabs.length - 1; - } - - $tabs.eq(index).find('a[data-toggle="tab"]').tab('show'); - return false; - } - - return true; - - }, Enums.Magics.Time100ms)); -}; - module.exports = KeyboardShortcutsHelpPopupView; diff --git a/dev/View/Popup/Languages.js b/dev/View/Popup/Languages.js index 05e979d14..88e2e7181 100644 --- a/dev/View/Popup/Languages.js +++ b/dev/View/Popup/Languages.js @@ -1,88 +1,76 @@ -var - _ = require('_'), - ko = require('ko'), +import _ from '_'; +import ko from 'ko'; - Utils = require('Common/Utils'), +import {convertLangName} from 'Common/Utils'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function LanguagesPopupView() +@view({ + name: 'View/Popup/Languages', + type: ViewType.Popup, + templateID: 'PopupsLanguages' +}) +class LanguagesPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsLanguages'); + constructor() { + super(); - var self = this; + this.fLang = null; + this.userLanguage = ko.observable(''); - this.fLang = null; - this.userLanguage = ko.observable(''); + this.langs = ko.observableArray([]); - this.langs = ko.observableArray([]); - - this.languages = ko.computed(function() { - var sUserLanguage = self.userLanguage(); - return _.map(self.langs(), function(sLanguage) { - return { - 'key': sLanguage, - 'user': sLanguage === sUserLanguage, - 'selected': ko.observable(false), - 'fullName': Utils.convertLangName(sLanguage) - }; + this.languages = ko.computed(() => { + const userLanguage = this.userLanguage(); + return _.map(this.langs(), (language) => ({ + key: language, + user: language === userLanguage, + selected: ko.observable(false), + fullName: convertLangName(language) + })); }); - }); - this.langs.subscribe(function() { - this.setLanguageSelection(); - }, this); - - kn.constructorEnd(this); -} - -kn.extendAsViewModel(['View/Popup/Languages', 'PopupsLanguagesViewModel'], LanguagesPopupView); -_.extend(LanguagesPopupView.prototype, AbstractView.prototype); - -LanguagesPopupView.prototype.languageTooltipName = function(sLanguage) -{ - var sResult = Utils.convertLangName(sLanguage, true); - return Utils.convertLangName(sLanguage, false) === sResult ? '' : sResult; -}; - -LanguagesPopupView.prototype.setLanguageSelection = function() -{ - var currentLang = this.fLang ? ko.unwrap(this.fLang) : ''; - _.each(this.languages(), function(item) { - item.selected(item.key === currentLang); - }); -}; - -LanguagesPopupView.prototype.onBeforeShow = function() -{ - this.fLang = null; - this.userLanguage(''); - - this.langs([]); -}; - -LanguagesPopupView.prototype.onShow = function(fLanguage, aLangs, sUserLanguage) -{ - this.fLang = fLanguage; - this.userLanguage(sUserLanguage || ''); - - this.langs(aLangs); -}; - -LanguagesPopupView.prototype.changeLanguage = function(sLang) -{ - if (this.fLang) - { - this.fLang(sLang); + this.langs.subscribe(() => { + this.setLanguageSelection(); + }); } - this.cancelCommand(); -}; + languageTooltipName(language) { + const result = convertLangName(language, true); + return convertLangName(language, false) === result ? '' : result; + } + + setLanguageSelection() { + const currentLang = this.fLang ? ko.unwrap(this.fLang) : ''; + _.each(this.languages(), (item) => { + item.selected(item.key === currentLang); + }); + } + + onBeforeShow() { + this.fLang = null; + this.userLanguage(''); + + this.langs([]); + } + + onShow(fLanguage, langs, userLanguage) { + this.fLang = fLanguage; + this.userLanguage(userLanguage || ''); + + this.langs(langs); + } + + changeLanguage(lang) { + if (this.fLang) + { + this.fLang(lang); + } + + this.cancelCommand(); + } +} module.exports = LanguagesPopupView; diff --git a/dev/View/Popup/MessageOpenPgp.js b/dev/View/Popup/MessageOpenPgp.js index 36c984068..e6592460a 100644 --- a/dev/View/Popup/MessageOpenPgp.js +++ b/dev/View/Popup/MessageOpenPgp.js @@ -1,175 +1,165 @@ -var - _ = require('_'), - ko = require('ko'), - key = require('key'), - $ = require('$'), +import _ from '_'; +import ko from 'ko'; +import key from 'key'; +import $ from '$'; - Utils = require('Common/Utils'), - Enums = require('Common/Enums'), +import {createCommand, pString, log} from 'Common/Utils'; +import {KeyState, Magics} from 'Common/Enums'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function MessageOpenPgpPopupView() +@view({ + name: 'View/Popup/MessageOpenPgp', + type: ViewType.Popup, + templateID: 'PopupsMessageOpenPgp' +}) +class MessageOpenPgpPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsMessageOpenPgp'); + constructor() { + super(); - this.notification = ko.observable(''); + this.notification = ko.observable(''); - this.selectedKey = ko.observable(null); - this.privateKeys = ko.observableArray([]); + this.selectedKey = ko.observable(null); + this.privateKeys = ko.observableArray([]); - this.password = ko.observable(''); - this.password.focus = ko.observable(false); - this.buttonFocus = ko.observable(false); + this.password = ko.observable(''); + this.password.focus = ko.observable(false); + this.buttonFocus = ko.observable(false); - this.resultCallback = null; + this.resultCallback = null; - this.submitRequest = ko.observable(false); + this.submitRequest = ko.observable(false); - // commands - this.doCommand = Utils.createCommand(this, function() { + // commands + this.doCommand = createCommand(() => { - this.submitRequest(true); + this.submitRequest(true); - _.delay(_.bind(function() { + _.delay(() => { - var oPrivateKey = null; + let privateKey = null; - try - { - if (this.resultCallback && this.selectedKey()) + try { - var oPrivateKeys = this.selectedKey().getNativeKeys(); - oPrivateKey = oPrivateKeys && oPrivateKeys[0] ? oPrivateKeys[0] : null; - - if (oPrivateKey) + if (this.resultCallback && this.selectedKey()) { - try + const privateKeys = this.selectedKey().getNativeKeys(); + privateKey = privateKeys && privateKeys[0] ? privateKeys[0] : null; + + if (privateKey) { - if (!oPrivateKey.decrypt(Utils.pString(this.password()))) + try { - Utils.log('Error: Private key cannot be decrypted'); - oPrivateKey = null; + if (!privateKey.decrypt(pString(this.password()))) + { + log('Error: Private key cannot be decrypted'); + privateKey = null; + } + } + catch (e) + { + log(e); + privateKey = null; } } - catch (e) + else { - Utils.log(e); - oPrivateKey = null; + log('Error: Private key cannot be found'); } } - else - { - Utils.log('Error: Private key cannot be found'); - } } - } - catch (e) + catch (e) + { + log(e); + privateKey = null; + } + + this.submitRequest(false); + + this.cancelCommand(); + this.resultCallback(privateKey); + + }, Magics.Time100ms); + + }, () => !this.submitRequest()); + + this.sDefaultKeyScope = KeyState.PopupMessageOpenPGP; + } + + clearPopup() { + this.notification(''); + + this.password(''); + this.password.focus(false); + this.buttonFocus(false); + + this.selectedKey(false); + this.submitRequest(false); + + this.resultCallback = null; + this.privateKeys([]); + } + + onBuild(oDom) { + key('tab,shift+tab', KeyState.PopupMessageOpenPGP, () => { + + switch (true) { - Utils.log(e); - oPrivateKey = null; + case this.password.focus(): + this.buttonFocus(true); + break; + case this.buttonFocus(): + this.password.focus(true); + break; + // no default } - this.submitRequest(false); + return false; - this.cancelCommand(); - this.resultCallback(oPrivateKey); + }); - }, this), Enums.Magics.Time100ms); + const self = this; - }, function() { - return !this.submitRequest(); - }); + oDom + .on('click', '.key-list__item', function() { // eslint-disable-line prefer-arrow-callback - this.sDefaultKeyScope = Enums.KeyState.PopupMessageOpenPGP; + oDom.find('.key-list__item .key-list__item__radio') + .addClass('icon-radio-unchecked') + .removeClass('icon-radio-checked'); - kn.constructorEnd(this); + $(this).find('.key-list__item__radio') // eslint-disable-line no-invalid-this + .removeClass('icon-radio-unchecked') + .addClass('icon-radio-checked'); + + self.selectedKey(ko.dataFor(this)); // eslint-disable-line no-invalid-this + + self.password.focus(true); + }); + } + + onHideWithDelay() { + this.clearPopup(); + } + + onShowWithDelay() { + this.password.focus(true); + // this.buttonFocus(true); + } + + onShow(fCallback, privateKeys) { + this.clearPopup(); + + this.resultCallback = fCallback; + this.privateKeys(privateKeys); + + if (this.viewModelDom) + { + this.viewModelDom.find('.key-list__item').first().click(); + } + } } -kn.extendAsViewModel(['View/Popup/MessageOpenPgp'], MessageOpenPgpPopupView); -_.extend(MessageOpenPgpPopupView.prototype, AbstractView.prototype); - -MessageOpenPgpPopupView.prototype.clearPopup = function() -{ - this.notification(''); - - this.password(''); - this.password.focus(false); - this.buttonFocus(false); - - this.selectedKey(false); - this.submitRequest(false); - - this.resultCallback = null; - this.privateKeys([]); -}; - -MessageOpenPgpPopupView.prototype.onBuild = function(oDom) -{ - key('tab,shift+tab', Enums.KeyState.PopupMessageOpenPGP, _.bind(function() { - - switch (true) - { - case this.password.focus(): - this.buttonFocus(true); - break; - case this.buttonFocus(): - this.password.focus(true); - break; - // no default - } - - return false; - - }, this)); - - var self = this; - - oDom - .on('click', '.key-list__item', function() { - - oDom.find('.key-list__item .key-list__item__radio') - .addClass('icon-radio-unchecked') - .removeClass('icon-radio-checked'); - - $(this).find('.key-list__item__radio') - .removeClass('icon-radio-unchecked') - .addClass('icon-radio-checked'); - - self.selectedKey(ko.dataFor(this)); - - self.password.focus(true); - }); -}; - -MessageOpenPgpPopupView.prototype.onHideWithDelay = function() -{ - this.clearPopup(); -}; - -MessageOpenPgpPopupView.prototype.onShowWithDelay = function() -{ - this.password.focus(true); -// this.buttonFocus(true); -}; - -MessageOpenPgpPopupView.prototype.onShow = function(fCallback, aPrivateKeys) -{ - this.clearPopup(); - - this.resultCallback = fCallback; - this.privateKeys(aPrivateKeys); - - if (this.viewModelDom) - { - this.viewModelDom.find('.key-list__item').first().click(); - } -}; - module.exports = MessageOpenPgpPopupView; diff --git a/dev/View/Popup/NewOpenPgpKey.js b/dev/View/Popup/NewOpenPgpKey.js index 24c5b340a..9c6cc974b 100644 --- a/dev/View/Popup/NewOpenPgpKey.js +++ b/dev/View/Popup/NewOpenPgpKey.js @@ -1,135 +1,129 @@ -var - _ = require('_'), - ko = require('ko'), +import _ from '_'; +import ko from 'ko'; - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), +import {Magics} from 'Common/Enums'; +import {trim, log, createCommand, delegateRun, pInt} from 'Common/Utils'; - PgpStore = require('Stores/User/Pgp'), +import PgpStore from 'Stores/User/Pgp'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {getApp} from 'Helper/Apps/User'; -/** - * @constructor - * @extends AbstractView - */ -function NewOpenPgpKeyPopupView() +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; + +@view({ + name: 'View/Popup/NewOpenPgpKey', + type: ViewType.Popup, + templateID: 'PopupsNewOpenPgpKey' +}) +class NewOpenPgpKeyPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsNewOpenPgpKey'); + constructor() { + super(); - this.email = ko.observable(''); - this.email.focus = ko.observable(''); - this.email.error = ko.observable(false); + 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(Enums.Magics.BitLength2048); + this.name = ko.observable(''); + this.password = ko.observable(''); + this.keyBitLength = ko.observable(Magics.BitLength2048); - this.submitRequest = ko.observable(false); - this.submitError = ko.observable(''); + this.submitRequest = ko.observable(false); + this.submitError = ko.observable(''); - this.email.subscribe(function() { - this.email.error(false); - }, this); + this.email.subscribe(() => { + this.email.error(false); + }); - this.generateOpenPgpKeyCommand = Utils.createCommand(this, function() { + this.generateOpenPgpKeyCommand = createCommand(() => { - var - self = this, - oUserId = {}, - oOpenpgpKeyring = PgpStore.openpgpKeyring; + const + userId = {}, + openpgpKeyring = PgpStore.openpgpKeyring; - this.email.error('' === Utils.trim(this.email())); - if (!oOpenpgpKeyring || this.email.error()) - { - return false; - } - - oUserId.email = this.email(); - if ('' !== this.name()) - { - oUserId.name = this.name(); - } - - this.submitRequest(true); - this.submitError(''); - - _.delay(function() { - - try { - - PgpStore.openpgp.generateKey({ - userIds: [oUserId], - numBits: Utils.pInt(self.keyBitLength()), - passphrase: Utils.trim(self.password()) - }).then(function(mKeyPair) { - - self.submitRequest(false); - - if (mKeyPair && mKeyPair.privateKeyArmored) - { - oOpenpgpKeyring.privateKeys.importKey(mKeyPair.privateKeyArmored); - oOpenpgpKeyring.publicKeys.importKey(mKeyPair.publicKeyArmored); - - oOpenpgpKeyring.store(); - - require('App/User').default.reloadOpenPgpKeys(); - Utils.delegateRun(self, 'cancelCommand'); - } - - }).then(null, function(e) { - self.submitRequest(false); - self.showError(e); - }); - } - catch (e) + this.email.error('' === trim(this.email())); + if (!openpgpKeyring || this.email.error()) { - self.submitRequest(false); - self.showError(e); + return false; } - }, Enums.Magics.Time100ms); + userId.email = this.email(); + if ('' !== this.name()) + { + userId.name = this.name(); + } - return true; - }); + this.submitRequest(true); + this.submitError(''); - kn.constructorEnd(this); + _.delay(() => { + + try { + + PgpStore.openpgp.generateKey({ + userIds: [userId], + numBits: pInt(this.keyBitLength()), + passphrase: trim(this.password()) + }).then((keyPair) => { + + this.submitRequest(false); + + if (keyPair && keyPair.privateKeyArmored) + { + openpgpKeyring.privateKeys.importKey(keyPair.privateKeyArmored); + openpgpKeyring.publicKeys.importKey(keyPair.publicKeyArmored); + + openpgpKeyring.store(); + + getApp().reloadOpenPgpKeys(); + delegateRun(this, 'cancelCommand'); + } + + }).catch((e) => { + this.submitRequest(false); + this.showError(e); + }); + } + catch (e) + { + this.submitRequest(false); + this.showError(e); + } + + }, Magics.Time100ms); + + return true; + }); + } + + showError(e) { + log(e); + if (e && e.message) + { + this.submitError(e.message); + } + } + + clearPopup() { + this.name(''); + this.password(''); + + this.email(''); + this.email.error(false); + this.keyBitLength(Magics.BitLength2048); + + this.submitError(''); + } + + onShow() { + this.clearPopup(); + } + + onShowWithDelay() { + this.email.focus(true); + } } -kn.extendAsViewModel(['View/Popup/NewOpenPgpKey', 'PopupsNewOpenPgpKeyViewModel'], NewOpenPgpKeyPopupView); -_.extend(NewOpenPgpKeyPopupView.prototype, AbstractView.prototype); - -NewOpenPgpKeyPopupView.prototype.showError = function(e) -{ - Utils.log(e); - if (e && e.message) - { - this.submitError(e.message); - } -}; - -NewOpenPgpKeyPopupView.prototype.clearPopup = function() -{ - this.name(''); - this.password(''); - - this.email(''); - this.email.error(false); - this.keyBitLength(Enums.Magics.BitLength2048); - - this.submitError(''); -}; - -NewOpenPgpKeyPopupView.prototype.onShow = function() -{ - this.clearPopup(); -}; - -NewOpenPgpKeyPopupView.prototype.onShowWithDelay = function() -{ - this.email.focus(true); -}; - module.exports = NewOpenPgpKeyPopupView; diff --git a/dev/View/Popup/Plugin.js b/dev/View/Popup/Plugin.js index 8764c7dc3..8afab1c44 100644 --- a/dev/View/Popup/Plugin.js +++ b/dev/View/Popup/Plugin.js @@ -1,168 +1,141 @@ -var - _ = require('_'), - ko = require('ko'), - key = require('key'), +import _ from '_'; +import ko from 'ko'; +import key from 'key'; - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Translator = require('Common/Translator'), +import {KeyState, Magics, StorageResultType, Notification} from 'Common/Enums'; +import {createCommand, isNonEmptyArray, delegateRun} from 'Common/Utils'; +import {getNotification, i18n} from 'Common/Translator'; - Remote = require('Remote/Admin/Ajax'), +import Remote from 'Remote/Admin/Ajax'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType, isPopupVisible, showScreenPopup} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function PluginPopupView() +@view({ + name: 'View/Popup/Plugin', + type: ViewType.Popup, + templateID: 'PopupsPlugin' +}) +class PluginPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsPlugin'); + constructor() { + super(); - var self = this; + this.onPluginSettingsUpdateResponse = _.bind(this.onPluginSettingsUpdateResponse, this); - this.onPluginSettingsUpdateResponse = _.bind(this.onPluginSettingsUpdateResponse, this); + this.saveError = ko.observable(''); - this.saveError = ko.observable(''); + this.name = ko.observable(''); + this.readme = ko.observable(''); - this.name = ko.observable(''); - this.readme = ko.observable(''); + this.configures = ko.observableArray([]); - this.configures = ko.observableArray([]); + this.hasReadme = ko.computed(() => '' !== this.readme()); + this.hasConfiguration = ko.computed(() => 0 < this.configures().length); - this.hasReadme = ko.computed(function() { - return '' !== this.readme(); - }, this); + this.readmePopoverConf = { + 'placement': 'right', + 'trigger': 'hover', + 'title': i18n('POPUPS_PLUGIN/TOOLTIP_ABOUT_TITLE'), + 'container': 'body', + 'html': true, + 'content': () => `
${this.readme()}
` + }; - this.hasConfiguration = ko.computed(function() { - return 0 < this.configures().length; - }, this); + this.saveCommand = createCommand(() => { - this.readmePopoverConf = { - 'placement': 'right', - 'trigger': 'hover', -// 'trigger': 'click', - 'title': Translator.i18n('POPUPS_PLUGIN/TOOLTIP_ABOUT_TITLE'), - 'container': 'body', - 'html': true, - 'content': function() { - return '
' + self.readme() + '
'; -// .replace(/[\r]/g, '').replace(/[\n]/g, '
').replace(/[\t]/g, '   '); - } - }; + const list = {}; + list.Name = this.name(); - this.saveCommand = Utils.createCommand(this, function() { + _.each(this.configures(), (oItem) => { + let value = oItem.value(); + if (false === value || true === value) + { + value = value ? '1' : '0'; + } + list['_' + oItem.Name] = value; + }); - var list = {}; + this.saveError(''); + Remote.pluginSettingsUpdate(this.onPluginSettingsUpdateResponse, list); - list.Name = this.name(); + }, this.hasConfiguration); - _.each(this.configures(), function(oItem) { - var value = oItem.value(); + this.bDisabeCloseOnEsc = true; + this.sDefaultKeyScope = KeyState.All; - if (false === value || true === value) - { - value = value ? '1' : '0'; - } - - list['_' + oItem.Name] = value; - }, this); - - this.saveError(''); - Remote.pluginSettingsUpdate(this.onPluginSettingsUpdateResponse, list); - - }, this.hasConfiguration); - - this.bDisabeCloseOnEsc = true; - this.sDefaultKeyScope = Enums.KeyState.All; - - this.tryToClosePopup = _.debounce(_.bind(this.tryToClosePopup, this), Enums.Magics.Time200ms); - - kn.constructorEnd(this); -} - -kn.extendAsViewModel(['View/Popup/Plugin', 'PopupsPluginViewModel'], PluginPopupView); -_.extend(PluginPopupView.prototype, AbstractView.prototype); - -PluginPopupView.prototype.onPluginSettingsUpdateResponse = function(sResult, oData) -{ - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - this.cancelCommand(); + this.tryToClosePopup = _.debounce(_.bind(this.tryToClosePopup, this), Magics.Time200ms); } - else - { - this.saveError(''); - if (oData && oData.ErrorCode) + + onPluginSettingsUpdateResponse(result, data) { + if (StorageResultType.Success === result && data && data.Result) { - this.saveError(Translator.getNotification(oData.ErrorCode)); + this.cancelCommand(); } else { - this.saveError(Translator.getNotification(Enums.Notification.CantSavePluginSettings)); - } - } -}; - -PluginPopupView.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]), - 'placeholder': ko.observable(aItem[6]), - 'Name': aItem[1], - 'Type': aItem[2], - 'Label': aItem[3], - 'Default': aItem[4], - 'Desc': aItem[5] - }; - })); - } - } -}; - -PluginPopupView.prototype.tryToClosePopup = function() -{ - var - self = this, - PopupsAskViewModel = require('View/Popup/Ask'); - - if (!kn.isPopupVisible(PopupsAskViewModel)) - { - kn.showScreenPopup(PopupsAskViewModel, [Translator.i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'), function() { - if (self.modalVisibility()) + this.saveError(''); + if (data && data.ErrorCode) { - Utils.delegateRun(self, 'cancelCommand'); + this.saveError(getNotification(data.ErrorCode)); + } + else + { + this.saveError(getNotification(Notification.CantSavePluginSettings)); } - }]); - } -}; - -PluginPopupView.prototype.onBuild = function() -{ - key('esc', Enums.KeyState.All, _.bind(function() { - if (this.modalVisibility()) - { - this.tryToClosePopup(); } + } - return false; - }, this)); -}; + onShow(oPlugin) { + this.name(); + this.readme(); + this.configures([]); + + if (oPlugin) + { + this.name(oPlugin.Name); + this.readme(oPlugin.Readme); + + const config = oPlugin.Config; + if (isNonEmptyArray(config)) + { + this.configures(_.map(config, (item) => ({ + 'value': ko.observable(item[0]), + 'placeholder': ko.observable(item[6]), + 'Name': item[1], + 'Type': item[2], + 'Label': item[3], + 'Default': item[4], + 'Desc': item[5] + }))); + } + } + } + + tryToClosePopup() { + const PopupsAskViewModel = require('View/Popup/Ask'); + if (!isPopupVisible(PopupsAskViewModel)) + { + showScreenPopup(PopupsAskViewModel, [i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'), () => { + if (this.modalVisibility()) + { + delegateRun(this, 'cancelCommand'); + } + }]); + } + } + + onBuild() { + key('esc', KeyState.All, () => { + if (this.modalVisibility()) + { + this.tryToClosePopup(); + } + + return false; + }); + } +} module.exports = PluginPopupView; diff --git a/dev/View/Popup/Template.js b/dev/View/Popup/Template.js index b16e8b66b..8b28e1954 100644 --- a/dev/View/Popup/Template.js +++ b/dev/View/Popup/Template.js @@ -1,199 +1,186 @@ -var - _ = require('_'), - ko = require('ko'), +import ko from 'ko'; - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Translator = require('Common/Translator'), - HtmlEditor = require('Common/HtmlEditor').default, +import {StorageResultType, Notification} from 'Common/Enums'; +import {trim, isNormal, createCommand} from 'Common/Utils'; +import {getNotification} from 'Common/Translator'; +import {HtmlEditor} from 'Common/HtmlEditor'; - Remote = require('Remote/User/Ajax'), +import Remote from 'Remote/User/Ajax'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {getApp} from 'Helper/Apps/User'; -/** - * @constructor - * @extends AbstractView - */ -function TemplatePopupView() +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; + +@view({ + name: 'View/Popup/Template', + type: ViewType.Popup, + templateID: 'PopupsTemplate' +}) +class TemplatePopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsTemplate'); + constructor() { + super(); - this.editor = null; - this.signatureDom = ko.observable(null); + this.editor = null; + this.signatureDom = ko.observable(null); - this.id = ko.observable(''); + this.id = ko.observable(''); - this.name = ko.observable(''); - this.name.error = ko.observable(false); - this.name.focus = ko.observable(false); + this.name = ko.observable(''); + this.name.error = ko.observable(false); + this.name.focus = ko.observable(false); - this.body = ko.observable(''); - this.body.loading = ko.observable(false); - this.body.error = ko.observable(false); + this.body = ko.observable(''); + this.body.loading = ko.observable(false); + this.body.error = ko.observable(false); - this.name.subscribe(function() { - this.name.error(false); - }, this); - - this.body.subscribe(function() { - this.body.error(false); - }, this); - - this.submitRequest = ko.observable(false); - this.submitError = ko.observable(''); - - this.addTemplateCommand = Utils.createCommand(this, function() { - - this.populateBodyFromEditor(); - - this.name.error('' === Utils.trim(this.name())); - this.body.error('' === Utils.trim(this.body()) || - ':HTML:' === Utils.trim(this.body())); - - if (this.name.error() || this.body.error()) - { - return false; - } - - this.submitRequest(true); - - Remote.templateSetup(_.bind(function(sResult, oData) { - - this.submitRequest(false); - if (Enums.StorageResultType.Success === sResult && oData) - { - if (oData.Result) - { - require('App/User').default.templates(); - this.cancelCommand(); - } - else if (oData.ErrorCode) - { - this.submitError(Translator.getNotification(oData.ErrorCode)); - } - } - else - { - this.submitError(Translator.getNotification(Enums.Notification.UnknownError)); - } - - }, this), this.id(), this.name(), this.body()); - - return true; - - }, function() { - return !this.submitRequest(); - }); - - kn.constructorEnd(this); -} - -kn.extendAsViewModel(['View/Popup/Template'], TemplatePopupView); -_.extend(TemplatePopupView.prototype, AbstractView.prototype); - -TemplatePopupView.prototype.clearPopup = function() -{ - this.id(''); - - this.name(''); - this.name.error(false); - - this.body(''); - this.body.loading(false); - this.body.error(false); - - this.submitRequest(false); - this.submitError(''); - - if (this.editor) - { - this.editor.setPlain('', false); - } -}; - -TemplatePopupView.prototype.populateBodyFromEditor = function() -{ - if (this.editor) - { - this.body(this.editor.getDataWithHtmlMark()); - } -}; - -TemplatePopupView.prototype.editorSetBody = function(sBody) -{ - var self = this; - - if (!this.editor && this.signatureDom()) - { - this.editor = new HtmlEditor(self.signatureDom(), function() { - self.populateBodyFromEditor(); - }, function() { - self.editor.setHtmlOrPlain(sBody); + this.name.subscribe(() => { + this.name.error(false); }); - } - else - { - this.editor.setHtmlOrPlain(sBody); - } -}; -TemplatePopupView.prototype.onShow = function(oTemplate) -{ - var self = this; + this.body.subscribe(() => { + this.body.error(false); + }); - this.clearPopup(); + this.submitRequest = ko.observable(false); + this.submitError = ko.observable(''); - if (oTemplate && oTemplate.id) - { - this.id(oTemplate.id); - this.name(oTemplate.name); - this.body(oTemplate.body); + this.addTemplateCommand = createCommand(() => { - if (oTemplate.populated) - { - self.editorSetBody(this.body()); - } - else - { - this.body.loading(true); - self.body.error(false); + this.populateBodyFromEditor(); - Remote.templateGetById(function(sResult, oData) { + this.name.error('' === trim(this.name())); + this.body.error('' === trim(this.body()) || ':HTML:' === trim(this.body())); - self.body.loading(false); + if (this.name.error() || this.body.error()) + { + return false; + } - if (Enums.StorageResultType.Success === sResult && oData && oData.Result && - 'Object/Template' === oData.Result['@Object'] && Utils.isNormal(oData.Result.Body)) + this.submitRequest(true); + + Remote.templateSetup((result, data) => { + + this.submitRequest(false); + if (StorageResultType.Success === result && data) { - oTemplate.body = oData.Result.Body; - oTemplate.populated = true; - - self.body(oTemplate.body); - self.body.error(false); + if (data.Result) + { + getApp().templates(); + this.cancelCommand(); + } + else if (data.ErrorCode) + { + this.submitError(getNotification(data.ErrorCode)); + } } else { - self.body(''); - self.body.error(true); + this.submitError(getNotification(Notification.UnknownError)); } - self.editorSetBody(self.body()); + }, this.id(), this.name(), this.body()); - }, this.id()); + return true; + + }, () => !this.submitRequest()); + } + + clearPopup() { + this.id(''); + + this.name(''); + this.name.error(false); + + this.body(''); + this.body.loading(false); + this.body.error(false); + + this.submitRequest(false); + this.submitError(''); + + if (this.editor) + { + this.editor.setPlain('', false); } } - else - { - self.editorSetBody(''); - } -}; -TemplatePopupView.prototype.onShowWithDelay = function() -{ - this.name.focus(true); -}; + populateBodyFromEditor() { + if (this.editor) + { + this.body(this.editor.getDataWithHtmlMark()); + } + } + + editorSetBody(sBody) { + if (!this.editor && this.signatureDom()) + { + this.editor = new HtmlEditor(this.signatureDom(), () => { + this.populateBodyFromEditor(); + }, () => { + this.editor.setHtmlOrPlain(sBody); + }); + } + else + { + this.editor.setHtmlOrPlain(sBody); + } + } + + onShow(template) { + + this.clearPopup(); + + if (template && template.id) + { + this.id(template.id); + this.name(template.name); + this.body(template.body); + + if (template.populated) + { + this.editorSetBody(this.body()); + } + else + { + this.body.loading(true); + this.body.error(false); + + Remote.templateGetById((result, data) => { + + this.body.loading(false); + + if (StorageResultType.Success === result && data && data.Result && + 'Object/Template' === data.Result['@Object'] && isNormal(data.Result.Body)) + { + template.body = data.Result.Body; + template.populated = true; + + this.body(template.body); + this.body.error(false); + } + else + { + this.body(''); + this.body.error(true); + } + + this.editorSetBody(this.body()); + + }, this.id()); + } + } + else + { + this.editorSetBody(''); + } + } + + onShowWithDelay() { + this.name.focus(true); + } +} module.exports = TemplatePopupView; diff --git a/dev/View/Popup/TwoFactorConfiguration.js b/dev/View/Popup/TwoFactorConfiguration.js index 033de90ed..49209dca0 100644 --- a/dev/View/Popup/TwoFactorConfiguration.js +++ b/dev/View/Popup/TwoFactorConfiguration.js @@ -1,240 +1,217 @@ -var - window = require('window'), - _ = require('_'), - ko = require('ko'), - qr = require('qr'), +import window from 'window'; +import _ from '_'; +import ko from 'ko'; +import qr from 'qr'; - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Translator = require('Common/Translator'), +import {Capa, StorageResultType} from 'Common/Enums'; +import {pString} from 'Common/Utils'; +import {i18n, trigger as translatorTrigger} from 'Common/Translator'; - Settings = require('Storage/Settings'), +import * as Settings from 'Storage/Settings'; - Remote = require('Remote/User/Ajax'), +import Remote from 'Remote/User/Ajax'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {getApp} from 'Helper/Apps/User'; -/** - * @constructor - * @extends AbstractView - */ -function TwoFactorConfigurationPopupView() +import {view, ViewType, showScreenPopup} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; + +@view({ + name: 'View/Popup/TwoFactorConfiguration', + type: ViewType.Popup, + templateID: 'PopupsTwoFactorConfiguration' +}) +class TwoFactorConfigurationPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsTwoFactorConfiguration'); + constructor() { + super(); - this.lock = ko.observable(false); + this.lock = ko.observable(false); - this.capaTwoFactor = Settings.capa(Enums.Capa.TwoFactor); + this.capaTwoFactor = Settings.capa(Capa.TwoFactor); - this.processing = ko.observable(false); - this.clearing = ko.observable(false); - this.secreting = ko.observable(false); + this.processing = ko.observable(false); + this.clearing = ko.observable(false); + this.secreting = ko.observable(false); - this.viewUser = ko.observable(''); - this.twoFactorStatus = ko.observable(false); + this.viewUser = ko.observable(''); + this.twoFactorStatus = ko.observable(false); - this.twoFactorTested = ko.observable(false); + this.twoFactorTested = ko.observable(false); - this.viewSecret = ko.observable(''); - this.viewBackupCodes = ko.observable(''); - this.viewUrlTitle = ko.observable(''); - this.viewUrl = ko.observable(''); + this.viewSecret = ko.observable(''); + this.viewBackupCodes = ko.observable(''); + this.viewUrlTitle = ko.observable(''); + this.viewUrl = ko.observable(''); - this.viewEnable_ = ko.observable(false); + this.viewEnable_ = ko.observable(false); - this.viewEnable = ko.computed({ - 'owner': this, - 'read': this.viewEnable_, - 'write': function(bValue) { - - var self = this; - - bValue = !!bValue; - - if (bValue && this.twoFactorTested()) - { - this.viewEnable_(bValue); - - Remote.enableTwoFactor(function(sResult, oData) { - if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) - { - self.viewEnable_(false); - } - - }, true); - } - else - { - if (!bValue) + this.viewEnable = ko.computed({ + read: this.viewEnable_, + write: (value) => { + value = !!value; + if (value && this.twoFactorTested()) { - this.viewEnable_(bValue); + this.viewEnable_(value); + Remote.enableTwoFactor((result, data) => { + if (StorageResultType.Success !== result || !data || !data.Result) + { + this.viewEnable_(false); + } + }, true); } - - Remote.enableTwoFactor(function(sResult, oData) { - if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) + else + { + if (!value) { - self.viewEnable_(false); + this.viewEnable_(value); } - }, false); + Remote.enableTwoFactor((result, data) => { + if (StorageResultType.Success !== result || !data || !data.Result) + { + this.viewEnable_(false); + } + }, false); + } } - } - }); + }); - this.viewTwoFactorEnableTooltip = ko.computed(function() { - Translator.trigger(); - return this.twoFactorTested() || this.viewEnable_() ? '' : - Translator.i18n('POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_TEST_BEFORE_DESC'); - }, this); + this.viewTwoFactorEnableTooltip = ko.computed(() => { + translatorTrigger(); + return this.twoFactorTested() || this.viewEnable_() ? '' : + i18n('POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_TEST_BEFORE_DESC'); + }); - this.viewTwoFactorStatus = ko.computed(function() { - Translator.trigger(); - return Translator.i18n(this.twoFactorStatus() ? - 'POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_CONFIGURED_DESC' : - 'POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC' - ); - }, this); + this.viewTwoFactorStatus = ko.computed(() => { + translatorTrigger(); + return i18n(this.twoFactorStatus() ? + 'POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_CONFIGURED_DESC' : + 'POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC' + ); + }); - this.twoFactorAllowedEnable = ko.computed(function() { - return this.viewEnable() || this.twoFactorTested(); - }, this); + this.twoFactorAllowedEnable = ko.computed(() => this.viewEnable() || this.twoFactorTested()); - this.onResult = _.bind(this.onResult, this); - this.onShowSecretResult = _.bind(this.onShowSecretResult, this); - - kn.constructorEnd(this); -} - -kn.extendAsViewModel(['View/Popup/TwoFactorConfiguration', 'TwoFactorConfigurationPopupView'], TwoFactorConfigurationPopupView); -_.extend(TwoFactorConfigurationPopupView.prototype, AbstractView.prototype); - -TwoFactorConfigurationPopupView.prototype.showSecret = function() -{ - this.secreting(true); - Remote.showTwoFactorSecret(this.onShowSecretResult); -}; - -TwoFactorConfigurationPopupView.prototype.hideSecret = function() -{ - this.viewSecret(''); - this.viewBackupCodes(''); - this.viewUrlTitle(''); - this.viewUrl(''); -}; - -TwoFactorConfigurationPopupView.prototype.createTwoFactor = function() -{ - this.processing(true); - Remote.createTwoFactor(this.onResult); -}; - -TwoFactorConfigurationPopupView.prototype.logout = function() -{ - require('App/User').default.logout(); -}; - -TwoFactorConfigurationPopupView.prototype.testTwoFactor = function() -{ - require('Knoin/Knoin').showScreenPopup(require('View/Popup/TwoFactorTest'), [this.twoFactorTested]); -}; - -TwoFactorConfigurationPopupView.prototype.clearTwoFactor = function() -{ - this.viewSecret(''); - this.viewBackupCodes(''); - this.viewUrlTitle(''); - this.viewUrl(''); - - this.twoFactorTested(false); - - this.clearing(true); - Remote.clearTwoFactor(this.onResult); -}; - -TwoFactorConfigurationPopupView.prototype.onShow = function(bLock) -{ - this.lock(!!bLock); - - this.viewSecret(''); - this.viewBackupCodes(''); - this.viewUrlTitle(''); - this.viewUrl(''); -}; - -TwoFactorConfigurationPopupView.prototype.onHide = function() -{ - if (this.lock()) - { - window.location.reload(); + this.onResult = _.bind(this.onResult, this); + this.onShowSecretResult = _.bind(this.onShowSecretResult, this); } -}; -TwoFactorConfigurationPopupView.prototype.getQr = function() -{ - return 'otpauth://totp/' + window.encodeURIComponent(this.viewUser()) + - '?secret=' + window.encodeURIComponent(this.viewSecret()) + - '&issuer=' + window.encodeURIComponent(''); -}; - -TwoFactorConfigurationPopupView.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.twoFactorTested(!!oData.Result.Tested); - - this.viewSecret(Utils.pString(oData.Result.Secret)); - this.viewBackupCodes(Utils.pString(oData.Result.BackupCodes).replace(/[\s]+/g, ' ')); - - this.viewUrlTitle(Utils.pString(oData.Result.UrlTitle)); - this.viewUrl(qr.toDataURL({level: 'M', size: 8, value: this.getQr()})); + showSecret() { + this.secreting(true); + Remote.showTwoFactorSecret(this.onShowSecretResult); } - else - { - this.viewUser(''); - this.viewEnable_(false); - this.twoFactorStatus(false); + + hideSecret() { + this.viewSecret(''); + this.viewBackupCodes(''); + this.viewUrlTitle(''); + this.viewUrl(''); + } + + createTwoFactor() { + this.processing(true); + Remote.createTwoFactor(this.onResult); + } + + logout() { + getApp().logout(); + } + + testTwoFactor() { + showScreenPopup(require('View/Popup/TwoFactorTest'), [this.twoFactorTested]); + } + + clearTwoFactor() { + this.viewSecret(''); + this.viewBackupCodes(''); + this.viewUrlTitle(''); + this.viewUrl(''); + this.twoFactorTested(false); + this.clearing(true); + Remote.clearTwoFactor(this.onResult); + } + + onShow(bLock) { + this.lock(!!bLock); + this.viewSecret(''); this.viewBackupCodes(''); this.viewUrlTitle(''); this.viewUrl(''); } -}; -TwoFactorConfigurationPopupView.prototype.onShowSecretResult = function(sResult, oData) -{ - this.secreting(false); + onHide() { + if (this.lock()) + { + window.location.reload(); + } + } - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - this.viewSecret(Utils.pString(oData.Result.Secret)); - this.viewUrlTitle(Utils.pString(oData.Result.UrlTitle)); - this.viewUrl(qr.toDataURL({level: 'M', size: 6, value: this.getQr()})); + getQr() { + return 'otpauth://totp/' + window.encodeURIComponent(this.viewUser()) + + '?secret=' + window.encodeURIComponent(this.viewSecret()) + + '&issuer=' + window.encodeURIComponent(''); } - else - { - this.viewSecret(''); - this.viewUrlTitle(''); - this.viewUrl(''); - } -}; -TwoFactorConfigurationPopupView.prototype.onBuild = function() -{ - if (this.capaTwoFactor) - { - this.processing(true); - Remote.getTwoFactor(this.onResult); + onResult(sResult, oData) { + this.processing(false); + this.clearing(false); + + if (StorageResultType.Success === sResult && oData && oData.Result) + { + this.viewUser(pString(oData.Result.User)); + this.viewEnable_(!!oData.Result.Enable); + this.twoFactorStatus(!!oData.Result.IsSet); + this.twoFactorTested(!!oData.Result.Tested); + + this.viewSecret(pString(oData.Result.Secret)); + this.viewBackupCodes(pString(oData.Result.BackupCodes).replace(/[\s]+/g, ' ')); + + this.viewUrlTitle(pString(oData.Result.UrlTitle)); + this.viewUrl(qr.toDataURL({level: 'M', size: 8, value: this.getQr()})); + } + else + { + this.viewUser(''); + this.viewEnable_(false); + this.twoFactorStatus(false); + this.twoFactorTested(false); + + this.viewSecret(''); + this.viewBackupCodes(''); + this.viewUrlTitle(''); + this.viewUrl(''); + } } -}; + + onShowSecretResult(result, data) { + this.secreting(false); + + if (StorageResultType.Success === result && data && data.Result) + { + this.viewSecret(pString(data.Result.Secret)); + this.viewUrlTitle(pString(data.Result.UrlTitle)); + this.viewUrl(qr.toDataURL({level: 'M', size: 6, value: this.getQr()})); + } + else + { + this.viewSecret(''); + this.viewUrlTitle(''); + this.viewUrl(''); + } + } + + onBuild() { + if (this.capaTwoFactor) + { + this.processing(true); + Remote.getTwoFactor(this.onResult); + } + } +} module.exports = TwoFactorConfigurationPopupView; diff --git a/dev/View/Popup/TwoFactorTest.js b/dev/View/Popup/TwoFactorTest.js index 00f3aa33b..8eb0a6149 100644 --- a/dev/View/Popup/TwoFactorTest.js +++ b/dev/View/Popup/TwoFactorTest.js @@ -1,84 +1,73 @@ -var - _ = require('_'), - ko = require('ko'), +import ko from 'ko'; - Enums = require('Common/Enums'), - Globals = require('Common/Globals'), - Utils = require('Common/Utils'), +import {StorageResultType} from 'Common/Enums'; +import {bMobileDevice} from 'Common/Globals'; +import {createCommand} from 'Common/Utils'; - Remote = require('Remote/User/Ajax'), +import Remote from 'Remote/User/Ajax'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function TwoFactorTestPopupView() +@view({ + name: 'View/Popup/TwoFactorTest', + type: ViewType.Popup, + templateID: 'PopupsTwoFactorTest' +}) +class TwoFactorTestPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsTwoFactorTest'); + constructor() { + super(); - var self = this; + this.code = ko.observable(''); + this.code.focused = ko.observable(false); + this.code.status = ko.observable(null); - this.code = ko.observable(''); - this.code.focused = ko.observable(false); - this.code.status = ko.observable(null); + this.koTestedTrigger = null; - this.koTestedTrigger = null; + this.testing = ko.observable(false); - this.testing = ko.observable(false); + // commands + this.testCode = createCommand(() => { - // commands - this.testCode = Utils.createCommand(this, function() { + this.testing(true); + Remote.testTwoFactor((result, data) => { - this.testing(true); - Remote.testTwoFactor(function(sResult, oData) { + this.testing(false); + this.code.status(StorageResultType.Success === result && data && !!data.Result); - self.testing(false); - self.code.status(Enums.StorageResultType.Success === sResult && oData && !!oData.Result); + if (this.koTestedTrigger && this.code.status()) + { + this.koTestedTrigger(true); + } - if (self.koTestedTrigger && self.code.status()) - { - self.koTestedTrigger(true); - } + }, this.code()); - }, this.code()); + }, () => '' !== this.code() && !this.testing()); + } - }, function() { - return '' !== this.code() && !this.testing(); - }); + clearPopup() { + this.code(''); + this.code.focused(false); + this.code.status(null); + this.testing(false); - kn.constructorEnd(this); + this.koTestedTrigger = null; + } + + onShow(koTestedTrigger) { + this.clearPopup(); + + this.koTestedTrigger = koTestedTrigger; + } + + onShowWithDelay() { + if (!bMobileDevice) + { + this.code.focused(true); + } + } } -kn.extendAsViewModel(['View/Popup/TwoFactorTest', 'PopupsTwoFactorTestViewModel'], TwoFactorTestPopupView); -_.extend(TwoFactorTestPopupView.prototype, AbstractView.prototype); - -TwoFactorTestPopupView.prototype.clearPopup = function() -{ - this.code(''); - this.code.focused(false); - this.code.status(null); - this.testing(false); - - this.koTestedTrigger = null; -}; - -TwoFactorTestPopupView.prototype.onShow = function(koTestedTrigger) -{ - this.clearPopup(); - - this.koTestedTrigger = koTestedTrigger; -}; - -TwoFactorTestPopupView.prototype.onShowWithDelay = function() -{ - if (!Globals.bMobile) - { - this.code.focused(true); - } -}; - module.exports = TwoFactorTestPopupView; diff --git a/dev/View/Popup/ViewOpenPgpKey.js b/dev/View/Popup/ViewOpenPgpKey.js index 01b8b2fff..b7d4e1256 100644 --- a/dev/View/Popup/ViewOpenPgpKey.js +++ b/dev/View/Popup/ViewOpenPgpKey.js @@ -1,64 +1,56 @@ -var - _ = require('_'), - ko = require('ko'), - key = require('key'), +import ko from 'ko'; +import key from 'key'; - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), +import {KeyState} from 'Common/Enums'; +import {selectElement} from 'Common/Utils'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function ViewOpenPgpKeyPopupView() +@view({ + name: 'View/Popup/ViewOpenPgpKey', + type: ViewType.Popup, + templateID: 'PopupsTwoFactorTest' +}) +class ViewOpenPgpKeyPopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsViewOpenPgpKey'); + constructor() { + super(); - this.key = ko.observable(''); - this.keyDom = ko.observable(null); + this.key = ko.observable(''); + this.keyDom = ko.observable(null); - this.sDefaultKeyScope = Enums.KeyState.PopupViewOpenPGP; + this.sDefaultKeyScope = KeyState.PopupViewOpenPGP; + } - kn.constructorEnd(this); + clearPopup() { + this.key(''); + } + + selectKey() { + const el = this.keyDom(); + if (el) + { + selectElement(el); + } + } + + onShow(oOpenPgpKey) { + this.clearPopup(); + + if (oOpenPgpKey) + { + this.key(oOpenPgpKey.armor); + } + } + + onBuild() { + key('ctrl+a, command+a', KeyState.PopupViewOpenPGP, () => { + this.selectKey(); + return false; + }); + } } -kn.extendAsViewModel(['View/Popup/ViewOpenPgpKey', 'PopupsViewOpenPgpKeyViewModel'], ViewOpenPgpKeyPopupView); -_.extend(ViewOpenPgpKeyPopupView.prototype, AbstractView.prototype); - -ViewOpenPgpKeyPopupView.prototype.clearPopup = function() -{ - this.key(''); -}; - -ViewOpenPgpKeyPopupView.prototype.selectKey = function() -{ - var oEl = this.keyDom(); - if (oEl) - { - Utils.selectElement(oEl); - } -}; - -ViewOpenPgpKeyPopupView.prototype.onShow = function(oOpenPgpKey) -{ - this.clearPopup(); - - if (oOpenPgpKey) - { - this.key(oOpenPgpKey.armor); - } -}; - -ViewOpenPgpKeyPopupView.prototype.onBuild = function() -{ - key('ctrl+a, command+a', Enums.KeyState.PopupViewOpenPGP, _.bind(function() { - this.selectKey(); - return false; - }, this)); -}; - module.exports = ViewOpenPgpKeyPopupView; diff --git a/dev/View/Popup/WelcomePage.js b/dev/View/Popup/WelcomePage.js index 41dd91ca5..8c27dc902 100644 --- a/dev/View/Popup/WelcomePage.js +++ b/dev/View/Popup/WelcomePage.js @@ -1,56 +1,48 @@ -var - _ = require('_'), - ko = require('ko'), +import ko from 'ko'; - Promises = require('Promises/User/Ajax'), +import Promises from 'Promises/User/Ajax'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function WelcomePagePopupView() +@view({ + name: 'View/Popup/WelcomePage', + type: ViewType.Popup, + templateID: 'PopupsWelcomePage' +}) +class WelcomePagePopupView extends AbstractViewNext { - AbstractView.call(this, 'Popups', 'PopupsWelcomePage'); + constructor() { + super(); - this.welcomePageURL = ko.observable(''); + this.welcomePageURL = ko.observable(''); - this.closeFocused = ko.observable(false); + this.closeFocused = ko.observable(false); + } - kn.constructorEnd(this); + clearPopup() { + this.welcomePageURL(''); + this.closeFocused(false); + } + + /** + * @param {string} sUrl + * @returns {void} + */ + onShow(sUrl) { + this.clearPopup(); + + this.welcomePageURL(sUrl); + } + + onShowWithDelay() { + this.closeFocused(true); + } + + onHide() { + Promises.welcomeClose(); + } } -kn.extendAsViewModel(['View/Popup/WelcomePage', 'WelcomePagePopupViewModel'], WelcomePagePopupView); -_.extend(WelcomePagePopupView.prototype, AbstractView.prototype); - -WelcomePagePopupView.prototype.clearPopup = function() -{ - this.welcomePageURL(''); - this.closeFocused(false); -}; - -/** - * @param {string} sUrl - * @returns {void} - */ -WelcomePagePopupView.prototype.onShow = function(sUrl) -{ - this.clearPopup(); - - this.welcomePageURL(sUrl); -}; - -WelcomePagePopupView.prototype.onShowWithDelay = function() -{ - this.closeFocused(true); -}; - -WelcomePagePopupView.prototype.onHide = function() -{ - Promises.welcomeClose(); -}; - module.exports = WelcomePagePopupView; diff --git a/dev/View/User/About.js b/dev/View/User/About.js index e59cc54fc..ab72c03bb 100644 --- a/dev/View/User/About.js +++ b/dev/View/User/About.js @@ -1,27 +1,23 @@ -var - _ = require('_'), - ko = require('ko'), +import ko from 'ko'; - Settings = require('Storage/Settings'), +import * as Settings from 'Storage/Settings'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function AboutUserView() +@view({ + name: 'View/User/About', + type: ViewType.Center, + templateID: 'About' +}) +class AboutUserView extends AbstractViewNext { - AbstractView.call(this, 'Center', 'About'); + constructor() { + super(); - this.version = ko.observable(Settings.appSettingsGet('version')); - - kn.constructorEnd(this); + this.version = ko.observable(Settings.appSettingsGet('version')); + } } -kn.extendAsViewModel(['View/User/About', 'View/App/About', 'AboutViewModel'], AboutUserView); -_.extend(AboutUserView.prototype, AbstractView.prototype); - -module.exports = AboutUserView; +export {AboutUserView, AboutUserView as default}; diff --git a/dev/View/User/AbstractSystemDropDown.js b/dev/View/User/AbstractSystemDropDown.js index f23e56776..77072e25e 100644 --- a/dev/View/User/AbstractSystemDropDown.js +++ b/dev/View/User/AbstractSystemDropDown.js @@ -1,138 +1,121 @@ -var - _ = require('_'), - ko = require('ko'), - key = require('key'), +import _ from '_'; +import ko from 'ko'; +import key from 'key'; - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Links = require('Common/Links'), - Events = require('Common/Events'), +import AppStore from 'Stores/User/App'; +import AccountStore from 'Stores/User/Account'; +import MessageStore from 'Stores/User/Message'; - AppStore = require('Stores/User/App'), - AccountStore = require('Stores/User/Account'), - MessageStore = require('Stores/User/Message'), +import {Capa, Magics, KeyState} from 'Common/Enums'; +import {trim, isUnd} from 'Common/Utils'; +import {settings} from 'Common/Links'; - Settings = require('Storage/Settings'), +import * as Events from 'Common/Events'; +import * as Settings from 'Storage/Settings'; - AbstractView = require('Knoin/AbstractView'); +import {getApp} from 'Helper/Apps/User'; -/** - * @constructor - * @extends AbstractView - */ -function AbstractSystemDropDownUserView() +import {view, ViewType, showScreenPopup, setHash} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; + +@view({ + type: ViewType.Right, + templateID: 'SystemDropDown' +}) +class AbstractSystemDropDownUserView extends AbstractViewNext { - AbstractView.call(this, 'Right', 'SystemDropDown'); + constructor() { + super(); - this.logoImg = Utils.trim(Settings.settingsGet('UserLogo')); - this.logoTitle = Utils.trim(Settings.settingsGet('UserLogoTitle')); + this.logoImg = trim(Settings.settingsGet('UserLogo')); + this.logoTitle = trim(Settings.settingsGet('UserLogoTitle')); - this.mobile = !!Settings.appSettingsGet('mobile'); - this.mobileDevice = !!Settings.appSettingsGet('mobileDevice'); + this.mobile = !!Settings.appSettingsGet('mobile'); + this.mobileDevice = !!Settings.appSettingsGet('mobileDevice'); - this.allowSettings = !!Settings.capa(Enums.Capa.Settings); - this.allowHelp = !!Settings.capa(Enums.Capa.Help); + this.allowSettings = !!Settings.capa(Capa.Settings); + this.allowHelp = !!Settings.capa(Capa.Help); - this.currentAudio = AppStore.currentAudio; + this.currentAudio = AppStore.currentAudio; - this.accountEmail = AccountStore.email; + this.accountEmail = AccountStore.email; - this.accounts = AccountStore.accounts; - this.accountsUnreadCount = AccountStore.accountsUnreadCount; + this.accounts = AccountStore.accounts; + this.accountsUnreadCount = AccountStore.accountsUnreadCount; - this.accountMenuDropdownTrigger = ko.observable(false); - this.capaAdditionalAccounts = ko.observable(Settings.capa(Enums.Capa.AdditionalAccounts)); + this.accountMenuDropdownTrigger = ko.observable(false); + this.capaAdditionalAccounts = ko.observable(Settings.capa(Capa.AdditionalAccounts)); - this.accountClick = _.bind(this.accountClick, this); + this.addAccountClick = _.bind(this.addAccountClick, this); - this.accountClick = _.bind(this.accountClick, this); + Events.sub('audio.stop', () => AppStore.currentAudio('')); + Events.sub('audio.start', (sName) => AppStore.currentAudio(sName)); + } - Events.sub('audio.stop', function() { - AppStore.currentAudio(''); - }); + stopPlay() { + Events.pub('audio.api.stop'); + } - Events.sub('audio.start', function(sName) { - AppStore.currentAudio(sName); - }); + accountClick(oAccount, oEvent) { + if (oAccount && oEvent && !isUnd(oEvent.which) && 1 === oEvent.which) + { + AccountStore.accounts.loading(true); + _.delay(() => AccountStore.accounts.loading(false), Magics.Time1s); + } + + return true; + } + + emailTitle() { + return AccountStore.email(); + } + + settingsClick() { + if (Settings.capa(Capa.Settings)) + { + setHash(settings()); + } + } + + settingsHelp() + { + if (Settings.capa(Capa.Help)) + { + showScreenPopup(require('View/Popup/KeyboardShortcutsHelp')); + } + } + + addAccountClick() { + if (this.capaAdditionalAccounts()) + { + showScreenPopup(require('View/Popup/Account')); + } + } + + logoutClick() { + getApp().logout(); + } + + onBuild() { + key('`', [KeyState.MessageList, KeyState.MessageView, KeyState.Settings], () => { + if (this.viewModelVisibility()) + { + MessageStore.messageFullScreenMode(false); + this.accountMenuDropdownTrigger(true); + } + }); + + // shortcuts help + key('shift+/', [KeyState.MessageList, KeyState.MessageView, KeyState.Settings], () => { + if (this.viewModelVisibility()) + { + showScreenPopup(require('View/Popup/KeyboardShortcutsHelp')); + return false; + } + return true; + }); + } } -_.extend(AbstractSystemDropDownUserView.prototype, AbstractView.prototype); - -AbstractSystemDropDownUserView.prototype.stopPlay = function() -{ - Events.pub('audio.api.stop'); -}; - -AbstractSystemDropDownUserView.prototype.accountClick = function(oAccount, oEvent) -{ - if (oAccount && oEvent && !Utils.isUnd(oEvent.which) && 1 === oEvent.which) - { - AccountStore.accounts.loading(true); - - _.delay(function() { - AccountStore.accounts.loading(false); - }, Enums.Magics.Time1s); - } - - return true; -}; - -AbstractSystemDropDownUserView.prototype.emailTitle = function() -{ - return AccountStore.email(); -}; - -AbstractSystemDropDownUserView.prototype.settingsClick = function() -{ - if (Settings.capa(Enums.Capa.Settings)) - { - require('Knoin/Knoin').setHash(Links.settings()); - } -}; - -AbstractSystemDropDownUserView.prototype.settingsHelp = function() -{ - if (Settings.capa(Enums.Capa.Help)) - { - require('Knoin/Knoin').showScreenPopup(require('View/Popup/KeyboardShortcutsHelp')); - } -}; - -AbstractSystemDropDownUserView.prototype.addAccountClick = function() -{ - if (this.capaAdditionalAccounts()) - { - require('Knoin/Knoin').showScreenPopup(require('View/Popup/Account')); - } -}; - -AbstractSystemDropDownUserView.prototype.logoutClick = function() -{ - require('App/User').default.logout(); -}; - -AbstractSystemDropDownUserView.prototype.onBuild = function() -{ - var self = this; - key('`', [Enums.KeyState.MessageList, Enums.KeyState.MessageView, Enums.KeyState.Settings], function() { - if (self.viewModelVisibility()) - { - MessageStore.messageFullScreenMode(false); - - self.accountMenuDropdownTrigger(true); - } - }); - - // shortcuts help - key('shift+/', [Enums.KeyState.MessageList, Enums.KeyState.MessageView, Enums.KeyState.Settings], function() { - if (self.viewModelVisibility()) - { - require('Knoin/Knoin').showScreenPopup(require('View/Popup/KeyboardShortcutsHelp')); - return false; - } - return true; - }); -}; - -module.exports = AbstractSystemDropDownUserView; +export {AbstractSystemDropDownUserView, AbstractSystemDropDownUserView as default}; diff --git a/dev/View/User/Login.js b/dev/View/User/Login.js index 43009d0be..084198e3e 100644 --- a/dev/View/User/Login.js +++ b/dev/View/User/Login.js @@ -3,487 +3,474 @@ import window from 'window'; import _ from '_'; import ko from 'ko'; -var - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Links = require('Common/Links'), +import { + LoginSignMeType, + LoginSignMeTypeAsString, + ClientSideKeyName, + StorageResultType, + Magics, + Notification +} from 'Common/Enums'; - Translator = require('Common/Translator'), +import { + trim, inArray, pInt, + convertLangName, + createCommand, + triggerAutocompleteInputChange +} from 'Common/Utils'; - Plugins = require('Common/Plugins'), +import {socialFacebook, socialGoogle, socialTwitter} from 'Common/Links'; +import {getNotification, getNotificationFromResponse, reload as translatorReload} from 'Common/Translator'; - LanguageStore = require('Stores/Language'), - AppStore = require('Stores/User/App'), +import * as Plugins from 'Common/Plugins'; - Local = require('Storage/Client'), - Settings = require('Storage/Settings'), +import AppStore from 'Stores/User/App'; +import LanguageStore from 'Stores/Language'; - Remote = require('Remote/User/Ajax'), +import * as Settings from 'Storage/Settings'; +import * as Local from 'Storage/Client'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import Remote from 'Remote/User/Ajax'; -/** - * @constructor - * @extends AbstractView - */ -function LoginUserView() +import {getApp} from 'Helper/Apps/User'; + +import {view, ViewType, routeOff, showScreenPopup} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; + +@view({ + name: 'View/User/Login', + type: ViewType.Center, + templateID: 'Login' +}) +class LoginUserView extends AbstractViewNext { - AbstractView.call(this, 'Center', 'Login'); + constructor() { + super(); - this.welcome = ko.observable(!!Settings.settingsGet('UseLoginWelcomePage')); + this.welcome = ko.observable(!!Settings.settingsGet('UseLoginWelcomePage')); - this.email = ko.observable(''); - this.password = ko.observable(''); - this.signMe = ko.observable(false); + this.email = ko.observable(''); + this.password = ko.observable(''); + this.signMe = ko.observable(false); - this.additionalCode = ko.observable(''); - this.additionalCode.error = ko.observable(false); - this.additionalCode.errorAnimation = ko.observable(false).extend({'falseTimeout': 500}); - this.additionalCode.focused = ko.observable(false); - this.additionalCode.visibility = ko.observable(false); - this.additionalCodeSignMe = ko.observable(false); + this.additionalCode = ko.observable(''); + this.additionalCode.error = ko.observable(false); + this.additionalCode.errorAnimation = ko.observable(false).extend({falseTimeout: 500}); + this.additionalCode.focused = ko.observable(false); + this.additionalCode.visibility = ko.observable(false); + this.additionalCodeSignMe = ko.observable(false); - this.logoImg = Utils.trim(Settings.settingsGet('LoginLogo')); - this.logoPowered = !!Settings.settingsGet('LoginPowered'); - this.loginDescription = Utils.trim(Settings.settingsGet('LoginDescription')); + this.logoImg = trim(Settings.settingsGet('LoginLogo')); + this.logoPowered = !!Settings.settingsGet('LoginPowered'); + this.loginDescription = trim(Settings.settingsGet('LoginDescription')); - this.mobile = !!Settings.appSettingsGet('mobile'); - this.mobileDevice = !!Settings.appSettingsGet('mobileDevice'); + this.mobile = !!Settings.appSettingsGet('mobile'); + this.mobileDevice = !!Settings.appSettingsGet('mobileDevice'); - this.forgotPasswordLinkUrl = Settings.appSettingsGet('forgotPasswordLinkUrl'); - this.registrationLinkUrl = Settings.appSettingsGet('registrationLinkUrl'); + this.forgotPasswordLinkUrl = Settings.appSettingsGet('forgotPasswordLinkUrl'); + this.registrationLinkUrl = Settings.appSettingsGet('registrationLinkUrl'); - this.emailError = ko.observable(false); - this.passwordError = ko.observable(false); + this.emailError = ko.observable(false); + this.passwordError = ko.observable(false); - this.emailErrorAnimation = ko.observable(false).extend({'falseTimeout': 500}); - this.passwordErrorAnimation = ko.observable(false).extend({'falseTimeout': 500}); + this.emailErrorAnimation = ko.observable(false).extend({falseTimeout: 500}); + this.passwordErrorAnimation = ko.observable(false).extend({falseTimeout: 500}); - this.formHidden = ko.observable(false); + this.formHidden = ko.observable(false); - this.formError = ko.computed(function() { - return this.emailErrorAnimation() || this.passwordErrorAnimation() || - (this.additionalCode.visibility() && this.additionalCode.errorAnimation()); - }, this); + this.formError = ko.computed( + () => this.emailErrorAnimation() || this.passwordErrorAnimation() || + (this.additionalCode.visibility() && this.additionalCode.errorAnimation()) + ); - this.emailFocus = ko.observable(false); - this.passwordFocus = ko.observable(false); - this.submitFocus = ko.observable(false); + this.emailFocus = ko.observable(false); + this.passwordFocus = ko.observable(false); + this.submitFocus = ko.observable(false); - this.email.subscribe(function() { - this.emailError(false); - this.additionalCode(''); - this.additionalCode.visibility(false); - }, this); + this.email.subscribe(() => { + this.emailError(false); + this.additionalCode(''); + this.additionalCode.visibility(false); + }); - this.password.subscribe(function() { - this.passwordError(false); - }, this); + this.password.subscribe(() => { + this.passwordError(false); + }); - this.additionalCode.subscribe(function() { - this.additionalCode.error(false); - }, this); - - this.additionalCode.visibility.subscribe(function() { - this.additionalCode.error(false); - }, this); - - this.emailError.subscribe(function(bV) { - this.emailErrorAnimation(!!bV); - }, this); - - this.passwordError.subscribe(function(bV) { - this.passwordErrorAnimation(!!bV); - }, this); - - this.additionalCode.error.subscribe(function(bV) { - this.additionalCode.errorAnimation(!!bV); - }, this); - - this.submitRequest = ko.observable(false); - this.submitError = ko.observable(''); - this.submitErrorAddidional = ko.observable(''); - - this.submitError.subscribe(function(sValue) { - if ('' === sValue) - { - this.submitErrorAddidional(''); - } - }, this); - - this.allowLanguagesOnLogin = AppStore.allowLanguagesOnLogin; - - this.langRequest = ko.observable(false); - this.language = LanguageStore.language; - this.languages = LanguageStore.languages; - - this.bSendLanguage = false; - - this.languageFullName = ko.computed(function() { - return Utils.convertLangName(this.language()); - }, this); - - this.signMeType = ko.observable(Enums.LoginSignMeType.Unused); - - this.signMeType.subscribe(function(iValue) { - this.signMe(Enums.LoginSignMeType.DefaultOn === iValue); - }, this); - - this.signMeVisibility = ko.computed(function() { - return Enums.LoginSignMeType.Unused !== this.signMeType(); - }, this); - - this.submitCommand = Utils.createCommand(this, function() { - Utils.triggerAutocompleteInputChange(); - - this.emailError(false); - this.passwordError(false); - - this.emailError('' === Utils.trim(this.email())); - this.passwordError('' === Utils.trim(this.password())); - - if (this.additionalCode.visibility()) - { + this.additionalCode.subscribe(() => { this.additionalCode.error(false); - this.additionalCode.error('' === Utils.trim(this.additionalCode())); - } + }); - if (this.emailError() || this.passwordError() || - (this.additionalCode.visibility() && this.additionalCode.error())) - { - switch (true) + this.additionalCode.visibility.subscribe(() => { + this.additionalCode.error(false); + }); + + this.emailError.subscribe((bV) => { + this.emailErrorAnimation(!!bV); + }); + + this.passwordError.subscribe((bV) => { + this.passwordErrorAnimation(!!bV); + }); + + this.additionalCode.error.subscribe((bV) => { + this.additionalCode.errorAnimation(!!bV); + }); + + this.submitRequest = ko.observable(false); + this.submitError = ko.observable(''); + this.submitErrorAddidional = ko.observable(''); + + this.submitError.subscribe((value) => { + if ('' === value) { - case this.emailError(): - this.emailFocus(true); - break; - case this.passwordError(): - this.passwordFocus(true); - break; - case this.additionalCode.visibility() && this.additionalCode.error(): - this.additionalCode.focused(true); - break; - // no default + this.submitErrorAddidional(''); + } + }); + + this.allowLanguagesOnLogin = AppStore.allowLanguagesOnLogin; + + this.langRequest = ko.observable(false); + this.language = LanguageStore.language; + this.languages = LanguageStore.languages; + + this.bSendLanguage = false; + + this.languageFullName = ko.computed( + () => convertLangName(this.language()) + ); + + this.signMeType = ko.observable(LoginSignMeType.Unused); + + this.signMeType.subscribe((iValue) => { + this.signMe(LoginSignMeType.DefaultOn === iValue); + }); + + this.signMeVisibility = ko.computed( + () => LoginSignMeType.Unused !== this.signMeType() + ); + + this.submitCommand = createCommand(() => { + triggerAutocompleteInputChange(); + + this.emailError(false); + this.passwordError(false); + + this.emailError('' === trim(this.email())); + this.passwordError('' === trim(this.password())); + + if (this.additionalCode.visibility()) + { + this.additionalCode.error(false); + this.additionalCode.error('' === trim(this.additionalCode())); } - return false; - } + if (this.emailError() || this.passwordError() || + (this.additionalCode.visibility() && this.additionalCode.error())) + { + switch (true) + { + case this.emailError(): + this.emailFocus(true); + break; + case this.passwordError(): + this.passwordFocus(true); + break; + case this.additionalCode.visibility() && this.additionalCode.error(): + this.additionalCode.focused(true); + break; + // no default + } - var - iPluginResultCode = 0, - sPluginResultMessage = '', - fSubmitResult = function(iResultCode, sResultMessage) { - iPluginResultCode = iResultCode || 0; - sPluginResultMessage = sResultMessage || ''; - }; + return false; + } - Plugins.runHook('user-login-submit', [fSubmitResult]); - if (0 < iPluginResultCode) - { - this.submitError(Translator.getNotification(iPluginResultCode)); - return false; - } - else if ('' !== sPluginResultMessage) - { - this.submitError(sPluginResultMessage); - return false; - } + let + pluginResultCode = 0, + pluginResultMessage = ''; - this.submitRequest(true); + const + fSubmitResult = (iResultCode, sResultMessage) => { + pluginResultCode = iResultCode || 0; + pluginResultMessage = sResultMessage || ''; + }; - var - self = this, - sPassword = this.password(), + Plugins.runHook('user-login-submit', [fSubmitResult]); + if (0 < pluginResultCode) + { + this.submitError(getNotification(pluginResultCode)); + return false; + } + else if ('' !== pluginResultMessage) + { + this.submitError(pluginResultMessage); + return false; + } - fLoginRequest = _.bind(function(sLoginPassword) { + this.submitRequest(true); - Remote.login(_.bind(function(sResult, oData) { + const + fLoginRequest = (sLoginPassword) => { - if (Enums.StorageResultType.Success === sResult && oData && 'Login' === oData.Action) - { - if (oData.Result) + Remote.login((sResult, oData) => { + + if (StorageResultType.Success === sResult && oData && 'Login' === oData.Action) { - if (oData.TwoFactorAuth) + if (oData.Result) + { + if (oData.TwoFactorAuth) + { + this.additionalCode(''); + this.additionalCode.visibility(true); + this.submitRequest(false); + + _.delay(() => this.additionalCode.focused(true), Magics.Time100ms); + } + else if (oData.Admin) + { + getApp().redirectToAdminPanel(); + } + else + { + getApp().loginAndLogoutReload(false); + } + } + else if (oData.ErrorCode) { - this.additionalCode(''); - this.additionalCode.visibility(true); this.submitRequest(false); + if (-1 < inArray(oData.ErrorCode, [Notification.InvalidInputArgument])) + { + oData.ErrorCode = Notification.AuthError; + } - _.delay(function() { - self.additionalCode.focused(true); - }, Enums.Magics.Time100ms); - } - else if (oData.Admin) - { - require('App/User').default.redirectToAdminPanel(); - } - else - { - require('App/User').default.loginAndLogoutReload(false); - } - } - else if (oData.ErrorCode) - { - this.submitRequest(false); - if (-1 < Utils.inArray(oData.ErrorCode, [Enums.Notification.InvalidInputArgument])) - { - oData.ErrorCode = Enums.Notification.AuthError; - } + this.submitError(getNotificationFromResponse(oData)); - this.submitError(Translator.getNotificationFromResponse(oData)); - - if ('' === this.submitError()) - { - this.submitError(Translator.getNotification(Enums.Notification.UnknownError)); - } - else - { - if (oData.ErrorMessageAdditional) + if ('' === this.submitError()) + { + this.submitError(getNotification(Notification.UnknownError)); + } + else if (oData.ErrorMessageAdditional) { this.submitErrorAddidional(oData.ErrorMessageAdditional); } } + else + { + this.submitRequest(false); + } } else { this.submitRequest(false); + this.submitError(getNotification(Notification.UnknownError)); } - } - else - { - this.submitRequest(false); - this.submitError(Translator.getNotification(Enums.Notification.UnknownError)); - } - }, this), this.email(), '', sLoginPassword, !!this.signMe(), - this.bSendLanguage ? this.language() : '', - this.additionalCode.visibility() ? this.additionalCode() : '', - this.additionalCode.visibility() ? !!this.additionalCodeSignMe() : false - ); + }, this.email(), '', sLoginPassword, !!this.signMe(), + this.bSendLanguage ? this.language() : '', + this.additionalCode.visibility() ? this.additionalCode() : '', + this.additionalCode.visibility() ? !!this.additionalCodeSignMe() : false + ); - Local.set(Enums.ClientSideKeyName.LastSignMe, this.signMe() ? '-1-' : '-0-'); + Local.set(ClientSideKeyName.LastSignMe, this.signMe() ? '-1-' : '-0-'); - }, this); + }; - fLoginRequest(sPassword); + fLoginRequest(this.password()); - return true; - }, function() { - return !this.submitRequest(); - }); + return true; - this.facebookLoginEnabled = ko.observable(false); + }, () => !this.submitRequest()); - this.facebookCommand = Utils.createCommand(this, function() { - window.open(Links.socialFacebook(), 'Facebook', - 'left=200,top=100,width=500,height=500,menubar=no,status=no,resizable=yes,scrollbars=yes'); - return true; - }, function() { - return !this.submitRequest() && this.facebookLoginEnabled(); - }); + this.facebookLoginEnabled = ko.observable(false); - this.googleLoginEnabled = ko.observable(false); - this.googleFastLoginEnabled = ko.observable(false); + this.facebookCommand = createCommand(() => { + window.open(socialFacebook(), 'Facebook', + 'left=200,top=100,width=500,height=500,menubar=no,status=no,resizable=yes,scrollbars=yes'); + return true; + }, () => !this.submitRequest() && this.facebookLoginEnabled()); - this.googleCommand = Utils.createCommand(this, function() { - window.open(Links.socialGoogle(), 'Google', - 'left=200,top=100,width=550,height=550,menubar=no,status=no,resizable=yes,scrollbars=yes'); - return true; - }, function() { - return !this.submitRequest() && this.googleLoginEnabled(); - }); + this.googleLoginEnabled = ko.observable(false); + this.googleFastLoginEnabled = ko.observable(false); - this.googleFastCommand = Utils.createCommand(this, function() { - window.open(Links.socialGoogle(true), 'Google', - 'left=200,top=100,width=550,height=550,menubar=no,status=no,resizable=yes,scrollbars=yes'); - return true; - }, function() { - return !this.submitRequest() && this.googleFastLoginEnabled(); - }); + this.googleCommand = createCommand(() => { + window.open(socialGoogle(), 'Google', + 'left=200,top=100,width=550,height=550,menubar=no,status=no,resizable=yes,scrollbars=yes'); + return true; + }, () => !this.submitRequest() && this.googleLoginEnabled()); - this.twitterLoginEnabled = ko.observable(false); + this.googleFastCommand = createCommand(() => { + window.open(socialGoogle(true), 'Google', + 'left=200,top=100,width=550,height=550,menubar=no,status=no,resizable=yes,scrollbars=yes'); + return true; + }, () => !this.submitRequest() && this.googleFastLoginEnabled()); - this.twitterCommand = Utils.createCommand(this, function() { - window.open(Links.socialTwitter(), 'Twitter', - 'left=200,top=100,width=500,height=500,menubar=no,status=no,resizable=yes,scrollbars=yes'); - return true; - }, function() { - return !this.submitRequest() && this.twitterLoginEnabled(); - }); + this.twitterLoginEnabled = ko.observable(false); - this.socialLoginEnabled = ko.computed(function() { - var - bF = this.facebookLoginEnabled(), - bG = this.googleLoginEnabled(), - bT = this.twitterLoginEnabled(); + this.twitterCommand = createCommand(() => { + window.open(socialTwitter(), 'Twitter', + 'left=200,top=100,width=500,height=500,menubar=no,status=no,resizable=yes,scrollbars=yes'); + return true; + }, () => !this.submitRequest() && this.twitterLoginEnabled()); - return bF || bG || bT; - }, this); - - if (Settings.settingsGet('AdditionalLoginError') && !this.submitError()) - { - this.submitError(Settings.settingsGet('AdditionalLoginError')); - } - - kn.constructorEnd(this); -} - -kn.extendAsViewModel(['View/User/Login', 'View/App/Login', 'LoginViewModel'], LoginUserView); -_.extend(LoginUserView.prototype, AbstractView.prototype); - -LoginUserView.prototype.displayMainForm = function() -{ - this.welcome(false); -}; - -LoginUserView.prototype.onShow = function() -{ - kn.routeOff(); -}; - -LoginUserView.prototype.onShowWithDelay = function() -{ - if ('' !== this.email() && '' !== this.password()) - { - this.submitFocus(true); - } - else if ('' === this.email()) - { - this.emailFocus(true); - } - else if ('' === this.password()) - { - this.passwordFocus(true); - } - else - { - this.emailFocus(true); - } -}; - -LoginUserView.prototype.onHide = function() -{ - this.submitFocus(false); - this.emailFocus(false); - this.passwordFocus(false); -}; - -LoginUserView.prototype.onBuild = function() -{ - var - self = this, - sSignMeLocal = Local.get(Enums.ClientSideKeyName.LastSignMe), - sSignMe = (Settings.settingsGet('SignMe') || 'unused').toLowerCase(), - sJsHash = Settings.appSettingsGet('jsHash'), - fSocial = function(iErrorCode) { - iErrorCode = Utils.pInt(iErrorCode); - if (0 === iErrorCode) - { - self.submitRequest(true); - require('App/User').default.loginAndLogoutReload(false); - } - else - { - self.submitError(Translator.getNotification(iErrorCode)); - } - }; - - this.facebookLoginEnabled(!!Settings.settingsGet('AllowFacebookSocial')); - this.twitterLoginEnabled(!!Settings.settingsGet('AllowTwitterSocial')); - this.googleLoginEnabled(!!Settings.settingsGet('AllowGoogleSocial') && - !!Settings.settingsGet('AllowGoogleSocialAuth')); - this.googleFastLoginEnabled(!!Settings.settingsGet('AllowGoogleSocial') && - !!Settings.settingsGet('AllowGoogleSocialAuthFast')); - - switch (sSignMe) - { - case Enums.LoginSignMeTypeAsString.DefaultOff: - case Enums.LoginSignMeTypeAsString.DefaultOn: - - this.signMeType(Enums.LoginSignMeTypeAsString.DefaultOn === sSignMe ? - Enums.LoginSignMeType.DefaultOn : Enums.LoginSignMeType.DefaultOff); - - switch (sSignMeLocal) - { - case '-1-': - this.signMeType(Enums.LoginSignMeType.DefaultOn); - break; - case '-0-': - this.signMeType(Enums.LoginSignMeType.DefaultOff); - break; - // no default - } - - break; - case Enums.LoginSignMeTypeAsString.Unused: - default: - this.signMeType(Enums.LoginSignMeType.Unused); - break; - } - - this.email(AppStore.devEmail); - this.password(AppStore.devPassword); - - if (this.googleLoginEnabled() || this.googleFastLoginEnabled()) - { - 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() { - - LanguageStore.language.subscribe(function(sValue) { - - self.langRequest(true); - - Translator.reload(false, sValue).then(function() { - self.langRequest(false); - self.bSendLanguage = true; - }, function() { - self.langRequest(false); - }); + this.socialLoginEnabled = ko.computed(() => { + const + bF = this.facebookLoginEnabled(), + bG = this.googleLoginEnabled(), + bT = this.twitterLoginEnabled(); + return bF || bG || bT; }); - }, Enums.Magics.Time50ms); - - Utils.triggerAutocompleteInputChange(true); -}; - -LoginUserView.prototype.submitForm = function() -{ - this.submitCommand(); -}; - -LoginUserView.prototype.selectLanguage = function() -{ - kn.showScreenPopup(require('View/Popup/Languages'), [ - this.language, this.languages(), LanguageStore.userLanguage() - ]); -}; - -LoginUserView.prototype.selectLanguageOnTab = function(bShift) -{ - if (!bShift) - { - var self = this; - _.delay(function() { - self.emailFocus(true); - }, Enums.Magics.Time50ms); - - return false; + if (Settings.settingsGet('AdditionalLoginError') && !this.submitError()) + { + this.submitError(Settings.settingsGet('AdditionalLoginError')); + } } - return true; -}; + displayMainForm() { + this.welcome(false); + } -module.exports = LoginUserView; + onShow() { + routeOff(); + } + + onShowWithDelay() { + if ('' !== this.email() && '' !== this.password()) + { + this.submitFocus(true); + } + else if ('' === this.email()) + { + this.emailFocus(true); + } + else if ('' === this.password()) + { + this.passwordFocus(true); + } + else + { + this.emailFocus(true); + } + } + + onHide() { + this.submitFocus(false); + this.emailFocus(false); + this.passwordFocus(false); + } + + onBuild() { + const + signMeLocal = Local.get(ClientSideKeyName.LastSignMe), + signMe = (Settings.settingsGet('SignMe') || 'unused').toLowerCase(), + jsHash = Settings.appSettingsGet('jsHash'), + fSocial = (iErrorCode) => { + iErrorCode = pInt(iErrorCode); + if (0 === iErrorCode) + { + this.submitRequest(true); + getApp().loginAndLogoutReload(false); + } + else + { + this.submitError(getNotification(iErrorCode)); + } + }; + + this.facebookLoginEnabled(!!Settings.settingsGet('AllowFacebookSocial')); + this.twitterLoginEnabled(!!Settings.settingsGet('AllowTwitterSocial')); + this.googleLoginEnabled(!!Settings.settingsGet('AllowGoogleSocial') && + !!Settings.settingsGet('AllowGoogleSocialAuth')); + this.googleFastLoginEnabled(!!Settings.settingsGet('AllowGoogleSocial') && + !!Settings.settingsGet('AllowGoogleSocialAuthFast')); + + switch (signMe) + { + case LoginSignMeTypeAsString.DefaultOff: + case LoginSignMeTypeAsString.DefaultOn: + + this.signMeType(LoginSignMeTypeAsString.DefaultOn === signMe ? + LoginSignMeType.DefaultOn : LoginSignMeType.DefaultOff); + + switch (signMeLocal) + { + case '-1-': + this.signMeType(LoginSignMeType.DefaultOn); + break; + case '-0-': + this.signMeType(LoginSignMeType.DefaultOff); + break; + // no default + } + + break; + case LoginSignMeTypeAsString.Unused: + default: + this.signMeType(LoginSignMeType.Unused); + break; + } + + this.email(AppStore.devEmail); + this.password(AppStore.devPassword); + + if (this.googleLoginEnabled() || this.googleFastLoginEnabled()) + { + window['rl_' + jsHash + '_google_login_service'] = fSocial; + } + + if (this.facebookLoginEnabled()) + { + window['rl_' + jsHash + '_facebook_login_service'] = fSocial; + } + + if (this.twitterLoginEnabled()) + { + window['rl_' + jsHash + '_twitter_login_service'] = fSocial; + } + + _.delay(() => { + + LanguageStore.language.subscribe((sValue) => { + + this.langRequest(true); + + translatorReload(false, sValue).then(() => { + this.langRequest(false); + this.bSendLanguage = true; + }, () => { + this.langRequest(false); + }); + + }); + + }, Magics.Time50ms); + + triggerAutocompleteInputChange(true); + } + + submitForm() { + this.submitCommand(); + } + + selectLanguage() { + showScreenPopup(require('View/Popup/Languages'), [ + this.language, this.languages(), LanguageStore.userLanguage() + ]); + } + + selectLanguageOnTab(bShift) { + if (!bShift) + { + _.delay(() => { + this.emailFocus(true); + }, Magics.Time50ms); + + return false; + } + + return true; + } +} + +export {LoginUserView, LoginUserView as default}; diff --git a/dev/View/User/MailBox/FolderList.js b/dev/View/User/MailBox/FolderList.js index 0d4fe32e8..bb253e4da 100644 --- a/dev/View/User/MailBox/FolderList.js +++ b/dev/View/User/MailBox/FolderList.js @@ -1,306 +1,290 @@ -var - window = require('window'), - _ = require('_'), - $ = require('$'), - ko = require('ko'), - key = require('key'), +import window from 'window'; +import $ from '$'; +import ko from 'ko'; +import key from 'key'; - Utils = require('Common/Utils'), - Enums = require('Common/Enums'), - Globals = require('Common/Globals'), - Links = require('Common/Links'), +import {trim, isNormal, isArray, windowResize} from 'Common/Utils'; +import {Capa, Focused, Layout, KeyState, EventKeyCode, Magics} from 'Common/Enums'; +import {$html, leftPanelDisabled} from 'Common/Globals'; +import {mailBox, settings} from 'Common/Links'; +import {setFolderHash} from 'Common/Cache'; - Cache = require('Common/Cache'), +import AppStore from 'Stores/User/App'; +import SettingsStore from 'Stores/User/Settings'; +import FolderStore from 'Stores/User/Folder'; +import MessageStore from 'Stores/User/Message'; - AppStore = require('Stores/User/App'), - SettingsStore = require('Stores/User/Settings'), - FolderStore = require('Stores/User/Folder'), - MessageStore = require('Stores/User/Message'), +import * as Settings from 'Storage/Settings'; - Settings = require('Storage/Settings'), +import {getApp} from 'Helper/Apps/User'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType, showScreenPopup, setHash} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function FolderListMailBoxUserView() +@view({ + name: 'View/User/MailBox/FolderList', + type: ViewType.Left, + templateID: 'MailFolderList' +}) +class FolderListMailBoxUserView extends AbstractViewNext { - AbstractView.call(this, 'Left', 'MailFolderList'); + constructor() { + super(); - this.oContentVisible = null; - this.oContentScrollable = null; + this.oContentVisible = null; + this.oContentScrollable = null; - this.composeInEdit = AppStore.composeInEdit; + this.composeInEdit = AppStore.composeInEdit; - this.messageList = MessageStore.messageList; - this.folderList = FolderStore.folderList; - this.folderListSystem = FolderStore.folderListSystem; - this.foldersChanging = FolderStore.foldersChanging; + this.messageList = MessageStore.messageList; + this.folderList = FolderStore.folderList; + this.folderListSystem = FolderStore.folderListSystem; + this.foldersChanging = FolderStore.foldersChanging; - this.foldersListWithSingleInboxRootFolder = FolderStore.foldersListWithSingleInboxRootFolder; + this.foldersListWithSingleInboxRootFolder = FolderStore.foldersListWithSingleInboxRootFolder; - this.leftPanelDisabled = Globals.leftPanelDisabled; + this.leftPanelDisabled = leftPanelDisabled; - this.iDropOverTimer = 0; + this.iDropOverTimer = 0; - this.allowComposer = !!Settings.capa(Enums.Capa.Composer); - this.allowContacts = !!AppStore.contactsIsAllowed(); - this.allowFolders = !!Settings.capa(Enums.Capa.Folders); + this.allowComposer = !!Settings.capa(Capa.Composer); + this.allowContacts = !!AppStore.contactsIsAllowed(); + this.allowFolders = !!Settings.capa(Capa.Folders); - this.folderListFocused = ko.computed(function() { - return Enums.Focused.FolderList === AppStore.focusedState(); - }); + this.folderListFocused = ko.computed(() => Focused.FolderList === AppStore.focusedState()); - this.isInboxStarred = ko.computed(function() { - return FolderStore.currentFolder() && - FolderStore.currentFolder().isInbox() && - -1 < Utils.trim(MessageStore.messageListSearch()).indexOf('is:flagged'); - }); + this.isInboxStarred = ko.computed( + () => FolderStore.currentFolder() && + FolderStore.currentFolder().isInbox() && + -1 < trim(MessageStore.messageListSearch()).indexOf('is:flagged') + ); + } - kn.constructorEnd(this); -} + onBuild(dom) { -kn.extendAsViewModel(['View/User/MailBox/FolderList', 'View/App/MailBox/FolderList', 'MailBoxFolderListViewModel'], FolderListMailBoxUserView); -_.extend(FolderListMailBoxUserView.prototype, AbstractView.prototype); + this.oContentVisible = $('.b-content', dom); + this.oContentScrollable = $('.content', this.oContentVisible); -FolderListMailBoxUserView.prototype.onBuild = function(oDom) -{ - this.oContentVisible = $('.b-content', oDom); - this.oContentScrollable = $('.content', this.oContentVisible); + const + self = this, + isMobile = Settings.appSettingsGet('mobile'), + fSelectFolder = (el, event, starred) => { - var - self = this, - bMobile = Settings.appSettingsGet('mobile'), - fSelectFolder = function(oEvent, bStarred) { - - if (bMobile) - { - Globals.leftPanelDisabled(true); - } - - oEvent.preventDefault(); - - if (bStarred) - { - oEvent.stopPropagation(); - } - - var - oFolder = ko.dataFor(this); - - if (oFolder) - { - if (Enums.Layout.NoPreview === SettingsStore.layout()) + if (isMobile) { - MessageStore.message(null); + leftPanelDisabled(true); } - if (oFolder.fullNameRaw === FolderStore.currentFolderFullNameRaw()) + event.preventDefault(); + + if (starred) { - Cache.setFolderHash(oFolder.fullNameRaw, ''); + event.stopPropagation(); } - if (bStarred) + const folder = ko.dataFor(el); + if (folder) { - kn.setHash(Links.mailBox(oFolder.fullNameHash, 1, 'is:flagged')); + if (Layout.NoPreview === SettingsStore.layout()) + { + MessageStore.message(null); + } + + if (folder.fullNameRaw === FolderStore.currentFolderFullNameRaw()) + { + setFolderHash(folder.fullNameRaw, ''); + } + + if (starred) + { + setHash(mailBox(folder.fullNameHash, 1, 'is:flagged')); + } + else + { + setHash(mailBox(folder.fullNameHash)); + } } - else + }; + + dom + .on('click', '.b-folders .e-item .e-link .e-collapsed-sign', function(event) { // eslint-disable-line prefer-arrow-callback + const folder = ko.dataFor(this); // eslint-disable-line no-invalid-this + if (folder && event) { - kn.setHash(Links.mailBox(oFolder.fullNameHash)); + const collapsed = folder.collapsed(); + getApp().setExpandedFolder(folder.fullNameHash, collapsed); + + folder.collapsed(!collapsed); + event.preventDefault(); + event.stopPropagation(); } - } - }; + }) + .on('click', '.b-folders .e-item .e-link.selectable .inbox-star-icon', function(event) { // eslint-disable-line prefer-arrow-callback + fSelectFolder(this, event, !self.isInboxStarred()); // eslint-disable-line no-invalid-this + }) + .on('click', '.b-folders .e-item .e-link.selectable', function(event) { // eslint-disable-line prefer-arrow-callback + fSelectFolder(this, event, false); // eslint-disable-line no-invalid-this + }); - oDom - .on('click', '.b-folders .e-item .e-link .e-collapsed-sign', function(oEvent) { + key('up, down', KeyState.FolderList, (event, handler) => { - var oFolder = ko.dataFor(this); - if (oFolder && oEvent) + const + keyCode = handler && 'up' === handler.shortcut ? EventKeyCode.Up : EventKeyCode.Down, + $items = $('.b-folders .e-item .e-link:not(.hidden):visible', dom); + + if (event && $items.length) { - var bCollapsed = oFolder.collapsed(); - require('App/User').default.setExpandedFolder(oFolder.fullNameHash, bCollapsed); + let index = $items.index($items.filter('.focused')); + if (-1 < index) + { + $items.eq(index).removeClass('focused'); + } - oFolder.collapsed(!bCollapsed); - oEvent.preventDefault(); - oEvent.stopPropagation(); + if (EventKeyCode.Up === keyCode && 0 < index) + { + index -= 1; + } + else if (EventKeyCode.Down === keyCode && index < $items.length - 1) + { + index += 1; + } + + $items.eq(index).addClass('focused'); + self.scrollToFocused(); } - }) - .on('click', '.b-folders .e-item .e-link.selectable .inbox-star-icon', function(oEvent) { - fSelectFolder.call(this, oEvent, !self.isInboxStarred()); - }) - .on('click', '.b-folders .e-item .e-link.selectable', function(oEvent) { - fSelectFolder.call(this, oEvent, false); + + return false; }); - key('up, down', Enums.KeyState.FolderList, function(event, handler) { - - var - iKeyCode = handler && 'up' === handler.shortcut ? Enums.EventKeyCode.Up : Enums.EventKeyCode.Down, - $items = $('.b-folders .e-item .e-link:not(.hidden):visible', oDom); - - if (event && $items.length) - { - var iIndex = $items.index($items.filter('.focused')); - if (-1 < iIndex) + key('enter', KeyState.FolderList, () => { + const $items = $('.b-folders .e-item .e-link:not(.hidden).focused', dom); + if ($items.length && $items[0]) { - $items.eq(iIndex).removeClass('focused'); + AppStore.focusedState(Focused.MessageList); + $items.click(); } - if (Enums.EventKeyCode.Up === iKeyCode && 0 < iIndex) + return false; + }); + + key('space', KeyState.FolderList, () => { + const $items = $('.b-folders .e-item .e-link:not(.hidden).focused', dom); + if ($items.length && $items[0]) { - iIndex -= 1; - } - else if (Enums.EventKeyCode.Down === iKeyCode && iIndex < $items.length - 1) - { - iIndex += 1; + const folder = ko.dataFor($items[0]); + if (folder) + { + const collapsed = folder.collapsed(); + getApp().setExpandedFolder(folder.fullNameHash, collapsed); + folder.collapsed(!collapsed); + } } - $items.eq(iIndex).addClass('focused'); - self.scrollToFocused(); - } + return false; + }); - return false; - }); + key('esc, tab, shift+tab, right', KeyState.FolderList, () => { + AppStore.focusedState(Focused.MessageList); + 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]) - { - AppStore.focusedState(Enums.Focused.MessageList); - $items.click(); - } - - return false; - }); - - key('space', Enums.KeyState.FolderList, function() { - var $items = $('.b-folders .e-item .e-link:not(.hidden).focused', oDom); - if ($items.length && $items[0]) - { - var oFolder = ko.dataFor($items[0]); - if (oFolder) + AppStore.focusedState.subscribe((value) => { + $('.b-folders .e-item .e-link.focused', dom).removeClass('focused'); + if (Focused.FolderList === value) { - var bCollapsed = oFolder.collapsed(); - require('App/User').default.setExpandedFolder(oFolder.fullNameHash, bCollapsed); - oFolder.collapsed(!bCollapsed); + $('.b-folders .e-item .e-link.selected', dom).addClass('focused'); + } + }); + } + + messagesDropOver(folder) { + window.clearTimeout(this.iDropOverTimer); + if (folder && folder.collapsed()) + { + this.iDropOverTimer = window.setTimeout(() => { + folder.collapsed(false); + getApp().setExpandedFolder(folder.fullNameHash, true); + windowResize(); + }, Magics.Time500ms); + } + } + + messagesDropOut() { + window.clearTimeout(this.iDropOverTimer); + } + + scrollToFocused() { + if (!this.oContentVisible || !this.oContentScrollable) + { + return false; + } + + const + offset = 20, + focused = $('.e-item .e-link.focused', this.oContentScrollable), + pos = focused.position(), + visibleHeight = this.oContentVisible.height(), + focusedHeight = focused.outerHeight(); + + if (pos && (0 > pos.top || pos.top + focusedHeight > visibleHeight)) + { + if (0 > pos.top) + { + this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + pos.top - offset); + } + else + { + this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + pos.top - visibleHeight + focusedHeight + offset); + } + + return true; + } + + return false; + } + + /** + * @param {FolderModel} toFolder + * @param {{helper:jQuery}} ui + * @returns {void} + */ + messagesDrop(toFolder, ui) { + if (toFolder && ui && ui.helper) + { + const + fromFolderFullNameRaw = ui.helper.data('rl-folder'), + copy = $html.hasClass('rl-ctrl-key-pressed'), + uids = ui.helper.data('rl-uids'); + + if (isNormal(fromFolderFullNameRaw) && '' !== fromFolderFullNameRaw && isArray(uids)) + { + getApp().moveMessagesToFolder(fromFolderFullNameRaw, uids, toFolder.fullNameRaw, copy); } } - - return false; - }); - - key('esc, tab, shift+tab, right', Enums.KeyState.FolderList, function() { - AppStore.focusedState(Enums.Focused.MessageList); - return false; - }); - - AppStore.focusedState.subscribe(function(mValue) { - $('.b-folders .e-item .e-link.focused', oDom).removeClass('focused'); - if (Enums.Focused.FolderList === mValue) - { - $('.b-folders .e-item .e-link.selected', oDom).addClass('focused'); - } - }); -}; - -FolderListMailBoxUserView.prototype.messagesDropOver = function(oFolder) -{ - window.clearTimeout(this.iDropOverTimer); - if (oFolder && oFolder.collapsed()) - { - this.iDropOverTimer = window.setTimeout(function() { - oFolder.collapsed(false); - require('App/User').default.setExpandedFolder(oFolder.fullNameHash, true); - Utils.windowResize(); - }, Enums.Magics.Time500ms); - } -}; - -FolderListMailBoxUserView.prototype.messagesDropOut = function() -{ - window.clearTimeout(this.iDropOverTimer); -}; - -FolderListMailBoxUserView.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 && (0 > oPos.top || oPos.top + iFocusedHeight > iVisibleHeight)) - { - if (0 > oPos.top) + composeClick() { + if (Settings.capa(Capa.Composer)) { - 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 - * @returns {void} - */ -FolderListMailBoxUserView.prototype.messagesDrop = function(oToFolder, oUi) -{ - if (oToFolder && oUi && oUi.helper) - { - var - sFromFolderFullNameRaw = oUi.helper.data('rl-folder'), - bCopy = Globals.$html.hasClass('rl-ctrl-key-pressed'), - aUids = oUi.helper.data('rl-uids'); - - if (Utils.isNormal(sFromFolderFullNameRaw) && '' !== sFromFolderFullNameRaw && Utils.isArray(aUids)) - { - require('App/User').default.moveMessagesToFolder(sFromFolderFullNameRaw, aUids, oToFolder.fullNameRaw, bCopy); + showScreenPopup(require('View/Popup/Compose')); } } -}; -FolderListMailBoxUserView.prototype.composeClick = function() -{ - if (Settings.capa(Enums.Capa.Composer)) - { - kn.showScreenPopup(require('View/Popup/Compose')); + createFolder() { + showScreenPopup(require('View/Popup/FolderCreate')); } -}; -FolderListMailBoxUserView.prototype.createFolder = function() -{ - kn.showScreenPopup(require('View/Popup/FolderCreate')); -}; - -FolderListMailBoxUserView.prototype.configureFolders = function() -{ - kn.setHash(Links.settings('folders')); -}; - -FolderListMailBoxUserView.prototype.contactsClick = function() -{ - if (this.allowContacts) - { - kn.showScreenPopup(require('View/Popup/Contacts')); + configureFolders() { + setHash(settings('folders')); } -}; -module.exports = FolderListMailBoxUserView; + contactsClick() { + if (this.allowContacts) + { + showScreenPopup(require('View/Popup/Contacts')); + } + } +} + +export {FolderListMailBoxUserView, FolderListMailBoxUserView as default}; diff --git a/dev/View/User/MailBox/MessageList.js b/dev/View/User/MailBox/MessageList.js index fd524cbac..ef04309d6 100644 --- a/dev/View/User/MailBox/MessageList.js +++ b/dev/View/User/MailBox/MessageList.js @@ -1,1064 +1,991 @@ -var - window = require('window'), - _ = require('_'), - $ = require('$'), - ko = require('ko'), - key = require('key'), - Jua = require('Jua'), - ifvisible = require('ifvisible'), +import window from 'window'; +import _ from '_'; +import $ from '$'; +import ko from 'ko'; +import key from 'key'; +import Jua from 'Jua'; +import ifvisible from 'ifvisible'; - Enums = require('Common/Enums'), - Consts = require('Common/Consts'), - Globals = require('Common/Globals'), - Utils = require('Common/Utils'), - Links = require('Common/Links'), - Events = require('Common/Events'), - Selector = require('Common/Selector'), - Translator = require('Common/Translator'), +import { + Capa, Layout, Focused, ComposeType, + FolderType, Magics, MessageSetAction, KeyState, + StorageResultType +} from 'Common/Enums'; - Cache = require('Common/Cache'), +import { + UNUSED_OPTION_VALUE +} from 'Common/Consts'; - AppStore = require('Stores/User/App'), - QuotaStore = require('Stores/User/Quota'), - SettingsStore = require('Stores/User/Settings'), - FolderStore = require('Stores/User/Folder'), - MessageStore = require('Stores/User/Message'), +import { + bMobileDevice, + popupVisibility, + leftPanelDisabled +} from 'Common/Globals'; - Settings = require('Storage/Settings'), - Remote = require('Remote/User/Ajax'), +import { + noop, + noopFalse, + createCommand, + computedPagenatorHelper, + draggablePlace, + friendlySize, + inArray, isUnd +} from 'Common/Utils'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {mailBox, append} from 'Common/Links'; +import {Selector} from 'Common/Selector'; +import * as Events from 'Common/Events'; -/** - * @constructor - * @extends AbstractView - */ -function MessageListMailBoxUserView() +import {i18n, initOnStartOrLangChange} from 'Common/Translator'; + +import { + getFolderFromCacheList, clearMessageFlagsFromCacheByFolder, + hasRequestedMessage, addRequestedMessage +} from 'Common/Cache'; + +import AppStore from 'Stores/User/App'; +import QuotaStore from 'Stores/User/Quota'; +import SettingsStore from 'Stores/User/Settings'; +import FolderStore from 'Stores/User/Folder'; +import MessageStore from 'Stores/User/Message'; + +import * as Settings from 'Storage/Settings'; +import Remote from 'Remote/User/Ajax'; + +import {getApp} from 'Helper/Apps/User'; + +import {view, ViewType, showScreenPopup, setHash} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; + +@view({ + name: 'View/User/MailBox/MessageList', + type: ViewType.Right, + templateID: 'MailMessageList' +}) +class MessageListMailBoxUserView extends AbstractViewNext { - AbstractView.call(this, 'Right', 'MailMessageList'); + constructor() { + super(); - this.sLastUid = null; - this.bPrefetch = false; - this.emptySubjectValue = ''; + this.sLastUid = null; + this.bPrefetch = false; + this.emptySubjectValue = ''; - this.mobile = !!Settings.appSettingsGet('mobile'); + this.iGoToUpUpOrDownDownTimeout = 0; - this.allowReload = !!Settings.capa(Enums.Capa.Reload); - this.allowSearch = !!Settings.capa(Enums.Capa.Search); - this.allowSearchAdv = !!Settings.capa(Enums.Capa.SearchAdv); - this.allowComposer = !!Settings.capa(Enums.Capa.Composer); - this.allowMessageListActions = !!Settings.capa(Enums.Capa.MessageListActions); - this.allowDangerousActions = !!Settings.capa(Enums.Capa.DangerousActions); - this.allowFolders = !!Settings.capa(Enums.Capa.Folders); + this.mobile = !!Settings.appSettingsGet('mobile'); - this.popupVisibility = Globals.popupVisibility; + this.allowReload = !!Settings.capa(Capa.Reload); + this.allowSearch = !!Settings.capa(Capa.Search); + this.allowSearchAdv = !!Settings.capa(Capa.SearchAdv); + this.allowComposer = !!Settings.capa(Capa.Composer); + this.allowMessageListActions = !!Settings.capa(Capa.MessageListActions); + this.allowDangerousActions = !!Settings.capa(Capa.DangerousActions); + this.allowFolders = !!Settings.capa(Capa.Folders); - this.message = MessageStore.message; - this.messageList = MessageStore.messageList; - this.messageListDisableAutoSelect = MessageStore.messageListDisableAutoSelect; + this.popupVisibility = popupVisibility; - this.folderList = FolderStore.folderList; + this.message = MessageStore.message; + this.messageList = MessageStore.messageList; + this.messageListDisableAutoSelect = MessageStore.messageListDisableAutoSelect; - this.composeInEdit = AppStore.composeInEdit; - this.leftPanelDisabled = Globals.leftPanelDisabled; + this.folderList = FolderStore.folderList; - this.selectorMessageSelected = MessageStore.selectorMessageSelected; - this.selectorMessageFocused = MessageStore.selectorMessageFocused; - this.isMessageSelected = MessageStore.isMessageSelected; - this.messageListSearch = MessageStore.messageListSearch; - this.messageListThreadUid = MessageStore.messageListThreadUid; - this.messageListError = MessageStore.messageListError; - this.folderMenuForMove = FolderStore.folderMenuForMove; + this.composeInEdit = AppStore.composeInEdit; + this.leftPanelDisabled = leftPanelDisabled; - this.useCheckboxesInList = SettingsStore.useCheckboxesInList; + this.selectorMessageSelected = MessageStore.selectorMessageSelected; + this.selectorMessageFocused = MessageStore.selectorMessageFocused; + this.isMessageSelected = MessageStore.isMessageSelected; + this.messageListSearch = MessageStore.messageListSearch; + this.messageListThreadUid = MessageStore.messageListThreadUid; + this.messageListError = MessageStore.messageListError; + this.folderMenuForMove = FolderStore.folderMenuForMove; - this.mainMessageListSearch = MessageStore.mainMessageListSearch; - this.messageListEndFolder = MessageStore.messageListEndFolder; - this.messageListEndThreadUid = MessageStore.messageListEndThreadUid; + this.useCheckboxesInList = SettingsStore.useCheckboxesInList; - this.messageListChecked = MessageStore.messageListChecked; - this.messageListCheckedOrSelected = MessageStore.messageListCheckedOrSelected; - this.messageListCheckedOrSelectedUidsWithSubMails = MessageStore.messageListCheckedOrSelectedUidsWithSubMails; - this.messageListCompleteLoadingThrottle = MessageStore.messageListCompleteLoadingThrottle; - this.messageListCompleteLoadingThrottleForAnimation = MessageStore.messageListCompleteLoadingThrottleForAnimation; + this.mainMessageListSearch = MessageStore.mainMessageListSearch; + this.messageListEndFolder = MessageStore.messageListEndFolder; + this.messageListEndThreadUid = MessageStore.messageListEndThreadUid; - Translator.initOnStartOrLangChange(_.bind(function() { - this.emptySubjectValue = Translator.i18n('MESSAGE_LIST/EMPTY_SUBJECT_TEXT'); - }, this)); + this.messageListChecked = MessageStore.messageListChecked; + this.messageListCheckedOrSelected = MessageStore.messageListCheckedOrSelected; + this.messageListCheckedOrSelectedUidsWithSubMails = MessageStore.messageListCheckedOrSelectedUidsWithSubMails; + this.messageListCompleteLoadingThrottle = MessageStore.messageListCompleteLoadingThrottle; + this.messageListCompleteLoadingThrottleForAnimation = MessageStore.messageListCompleteLoadingThrottleForAnimation; - this.userQuota = QuotaStore.quota; - this.userUsageSize = QuotaStore.usage; - this.userUsageProc = QuotaStore.percentage; + initOnStartOrLangChange(() => { + this.emptySubjectValue = i18n('MESSAGE_LIST/EMPTY_SUBJECT_TEXT'); + }); - this.moveDropdownTrigger = ko.observable(false); - this.moreDropdownTrigger = ko.observable(false); + this.userQuota = QuotaStore.quota; + this.userUsageSize = QuotaStore.usage; + this.userUsageProc = QuotaStore.percentage; - // 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.moveDropdownTrigger = ko.observable(false); + this.moreDropdownTrigger = ko.observable(false); - this.messageListItemTemplate = ko.computed(function() { - return this.mobile || Enums.Layout.SidePreview === SettingsStore.layout() ? - 'MailMessageListItem' : 'MailMessageListItemNoPreviewPane'; - }, this); + // 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.messageListSearchDesc = ko.computed(function() { - var sValue = MessageStore.messageListEndSearch(); - return '' === sValue ? '' : Translator.i18n('MESSAGE_LIST/SEARCH_RESULT_FOR', {'SEARCH': sValue}); - }); + this.messageListItemTemplate = ko.computed( + () => (this.mobile || Layout.SidePreview === SettingsStore.layout() ? + 'MailMessageListItem' : 'MailMessageListItemNoPreviewPane') + ); - this.messageListPagenator = ko.computed(Utils.computedPagenatorHelper( - MessageStore.messageListPage, MessageStore.messageListPageCount)); + this.messageListSearchDesc = ko.computed(() => { + const value = MessageStore.messageListEndSearch(); + return '' === value ? '' : i18n('MESSAGE_LIST/SEARCH_RESULT_FOR', {'SEARCH': value}); + }); - this.checkAll = ko.computed({ - 'read': function() { - return 0 < MessageStore.messageListChecked().length; - }, + this.messageListPagenator = ko.computed( + computedPagenatorHelper(MessageStore.messageListPage, MessageStore.messageListPageCount)); - 'write': function(bValue) { - bValue = !!bValue; - _.each(MessageStore.messageList(), function(oMessage) { - oMessage.checked(bValue); - }); - } - }); + this.checkAll = ko.computed({ + read: () => 0 < MessageStore.messageListChecked().length, + write: (value) => { + value = !!value; + _.each(MessageStore.messageList(), (message) => { + message.checked(value); + }); + } + }); - this.inputMessageListSearchFocus = ko.observable(false); + this.inputMessageListSearchFocus = ko.observable(false); - this.sLastSearchValue = ''; - this.inputProxyMessageListSearch = ko.computed({ - 'read': this.mainMessageListSearch, - 'write': function(sValue) { - this.sLastSearchValue = sValue; - }, - 'owner': this - }); + this.sLastSearchValue = ''; + this.inputProxyMessageListSearch = ko.computed({ + read: this.mainMessageListSearch, + write: (value) => { + this.sLastSearchValue = value; + } + }); - this.isIncompleteChecked = ko.computed(function() { - var - iM = MessageStore.messageList().length, - iC = MessageStore.messageListChecked().length; - return 0 < iM && 0 < iC && iM > iC; - }, this); + this.isIncompleteChecked = ko.computed(() => { + const + m = MessageStore.messageList().length, + c = MessageStore.messageListChecked().length; + return 0 < m && 0 < c && m > c; + }); - this.hasMessages = ko.computed(function() { - return 0 < this.messageList().length; - }, this); + this.hasMessages = ko.computed(() => 0 < this.messageList().length); - this.hasCheckedOrSelectedLines = ko.computed(function() { - return 0 < this.messageListCheckedOrSelected().length; - }, this); + this.hasCheckedOrSelectedLines = ko.computed(() => 0 < this.messageListCheckedOrSelected().length); - this.isSpamFolder = ko.computed(function() { - return FolderStore.spamFolder() === this.messageListEndFolder() && - '' !== FolderStore.spamFolder(); - }, this); + this.isSpamFolder = ko.computed( + () => FolderStore.spamFolder() === this.messageListEndFolder() && '' !== FolderStore.spamFolder() + ); - this.isSpamDisabled = ko.computed(function() { - return Consts.UNUSED_OPTION_VALUE === FolderStore.spamFolder(); - }, this); + this.isSpamDisabled = ko.computed(() => UNUSED_OPTION_VALUE === FolderStore.spamFolder()); - this.isTrashFolder = ko.computed(function() { - return FolderStore.trashFolder() === this.messageListEndFolder() && - '' !== FolderStore.trashFolder(); - }, this); + this.isTrashFolder = ko.computed( + () => FolderStore.trashFolder() === this.messageListEndFolder() && '' !== FolderStore.trashFolder() + ); - this.isDraftFolder = ko.computed(function() { - return FolderStore.draftFolder() === this.messageListEndFolder() && - '' !== FolderStore.draftFolder(); - }, this); + this.isDraftFolder = ko.computed( + () => FolderStore.draftFolder() === this.messageListEndFolder() && '' !== FolderStore.draftFolder() + ); - this.isSentFolder = ko.computed(function() { - return FolderStore.sentFolder() === this.messageListEndFolder() && - '' !== FolderStore.sentFolder(); - }, this); + this.isSentFolder = ko.computed( + () => FolderStore.sentFolder() === this.messageListEndFolder() && '' !== FolderStore.sentFolder() + ); - this.isArchiveFolder = ko.computed(function() { - return FolderStore.archiveFolder() === this.messageListEndFolder() && - '' !== FolderStore.archiveFolder(); - }, this); + this.isArchiveFolder = ko.computed( + () => FolderStore.archiveFolder() === this.messageListEndFolder() && '' !== FolderStore.archiveFolder() + ); - this.isArchiveDisabled = ko.computed(function() { - return Consts.UNUSED_OPTION_VALUE === FolderStore.archiveFolder(); - }, this); + this.isArchiveDisabled = ko.computed(() => UNUSED_OPTION_VALUE === FolderStore.archiveFolder()); - this.isArchiveVisible = ko.computed(function() { - return !this.isArchiveFolder() && !this.isArchiveDisabled() && !this.isDraftFolder(); - }, this); + this.isArchiveVisible = ko.computed( + () => !this.isArchiveFolder() && !this.isArchiveDisabled() && !this.isDraftFolder() + ); - this.isSpamVisible = ko.computed(function() { - return !this.isSpamFolder() && !this.isSpamDisabled() && !this.isDraftFolder() && !this.isSentFolder(); - }, this); + this.isSpamVisible = ko.computed( + () => !this.isSpamFolder() && !this.isSpamDisabled() && !this.isDraftFolder() && !this.isSentFolder() + ); - this.isUnSpamVisible = ko.computed(function() { - return this.isSpamFolder() && !this.isSpamDisabled() && !this.isDraftFolder() && !this.isSentFolder(); - }, this); + this.isUnSpamVisible = ko.computed( + () => this.isSpamFolder() && !this.isSpamDisabled() && !this.isDraftFolder() && !this.isSentFolder() + ); - this.mobileCheckedStateShow = ko.computed(function() { - var checked = 0 < this.messageListChecked().length; - return this.mobile ? checked : true; - }, this); + this.mobileCheckedStateShow = ko.computed(() => { + const checked = 0 < this.messageListChecked().length; + return this.mobile ? checked : true; + }); - this.mobileCheckedStateHide = ko.computed(function() { - var checked = 0 < this.messageListChecked().length; - return this.mobile ? !checked : true; - }, this); + this.mobileCheckedStateHide = ko.computed(() => { + const checked = 0 < this.messageListChecked().length; + return this.mobile ? !checked : true; + }); - this.messageListFocused = ko.computed(function() { - return Enums.Focused.MessageList === AppStore.focusedState(); - }); + this.messageListFocused = ko.computed(() => Focused.MessageList === AppStore.focusedState()); - this.canBeMoved = this.hasCheckedOrSelectedLines; + this.canBeMoved = this.hasCheckedOrSelectedLines; - this.clearCommand = Utils.createCommand(this, function() { - if (Settings.capa(Enums.Capa.DangerousActions)) - { - kn.showScreenPopup(require('View/Popup/FolderClear'), [FolderStore.currentFolder()]); - } - }); + this.clearCommand = createCommand(() => { + if (Settings.capa(Capa.DangerousActions)) + { + showScreenPopup(require('View/Popup/FolderClear'), [FolderStore.currentFolder()]); + } + }); - this.multyForwardCommand = Utils.createCommand(this, function() { - if (Settings.capa(Enums.Capa.Composer)) - { - kn.showScreenPopup(require('View/Popup/Compose'), [ - Enums.ComposeType.ForwardAsAttachment, MessageStore.messageListCheckedOrSelected()]); - } - }, this.canBeMoved); + this.multyForwardCommand = createCommand(() => { + if (Settings.capa(Capa.Composer)) + { + showScreenPopup(require('View/Popup/Compose'), [ + ComposeType.ForwardAsAttachment, MessageStore.messageListCheckedOrSelected()]); + } + }, this.canBeMoved); - this.deleteWithoutMoveCommand = Utils.createCommand(this, function() { - if (Settings.capa(Enums.Capa.DangerousActions)) - { - require('App/User').default.deleteMessagesFromFolder(Enums.FolderType.Trash, + this.deleteWithoutMoveCommand = createCommand(() => { + if (Settings.capa(Capa.DangerousActions)) + { + getApp().deleteMessagesFromFolder(FolderType.Trash, + FolderStore.currentFolderFullNameRaw(), + MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), false); + } + }, this.canBeMoved); + + this.deleteCommand = createCommand(() => { + getApp().deleteMessagesFromFolder(FolderType.Trash, FolderStore.currentFolderFullNameRaw(), - MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), false); - } - }, this.canBeMoved); + MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), true); + }, this.canBeMoved); - this.deleteCommand = Utils.createCommand(this, function() { - require('App/User').default.deleteMessagesFromFolder(Enums.FolderType.Trash, - FolderStore.currentFolderFullNameRaw(), - MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), true); - }, this.canBeMoved); + this.archiveCommand = createCommand(() => { + getApp().deleteMessagesFromFolder(FolderType.Archive, + FolderStore.currentFolderFullNameRaw(), + MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), true); + }, this.canBeMoved); - this.archiveCommand = Utils.createCommand(this, function() { - require('App/User').default.deleteMessagesFromFolder(Enums.FolderType.Archive, - FolderStore.currentFolderFullNameRaw(), - MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), true); - }, this.canBeMoved); + this.spamCommand = createCommand(() => { + getApp().deleteMessagesFromFolder(FolderType.Spam, + FolderStore.currentFolderFullNameRaw(), + MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), true); + }, this.canBeMoved); - this.spamCommand = Utils.createCommand(this, function() { - require('App/User').default.deleteMessagesFromFolder(Enums.FolderType.Spam, - FolderStore.currentFolderFullNameRaw(), - MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), true); - }, this.canBeMoved); + this.notSpamCommand = createCommand(() => { + getApp().deleteMessagesFromFolder(FolderType.NotSpam, + FolderStore.currentFolderFullNameRaw(), + MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), true); + }, this.canBeMoved); - this.notSpamCommand = Utils.createCommand(this, function() { - require('App/User').default.deleteMessagesFromFolder(Enums.FolderType.NotSpam, - FolderStore.currentFolderFullNameRaw(), - MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), true); - }, this.canBeMoved); + this.moveCommand = createCommand(noop, this.canBeMoved); - this.moveCommand = Utils.createCommand(this, Utils.noop, this.canBeMoved); - - this.reloadCommand = Utils.createCommand(this, function() { - if (!MessageStore.messageListCompleteLoadingThrottleForAnimation() && this.allowReload) - { - require('App/User').default.reloadMessageList(false, true); - } - }); - - this.quotaTooltip = _.bind(this.quotaTooltip, this); - - this.selector = new Selector.Selector(this.messageList, this.selectorMessageSelected, this.selectorMessageFocused, - '.messageListItem .actionHandle', '.messageListItem.selected', '.messageListItem .checkboxMessage', - '.messageListItem.focused'); - - this.selector.on('onItemSelect', _.bind(function(oMessage) { - MessageStore.selectMessage(oMessage); - }, this)); - - this.selector.on('onItemGetUid', function(oMessage) { - return oMessage ? oMessage.generateUid() : ''; - }); - - this.selector.on('onAutoSelect', _.bind(function() { - return this.useAutoSelect(); - }, this)); - - this.selector.on('onUpUpOrDownDown', _.bind(function(bV) { - this.goToUpUpOrDownDown(bV); - }, this)); - - Events.sub('mailbox.message-list.selector.go-down', function(bSelect) { - this.selector.goDown(bSelect); - }, this); - - Events.sub('mailbox.message-list.selector.go-up', function(bSelect) { - this.selector.goUp(bSelect); - }, this); - - Events.sub('mailbox.message.show', function(sFolder, sUid) { - - var oMessage = _.find(this.messageList(), function(oItem) { - return oItem && sFolder === oItem.folderFullNameRaw && sUid === oItem.uid; + this.reloadCommand = createCommand(() => { + if (!MessageStore.messageListCompleteLoadingThrottleForAnimation() && this.allowReload) + { + getApp().reloadMessageList(false, true); + } }); - if ('INBOX' === sFolder) - { - kn.setHash(Links.mailBox(sFolder, 1)); - } + this.quotaTooltip = _.bind(this.quotaTooltip, this); - if (oMessage) - { - this.selector.selectMessageItem(oMessage); - } - else - { - if ('INBOX' !== sFolder) + this.selector = new Selector( + this.messageList, this.selectorMessageSelected, this.selectorMessageFocused, + '.messageListItem .actionHandle', '.messageListItem.selected', + '.messageListItem .checkboxMessage', '.messageListItem.focused'); + + this.selector.on('onItemSelect', (message) => { + MessageStore.selectMessage(message); + }); + + this.selector.on('onItemGetUid', (message) => (message ? message.generateUid() : '')); + + this.selector.on('onAutoSelect', () => this.useAutoSelect()); + + this.selector.on('onUpUpOrDownDown', (v) => { + this.goToUpUpOrDownDown(v); + }); + + Events.sub('mailbox.message-list.selector.go-down', (select) => { + this.selector.goDown(select); + }); + + Events.sub('mailbox.message-list.selector.go-up', (select) => { + this.selector.goUp(select); + }); + + Events.sub('mailbox.message.show', (sFolder, sUid) => { + + const message = _.find(this.messageList(), (item) => item && sFolder === item.folderFullNameRaw && sUid === item.uid); + + if ('INBOX' === sFolder) { - kn.setHash(Links.mailBox(sFolder, 1)); + setHash(mailBox(sFolder, 1)); } - MessageStore.selectMessageByFolderAndUid(sFolder, sUid); - } - - }, this); - - MessageStore.messageListEndHash.subscribe(function() { - this.selector.scrollToTop(); - }, this); - - kn.constructorEnd(this); -} - -kn.extendAsViewModel(['View/User/MailBox/MessageList', 'View/App/MailBox/MessageList', 'MailBoxMessageListViewModel'], MessageListMailBoxUserView); -_.extend(MessageListMailBoxUserView.prototype, AbstractView.prototype); - -/** - * @type {string} - */ -MessageListMailBoxUserView.prototype.emptySubjectValue = ''; - -MessageListMailBoxUserView.prototype.iGoToUpUpOrDownDownTimeout = 0; - -MessageListMailBoxUserView.prototype.hideLeft = function(oItem, oEvent) -{ - oEvent.preventDefault(); - oEvent.stopPropagation(); - - Globals.leftPanelDisabled(true); -}; - -MessageListMailBoxUserView.prototype.showLeft = function(oItem, oEvent) -{ - oEvent.preventDefault(); - oEvent.stopPropagation(); - - Globals.leftPanelDisabled(false); -}; - -MessageListMailBoxUserView.prototype.composeClick = function() -{ - if (Settings.capa(Enums.Capa.Composer)) - { - kn.showScreenPopup(require('View/Popup/Compose')); - } -}; - -MessageListMailBoxUserView.prototype.goToUpUpOrDownDown = function(bUp) -{ - var self = this; - - if (0 < this.messageListChecked().length) - { - return false; - } - - window.clearTimeout(this.iGoToUpUpOrDownDownTimeout); - this.iGoToUpUpOrDownDownTimeout = window.setTimeout(function() { - - var - oPrev = null, - oNext = null, - oTemp = null, - oCurrent = null, - aPages = self.messageListPagenator(); - - _.find(aPages, function(oItem) { - - if (oItem) + if (message) { - if (oCurrent) + this.selector.selectMessageItem(message); + } + else + { + if ('INBOX' !== sFolder) { - oNext = oItem; + setHash(mailBox(sFolder, 1)); } - if (oItem.current) - { - oCurrent = oItem; - oPrev = oTemp; - } - - if (oNext) - { - return true; - } - - oTemp = oItem; + MessageStore.selectMessageByFolderAndUid(sFolder, sUid); } - return false; }); - if (Enums.Layout.NoPreview === SettingsStore.layout() && !self.message()) - { - self.selector.iFocusedNextHelper = bUp ? -1 : 1; - } - else - { - self.selector.iSelectNextHelper = bUp ? -1 : 1; - } - - if (bUp ? oPrev : oNext) - { - self.selector.unselect(); - self.gotoPage(bUp ? oPrev : oNext); - } - - }, Enums.Magics.Time350ms); - - return true; -}; - -MessageListMailBoxUserView.prototype.useAutoSelect = function() -{ - if (this.messageListDisableAutoSelect()) - { - return false; - } - - if (/is:unseen/.test(this.mainMessageListSearch())) - { - return false; - } - - return Enums.Layout.NoPreview !== SettingsStore.layout(); -}; - -MessageListMailBoxUserView.prototype.searchEnterAction = function() -{ - this.mainMessageListSearch(this.sLastSearchValue); - this.inputMessageListSearchFocus(false); -}; - -/** - * @returns {string} - */ -MessageListMailBoxUserView.prototype.printableMessageCountForDeletion = function() -{ - var iCnt = this.messageListCheckedOrSelectedUidsWithSubMails().length; - return 1 < iCnt ? ' (' + (100 > iCnt ? iCnt : '99+') + ')' : ''; // eslint-disable-line no-magic-numbers -}; - -MessageListMailBoxUserView.prototype.cancelSearch = function() -{ - this.mainMessageListSearch(''); - this.inputMessageListSearchFocus(false); -}; - -MessageListMailBoxUserView.prototype.cancelThreadUid = function() -{ - kn.setHash(Links.mailBox( - FolderStore.currentFolderFullNameHash(), - MessageStore.messageListPageBeforeThread(), - MessageStore.messageListSearch() - )); -}; - -/** - * @param {string} sToFolderFullNameRaw - * @param {boolean} bCopy - * @returns {boolean} - */ -MessageListMailBoxUserView.prototype.moveSelectedMessagesToFolder = function(sToFolderFullNameRaw, bCopy) -{ - if (this.canBeMoved()) - { - require('App/User').default.moveMessagesToFolder( - FolderStore.currentFolderFullNameRaw(), - MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), sToFolderFullNameRaw, bCopy); - } - - return false; -}; - -MessageListMailBoxUserView.prototype.dragAndDronHelper = function(oMessageListItem) -{ - if (oMessageListItem) - { - oMessageListItem.checked(true); - } - - var - oEl = Utils.draggablePlace(), - updateUidsInfo = function() { - var aUids = MessageStore.messageListCheckedOrSelectedUidsWithSubMails(); - oEl.data('rl-uids', aUids); - oEl.find('.text').text('' + aUids.length); - }; - - oEl.data('rl-folder', FolderStore.currentFolderFullNameRaw()); - - updateUidsInfo(); - _.defer(updateUidsInfo); - - return oEl; -}; - -/** - * @param {string} sFolderFullNameRaw - * @param {string|bool} mUid - * @param {number} iSetAction - * @param {Array=} aMessages = null - * @returns {void} - */ -MessageListMailBoxUserView.prototype.setAction = function(sFolderFullNameRaw, mUid, iSetAction, aMessages) -{ - require('App/User').default.messageListAction(sFolderFullNameRaw, mUid, iSetAction, aMessages); -}; - -/** - * @param {string} sFolderFullNameRaw - * @param {number} iSetAction - * @returns {void} - */ -MessageListMailBoxUserView.prototype.setActionForAll = function(sFolderFullNameRaw, iSetAction) -{ - if ('' !== sFolderFullNameRaw) - { - var oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw); - if (oFolder) - { - switch (iSetAction) - { - case Enums.MessageSetAction.SetSeen: - oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw); - if (oFolder) - { - _.each(MessageStore.messageList(), function(oMessage) { - oMessage.unseen(false); - }); - - oFolder.messageCountUnread(0); - Cache.clearMessageFlagsFromCacheByFolder(sFolderFullNameRaw); - } - - Remote.messageSetSeenToAll(Utils.noop, sFolderFullNameRaw, true); - break; - case Enums.MessageSetAction.UnsetSeen: - oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw); - if (oFolder) - { - _.each(MessageStore.messageList(), function(oMessage) { - oMessage.unseen(true); - }); - - oFolder.messageCountUnread(oFolder.messageCountAll()); - Cache.clearMessageFlagsFromCacheByFolder(sFolderFullNameRaw); - } - Remote.messageSetSeenToAll(Utils.noop, sFolderFullNameRaw, false); - break; - // no default - } - - require('App/User').default.reloadFlagsCurrentMessageListAndMessageFromCache(); - } - } -}; - -MessageListMailBoxUserView.prototype.listSetSeen = function() -{ - this.setAction(FolderStore.currentFolderFullNameRaw(), true, - Enums.MessageSetAction.SetSeen, MessageStore.messageListCheckedOrSelected()); -}; - -MessageListMailBoxUserView.prototype.listSetAllSeen = function() -{ - this.setActionForAll(FolderStore.currentFolderFullNameRaw(), Enums.MessageSetAction.SetSeen); -}; - -MessageListMailBoxUserView.prototype.listUnsetSeen = function() -{ - this.setAction(FolderStore.currentFolderFullNameRaw(), true, - Enums.MessageSetAction.UnsetSeen, MessageStore.messageListCheckedOrSelected()); -}; - -MessageListMailBoxUserView.prototype.listSetFlags = function() -{ - this.setAction(FolderStore.currentFolderFullNameRaw(), true, - Enums.MessageSetAction.SetFlag, MessageStore.messageListCheckedOrSelected()); -}; - -MessageListMailBoxUserView.prototype.listUnsetFlags = function() -{ - this.setAction(FolderStore.currentFolderFullNameRaw(), true, - Enums.MessageSetAction.UnsetFlag, MessageStore.messageListCheckedOrSelected()); -}; - -MessageListMailBoxUserView.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, true, oCurrentMessage.flagged() ? - Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, aChecked); - } - else - { - this.setAction(oCurrentMessage.folderFullNameRaw, true, oCurrentMessage.flagged() ? - Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, [oCurrentMessage]); - } - } -}; - -MessageListMailBoxUserView.prototype.flagMessagesFast = function(bFlag) -{ - var aChecked = this.messageListCheckedOrSelected(); - if (0 < aChecked.length) - { - if (Utils.isUnd(bFlag)) - { - var aFlagged = _.filter(aChecked, function(oMessage) { - return oMessage.flagged(); - }); - - this.setAction(aChecked[0].folderFullNameRaw, true, - aChecked.length === aFlagged.length ? Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, aChecked); - } - else - { - this.setAction(aChecked[0].folderFullNameRaw, true, - !bFlag ? Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, aChecked); - } - } -}; - -MessageListMailBoxUserView.prototype.seenMessagesFast = function(bSeen) -{ - var aChecked = this.messageListCheckedOrSelected(); - if (0 < aChecked.length) - { - if (Utils.isUnd(bSeen)) - { - var aUnseen = _.filter(aChecked, function(oMessage) { - return oMessage.unseen(); - }); - - this.setAction(aChecked[0].folderFullNameRaw, true, - 0 < aUnseen.length ? Enums.MessageSetAction.SetSeen : Enums.MessageSetAction.UnsetSeen, aChecked); - } - else - { - this.setAction(aChecked[0].folderFullNameRaw, true, - bSeen ? Enums.MessageSetAction.SetSeen : Enums.MessageSetAction.UnsetSeen, aChecked); - } - } -}; - -MessageListMailBoxUserView.prototype.gotoPage = function(oPage) -{ - if (oPage) - { - kn.setHash(Links.mailBox( - FolderStore.currentFolderFullNameHash(), - oPage.value, - MessageStore.messageListSearch(), - MessageStore.messageListThreadUid() - )); - } -}; - -MessageListMailBoxUserView.prototype.gotoThread = function(oMessage) -{ - if (oMessage && 0 < oMessage.threadsLen()) - { - MessageStore.messageListPageBeforeThread(MessageStore.messageListPage()); - - kn.setHash(Links.mailBox( - FolderStore.currentFolderFullNameHash(), - 1, - MessageStore.messageListSearch(), - oMessage.uid - )); - } -}; - -MessageListMailBoxUserView.prototype.clearListIsVisible = function() -{ - return '' === this.messageListSearchDesc() && '' === this.messageListError() && - '' === MessageStore.messageListEndThreadUid() && - 0 < this.messageList().length && (this.isSpamFolder() || this.isTrashFolder()); -}; - -MessageListMailBoxUserView.prototype.onBuild = function(oDom) -{ - var self = this; - - this.oContentVisible = $('.b-content', oDom); - this.oContentScrollable = $('.content', this.oContentVisible); - - this.selector.init(this.oContentVisible, this.oContentScrollable, Enums.KeyState.MessageList); - - if (this.mobile) - { - oDom - .on('click', function() { - Globals.leftPanelDisabled(true); - }); - } - - oDom - .on('click', '.messageList .b-message-list-wrapper', function() { - if (Enums.Focused.MessageView === AppStore.focusedState()) - { - AppStore.focusedState(Enums.Focused.MessageList); - } - }) - .on('click', '.e-pagenator .e-page', function() { - self.gotoPage(ko.dataFor(this)); - }) - .on('click', '.messageList .checkboxCkeckAll', function() { - self.checkAll(!self.checkAll()); - }) - .on('click', '.messageList .messageListItem .flagParent', function() { - self.flagMessages(ko.dataFor(this)); - }) - .on('click', '.messageList .messageListItem .threads-len', function() { - self.gotoThread(ko.dataFor(this)); - }) - .on('dblclick', '.messageList .messageListItem .actionHandle', function() { - self.gotoThread(ko.dataFor(this)); - }); - - this.initUploaderForAppend(); - this.initShortcuts(); - - if (!Globals.bMobileDevice && ifvisible && Settings.capa(Enums.Capa.Prefetch)) - { - ifvisible.setIdleDuration(Enums.Magics.ifvisibleIdle10s); - - ifvisible.idle(function() { - self.prefetchNextTick(); + MessageStore.messageListEndHash.subscribe(() => { + this.selector.scrollToTop(); }); } -}; -MessageListMailBoxUserView.prototype.initShortcuts = function() -{ - var self = this; + hideLeft(oItem, oEvent) { + oEvent.preventDefault(); + oEvent.stopPropagation(); - key('enter', Enums.KeyState.MessageList, function() { - if (self.message() && self.useAutoSelect()) + leftPanelDisabled(true); + } + + showLeft(oItem, oEvent) { + oEvent.preventDefault(); + oEvent.stopPropagation(); + + leftPanelDisabled(false); + } + + composeClick() { + if (Settings.capa(Capa.Composer)) + { + showScreenPopup(require('View/Popup/Compose')); + } + } + + goToUpUpOrDownDown(up) { + + if (0 < this.messageListChecked().length) { - Events.pub('mailbox.message-view.toggle-full-screen'); return false; } + window.clearTimeout(this.iGoToUpUpOrDownDownTimeout); + this.iGoToUpUpOrDownDownTimeout = window.setTimeout(() => { + + let + prev = null, + next = null, + temp = null, + current = null; + + _.find(this.messageListPagenator(), (item) => { + + if (item) + { + if (current) + { + next = item; + } + + if (item.current) + { + current = item; + prev = temp; + } + + if (next) + { + return true; + } + + temp = item; + } + + return false; + }); + + if (Layout.NoPreview === SettingsStore.layout() && !this.message()) + { + this.selector.iFocusedNextHelper = up ? -1 : 1; + } + else + { + this.selector.iSelectNextHelper = up ? -1 : 1; + } + + if (up ? prev : next) + { + this.selector.unselect(); + this.gotoPage(up ? prev : next); + } + + }, Magics.Time350ms); + return true; - }); + } - if (Settings.capa(Enums.Capa.MessageListActions)) - { - // archive (zip) - key('z', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function() { - self.archiveCommand(); + useAutoSelect() { + if (this.messageListDisableAutoSelect()) + { return false; - }); + } - // delete - key('delete, shift+delete, shift+3', Enums.KeyState.MessageList, function(event, handler) { - if (event) + if (/is:unseen/.test(this.mainMessageListSearch())) + { + return false; + } + + return Layout.NoPreview !== SettingsStore.layout(); + } + + searchEnterAction() { + this.mainMessageListSearch(this.sLastSearchValue); + this.inputMessageListSearchFocus(false); + } + + /** + * @returns {string} + */ + printableMessageCountForDeletion() { + const cnt = this.messageListCheckedOrSelectedUidsWithSubMails().length; + return 1 < cnt ? ' (' + (100 > cnt ? cnt : '99+') + ')' : ''; // eslint-disable-line no-magic-numbers + } + + cancelSearch() { + this.mainMessageListSearch(''); + this.inputMessageListSearchFocus(false); + } + + cancelThreadUid() { + setHash(mailBox( + FolderStore.currentFolderFullNameHash(), + MessageStore.messageListPageBeforeThread(), + MessageStore.messageListSearch() + )); + } + + /** + * @param {string} sToFolderFullNameRaw + * @param {boolean} bCopy + * @returns {boolean} + */ + moveSelectedMessagesToFolder(sToFolderFullNameRaw, bCopy) { + if (this.canBeMoved()) + { + getApp().moveMessagesToFolder( + FolderStore.currentFolderFullNameRaw(), + MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), sToFolderFullNameRaw, bCopy); + } + + return false; + } + + dragAndDronHelper(oMessageListItem) { + if (oMessageListItem) + { + oMessageListItem.checked(true); + } + + const + el = draggablePlace(), + updateUidsInfo = () => { + const uids = MessageStore.messageListCheckedOrSelectedUidsWithSubMails(); + el.data('rl-uids', uids); + el.find('.text').text('' + uids.length); + }; + + el.data('rl-folder', FolderStore.currentFolderFullNameRaw()); + + updateUidsInfo(); + _.defer(updateUidsInfo); + + return el; + } + + /** + * @param {string} sFolderFullNameRaw + * @param {string|bool} mUid + * @param {number} iSetAction + * @param {Array=} aMessages = null + * @returns {void} + */ + setAction(sFolderFullNameRaw, mUid, iSetAction, aMessages) { + getApp().messageListAction(sFolderFullNameRaw, mUid, iSetAction, aMessages); + } + + /** + * @param {string} sFolderFullNameRaw + * @param {number} iSetAction + * @returns {void} + */ + setActionForAll(sFolderFullNameRaw, iSetAction) { + if ('' !== sFolderFullNameRaw) + { + let folder = getFolderFromCacheList(sFolderFullNameRaw); + if (folder) { - if (0 < MessageStore.messageListCheckedOrSelected().length) + switch (iSetAction) { - if (handler && 'shift+delete' === handler.shortcut) - { - self.deleteWithoutMoveCommand(); - } - else - { - self.deleteCommand(); - } + case MessageSetAction.SetSeen: + folder = getFolderFromCacheList(sFolderFullNameRaw); + if (folder) + { + _.each(MessageStore.messageList(), (message) => { + message.unseen(false); + }); + + folder.messageCountUnread(0); + clearMessageFlagsFromCacheByFolder(sFolderFullNameRaw); + } + + Remote.messageSetSeenToAll(noop, sFolderFullNameRaw, true); + break; + case MessageSetAction.UnsetSeen: + folder = getFolderFromCacheList(sFolderFullNameRaw); + if (folder) + { + _.each(MessageStore.messageList(), (message) => { + message.unseen(true); + }); + + folder.messageCountUnread(folder.messageCountAll()); + clearMessageFlagsFromCacheByFolder(sFolderFullNameRaw); + } + Remote.messageSetSeenToAll(noop, sFolderFullNameRaw, false); + break; + // no default } + getApp().reloadFlagsCurrentMessageListAndMessageFromCache(); + } + } + } + + listSetSeen() { + this.setAction(FolderStore.currentFolderFullNameRaw(), true, + MessageSetAction.SetSeen, MessageStore.messageListCheckedOrSelected()); + } + + listSetAllSeen() { + this.setActionForAll(FolderStore.currentFolderFullNameRaw(), MessageSetAction.SetSeen); + } + + listUnsetSeen() { + this.setAction(FolderStore.currentFolderFullNameRaw(), true, + MessageSetAction.UnsetSeen, MessageStore.messageListCheckedOrSelected()); + } + + listSetFlags() { + this.setAction(FolderStore.currentFolderFullNameRaw(), true, + MessageSetAction.SetFlag, MessageStore.messageListCheckedOrSelected()); + } + + listUnsetFlags() { + this.setAction(FolderStore.currentFolderFullNameRaw(), true, + MessageSetAction.UnsetFlag, MessageStore.messageListCheckedOrSelected()); + } + + flagMessages(currentMessage) { + const checked = this.messageListCheckedOrSelected(); + if (currentMessage) + { + const checkedUids = _.map(checked, (message) => message.uid); + if (0 < checkedUids.length && -1 < inArray(currentMessage.uid, checkedUids)) + { + this.setAction(currentMessage.folderFullNameRaw, true, currentMessage.flagged() ? + MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, checked); + } + else + { + this.setAction(currentMessage.folderFullNameRaw, true, currentMessage.flagged() ? + MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, [currentMessage]); + } + } + } + + flagMessagesFast(bFlag) { + const checked = this.messageListCheckedOrSelected(); + if (0 < checked.length) + { + if (isUnd(bFlag)) + { + const flagged = _.filter(checked, (message) => message.flagged()); + this.setAction(checked[0].folderFullNameRaw, true, + checked.length === flagged.length ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, checked); + } + else + { + this.setAction(checked[0].folderFullNameRaw, true, + !bFlag ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, checked); + } + } + } + + seenMessagesFast(seen) { + const checked = this.messageListCheckedOrSelected(); + if (0 < checked.length) + { + if (isUnd(seen)) + { + const unseen = _.filter(checked, (message) => message.unseen()); + this.setAction(checked[0].folderFullNameRaw, true, + 0 < unseen.length ? MessageSetAction.SetSeen : MessageSetAction.UnsetSeen, checked); + } + else + { + this.setAction(checked[0].folderFullNameRaw, true, + seen ? MessageSetAction.SetSeen : MessageSetAction.UnsetSeen, checked); + } + } + } + + gotoPage(page) { + if (page) + { + setHash(mailBox( + FolderStore.currentFolderFullNameHash(), + page.value, + MessageStore.messageListSearch(), + MessageStore.messageListThreadUid() + )); + } + } + + gotoThread(message) { + if (message && 0 < message.threadsLen()) + { + MessageStore.messageListPageBeforeThread(MessageStore.messageListPage()); + + setHash(mailBox( + FolderStore.currentFolderFullNameHash(), + 1, + MessageStore.messageListSearch(), + message.uid + )); + } + } + + clearListIsVisible() { + return '' === this.messageListSearchDesc() && '' === this.messageListError() && + '' === MessageStore.messageListEndThreadUid() && + 0 < this.messageList().length && (this.isSpamFolder() || this.isTrashFolder()); + } + + onBuild(dom) { + + const self = this; + + this.oContentVisible = $('.b-content', dom); + this.oContentScrollable = $('.content', this.oContentVisible); + + this.selector.init(this.oContentVisible, this.oContentScrollable, KeyState.MessageList); + + if (this.mobile) + { + dom + .on('click', () => { + leftPanelDisabled(true); + }); + } + + dom + .on('click', '.messageList .b-message-list-wrapper', () => { + if (Focused.MessageView === AppStore.focusedState()) + { + AppStore.focusedState(Focused.MessageList); + } + }) + .on('click', '.e-pagenator .e-page', function() { // eslint-disable-line prefer-arrow-callback + self.gotoPage(ko.dataFor(this)); // eslint-disable-line no-invalid-this + }) + .on('click', '.messageList .checkboxCkeckAll', () => { + this.checkAll(!this.checkAll()); + }) + .on('click', '.messageList .messageListItem .flagParent', function() { // eslint-disable-line prefer-arrow-callback + self.flagMessages(ko.dataFor(this)); // eslint-disable-line no-invalid-this + }) + .on('click', '.messageList .messageListItem .threads-len', function() { // eslint-disable-line prefer-arrow-callback + self.gotoThread(ko.dataFor(this)); // eslint-disable-line no-invalid-this + }) + .on('dblclick', '.messageList .messageListItem .actionHandle', function() { // eslint-disable-line prefer-arrow-callback + self.gotoThread(ko.dataFor(this)); // eslint-disable-line no-invalid-this + }); + + this.initUploaderForAppend(); + this.initShortcuts(); + + if (!bMobileDevice && ifvisible && Settings.capa(Capa.Prefetch)) + { + ifvisible.setIdleDuration(Magics.ifvisibleIdle10s); + + ifvisible.idle(() => { + this.prefetchNextTick(); + }); + } + } + + initShortcuts() { + + key('enter', KeyState.MessageList, () => { + if (this.message() && this.useAutoSelect()) + { + Events.pub('mailbox.message-view.toggle-full-screen'); return false; } return true; }); - } - if (Settings.capa(Enums.Capa.Reload)) - { - // 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; - }); - - if (Settings.capa(Enums.Capa.Composer)) - { - // write/compose (open compose popup) - key('w,c', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function() { - kn.showScreenPopup(require('View/Popup/Compose')); - return false; - }); - } - - if (Settings.capa(Enums.Capa.MessageListActions)) - { - // important - star/flag messages - key('i', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function() { - self.flagMessagesFast(); - return false; - }); - } - - key('t', [Enums.KeyState.MessageList], function() { - - var oMessage = self.selectorMessageSelected(); - if (!oMessage) + if (Settings.capa(Capa.MessageListActions)) { - oMessage = self.selectorMessageFocused(); - } - - if (oMessage && 0 < oMessage.threadsLen()) - { - self.gotoThread(oMessage); - } - - return false; - }); - - if (Settings.capa(Enums.Capa.MessageListActions)) - { - // move - key('m', Enums.KeyState.MessageList, function() { - self.moveDropdownTrigger(true); - return false; - }); - } - - if (Settings.capa(Enums.Capa.MessageListActions)) - { - // 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; - }); - } - - if (Settings.capa(Enums.Capa.Composer)) - { - key('shift+f', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function() { - self.multyForwardCommand(); - return false; - }); - } - - if (Settings.capa(Enums.Capa.Search)) - { - // 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; - } - else if ('' !== self.messageListEndThreadUid()) - { - self.cancelThreadUid(); - return false; - } - - return true; - }); - - // 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)) - { - AppStore.focusedState(Enums.Focused.FolderList); - } - else if (self.message()) - { - AppStore.focusedState(Enums.Focused.MessageView); - } - - return false; - }); - - key('ctrl+left, command+left', Enums.KeyState.MessageView, function() { - return false; - }); - - key('ctrl+right, command+right', Enums.KeyState.MessageView, function() { - return false; - }); -}; - -MessageListMailBoxUserView.prototype.prefetchNextTick = function() -{ - if (ifvisible && !this.bPrefetch && !ifvisible.now() && this.viewModelVisibility()) - { - var - self = this, - oMessage = _.find(this.messageList(), function(oItem) { - return oItem && !Cache.hasRequestedMessage(oItem.folderFullNameRaw, oItem.uid); + // archive (zip) + key('z', [KeyState.MessageList, KeyState.MessageView], () => { + this.archiveCommand(); + return false; }); - 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) + // delete + key('delete, shift+delete, shift+3', KeyState.MessageList, (event, handler) => { + if (event) + { + if (0 < MessageStore.messageListCheckedOrSelected().length) { - self.prefetchNextTick(); + if (handler && 'shift+delete' === handler.shortcut) + { + this.deleteWithoutMoveCommand(); + } + else + { + this.deleteCommand(); + } } - }, Enums.Magics.Time1s); - }, oMessage.folderFullNameRaw, oMessage.uid); - } - } -}; - -MessageListMailBoxUserView.prototype.composeClick = function() -{ - if (Settings.capa(Enums.Capa.Composer)) - { - kn.showScreenPopup(require('View/Popup/Compose')); - } -}; - -MessageListMailBoxUserView.prototype.advancedSearchClick = function() -{ - if (Settings.capa(Enums.Capa.SearchAdv)) - { - kn.showScreenPopup(require('View/Popup/AdvancedSearch'), [this.mainMessageListSearch()]); - } -}; - -MessageListMailBoxUserView.prototype.quotaTooltip = function() -{ - return Translator.i18n('MESSAGE_LIST/QUOTA_SIZE', { - 'SIZE': Utils.friendlySize(this.userUsageSize()), - 'PROC': this.userUsageProc(), - 'LIMIT': Utils.friendlySize(this.userQuota()) - }); -}; - -MessageListMailBoxUserView.prototype.initUploaderForAppend = function() -{ - if (!Settings.appSettingsGet('allowAppendMessage') || !this.dragOverArea()) - { - return false; - } - - var - oJua = new Jua({ - action: Links.append(), - name: 'AppendFile', - queueSize: 1, - multipleSizeLimit: 1, - hidden: { - Folder: function() { - return FolderStore.currentFolderFullNameRaw(); + return false; } - }, - dragAndDropElement: this.dragOverArea(), - dragAndDropBodyElement: this.dragOverBodyArea() + + return true; + }); + } + + if (Settings.capa(Capa.Reload)) + { + // check mail + key('ctrl+r, command+r', [KeyState.FolderList, KeyState.MessageList, KeyState.MessageView], () => { + this.reloadCommand(); + return false; + }); + } + + // check all + key('ctrl+a, command+a', KeyState.MessageList, () => { + this.checkAll(!(this.checkAll() && !this.isIncompleteChecked())); + return false; }); - this.dragOver.subscribe(function(bValue) { - if (bValue) + if (Settings.capa(Capa.Composer)) { - this.selector.scrollToTop(); + // write/compose (open compose popup) + key('w,c', [KeyState.MessageList, KeyState.MessageView], () => { + showScreenPopup(require('View/Popup/Compose')); + return false; + }); } - }, this); - 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 (Settings.capa(Capa.MessageListActions)) + { + // important - star/flag messages + key('i', [KeyState.MessageList, KeyState.MessageView], () => { + this.flagMessagesFast(); + return false; + }); + } - if (sUid && oData && 'message/rfc822' === oData.Type) + key('t', [KeyState.MessageList], () => { + + let message = this.selectorMessageSelected(); + if (!message) { - MessageStore.messageListLoading(true); - return true; + message = this.selectorMessageFocused(); + } + + if (message && 0 < message.threadsLen()) + { + this.gotoThread(message); } return false; + }); - }, this)) - .on('onComplete', _.bind(function() { - require('App/User').default.reloadMessageList(true, true); - }, this)); + if (Settings.capa(Capa.MessageListActions)) + { + // move + key('m', KeyState.MessageList, () => { + this.moveDropdownTrigger(true); + return false; + }); + } - return !!oJua; -}; + if (Settings.capa(Capa.MessageListActions)) + { + // read + key('q', [KeyState.MessageList, KeyState.MessageView], () => { + this.seenMessagesFast(true); + return false; + }); -module.exports = MessageListMailBoxUserView; + // unread + key('u', [KeyState.MessageList, KeyState.MessageView], () => { + this.seenMessagesFast(false); + return false; + }); + } + + if (Settings.capa(Capa.Composer)) + { + key('shift+f', [KeyState.MessageList, KeyState.MessageView], () => { + this.multyForwardCommand(); + return false; + }); + } + + if (Settings.capa(Capa.Search)) + { + // search input focus + key('/', [KeyState.MessageList, KeyState.MessageView], () => { + this.inputMessageListSearchFocus(true); + return false; + }); + } + + // cancel search + key('esc', KeyState.MessageList, () => { + if ('' !== this.messageListSearchDesc()) + { + this.cancelSearch(); + return false; + } + else if ('' !== this.messageListEndThreadUid()) + { + this.cancelThreadUid(); + return false; + } + + return true; + }); + + // change focused state + key('tab, shift+tab, left, right', KeyState.MessageList, (event, handler) => { + if (event && handler && ('shift+tab' === handler.shortcut || 'left' === handler.shortcut)) + { + AppStore.focusedState(Focused.FolderList); + } + else if (this.message()) + { + AppStore.focusedState(Focused.MessageView); + } + + return false; + }); + + key('ctrl+left, command+left', KeyState.MessageView, noopFalse); + key('ctrl+right, command+right', KeyState.MessageView, noopFalse); + } + + prefetchNextTick() { + if (ifvisible && !this.bPrefetch && !ifvisible.now() && this.viewModelVisibility()) + { + const message = _.find(this.messageList(), (item) => item && !hasRequestedMessage(item.folderFullNameRaw, item.uid)); + if (message) + { + this.bPrefetch = true; + + addRequestedMessage(message.folderFullNameRaw, message.uid); + + Remote.message((result, data) => { + const next = !!(StorageResultType.Success === result && data && data.Result); + _.delay(() => { + this.bPrefetch = false; + if (next) + { + this.prefetchNextTick(); + } + }, Magics.Time1s); + + }, message.folderFullNameRaw, message.uid); + } + } + } + + advancedSearchClick() { + if (Settings.capa(Capa.SearchAdv)) + { + showScreenPopup(require('View/Popup/AdvancedSearch'), [this.mainMessageListSearch()]); + } + } + + quotaTooltip() { + return i18n('MESSAGE_LIST/QUOTA_SIZE', { + 'SIZE': friendlySize(this.userUsageSize()), + 'PROC': this.userUsageProc(), + 'LIMIT': friendlySize(this.userQuota()) + }); + } + + initUploaderForAppend() { + if (!Settings.appSettingsGet('allowAppendMessage') || !this.dragOverArea()) + { + return false; + } + + const + oJua = new Jua({ + action: append(), + name: 'AppendFile', + queueSize: 1, + multipleSizeLimit: 1, + hidden: { + Folder: () => FolderStore.currentFolderFullNameRaw() + }, + dragAndDropElement: this.dragOverArea(), + dragAndDropBodyElement: this.dragOverBodyArea() + }); + + this.dragOver.subscribe((value) => { + if (value) + { + this.selector.scrollToTop(); + } + }); + + oJua + .on('onDragEnter', () => { + this.dragOverEnter(true); + }) + .on('onDragLeave', () => { + this.dragOverEnter(false); + }) + .on('onBodyDragEnter', () => { + this.dragOver(true); + }) + .on('onBodyDragLeave', () => { + this.dragOver(false); + }) + .on('onSelect', (sUid, oData) => { + + if (sUid && oData && 'message/rfc822' === oData.Type) + { + MessageStore.messageListLoading(true); + return true; + } + + return false; + + }) + .on('onComplete', () => { + getApp().reloadMessageList(true, true); + }); + + return !!oJua; + } +} + +export {MessageListMailBoxUserView, MessageListMailBoxUserView as default}; diff --git a/dev/View/User/MailBox/MessageView.js b/dev/View/User/MailBox/MessageView.js index 1935c25d7..b9be7531e 100644 --- a/dev/View/User/MailBox/MessageView.js +++ b/dev/View/User/MailBox/MessageView.js @@ -1,1221 +1,1160 @@ -var - window = require('window'), - _ = require('_'), - $ = require('$'), - ko = require('ko'), - key = require('key'), +import window from 'window'; +import _ from '_'; +import $ from '$'; +import ko from 'ko'; +import key from 'key'; - Consts = require('Common/Consts'), - Enums = require('Common/Enums'), - Globals = require('Common/Globals'), - Utils = require('Common/Utils'), - Events = require('Common/Events'), - Translator = require('Common/Translator'), - Audio = require('Common/Audio'), - Links = require('Common/Links'), +import {DATA_IMAGE_USER_DOT_PIC, UNUSED_OPTION_VALUE} from 'Common/Consts'; - Cache = require('Common/Cache'), +import { + Capa, ComposeType, ClientSideKeyName, KeyState, + FolderType, Focused, Layout, Magics, MessageSetAction +} from 'Common/Enums'; - SocialStore = require('Stores/Social'), - AppStore = require('Stores/User/App'), - SettingsStore = require('Stores/User/Settings'), - AccountStore = require('Stores/User/Account'), - FolderStore = require('Stores/User/Folder'), - MessageStore = require('Stores/User/Message'), +import { + $html, + leftPanelDisabled, + keyScopeReal, + useKeyboardShortcuts +} from 'Common/Globals'; - Local = require('Storage/Client'), - Settings = require('Storage/Settings'), - Remote = require('Remote/User/Ajax'), +import { + createCommand, inArray, trim, noop, + isNonEmptyArray, windowResize, windowResizeCallback, + removeSelection, removeInFocus, mailToHelper, + inFocus, isArray +} from 'Common/Utils'; - Promises = require('Promises/User/Ajax'), +import Audio from 'Common/Audio'; +import * as Events from 'Common/Events'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {i18n} from 'Common/Translator'; +import {attachmentDownload} from 'Common/Links'; -/** - * @constructor - * @extends AbstractView - */ -function MessageViewMailBoxUserView() +import { + getUserPic, + storeMessageFlagsToCache +} from 'Common/Cache'; + +import SocialStore from 'Stores/Social'; +import AppStore from 'Stores/User/App'; +import SettingsStore from 'Stores/User/Settings'; +import AccountStore from 'Stores/User/Account'; +import FolderStore from 'Stores/User/Folder'; +import MessageStore from 'Stores/User/Message'; + +import * as Local from 'Storage/Client'; +import * as Settings from 'Storage/Settings'; + +import Remote from 'Remote/User/Ajax'; +import Promises from 'Promises/User/Ajax'; + +import {getApp} from 'Helper/Apps/User'; + +import {view, ViewType, showScreenPopup} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; + +@view({ + name: 'View/User/MailBox/MessageView', + type: ViewType.Right, + templateID: 'MailMessageView' +}) +class MessageViewMailBoxUserView extends AbstractViewNext { - AbstractView.call(this, 'Right', 'MailMessageView'); + constructor() { + super(); - var - self = this, - sLastEmail = '', - createCommandHelper = function(sType) { - return Utils.createCommand(self, function() { - this.lastReplyAction(sType); - this.replyOrforward(sType); - }, self.canBeRepliedOrForwarded); - }; + let lastEmail = ''; + const createCommandHelper = (type) => createCommand(() => { + this.lastReplyAction(type); + this.replyOrforward(type); + }, this.canBeRepliedOrForwarded); - this.oDom = null; - this.oHeaderDom = null; - this.oMessageScrollerDom = null; + this.oDom = null; + this.oHeaderDom = null; + this.oMessageScrollerDom = null; - this.bodyBackgroundColor = ko.observable(''); + this.bodyBackgroundColor = ko.observable(''); - this.pswp = null; + this.pswp = null; - this.allowComposer = !!Settings.capa(Enums.Capa.Composer); - this.allowMessageActions = !!Settings.capa(Enums.Capa.MessageActions); - this.allowMessageListActions = !!Settings.capa(Enums.Capa.MessageListActions); + this.allowComposer = !!Settings.capa(Capa.Composer); + this.allowMessageActions = !!Settings.capa(Capa.MessageActions); + this.allowMessageListActions = !!Settings.capa(Capa.MessageListActions); - this.logoImg = Utils.trim(Settings.settingsGet('UserLogoMessage')); - this.logoIframe = Utils.trim(Settings.settingsGet('UserIframeMessage')); + this.logoImg = trim(Settings.settingsGet('UserLogoMessage')); + this.logoIframe = trim(Settings.settingsGet('UserIframeMessage')); - this.mobile = !!Settings.appSettingsGet('mobile'); + this.mobile = !!Settings.appSettingsGet('mobile'); - this.attachmentsActions = AppStore.attachmentsActions; + this.attachmentsActions = AppStore.attachmentsActions; - this.message = MessageStore.message; - this.messageListChecked = MessageStore.messageListChecked; - this.hasCheckedMessages = MessageStore.hasCheckedMessages; - this.messageListCheckedOrSelectedUidsWithSubMails = MessageStore.messageListCheckedOrSelectedUidsWithSubMails; - this.messageLoadingThrottle = MessageStore.messageLoadingThrottle; - this.messagesBodiesDom = MessageStore.messagesBodiesDom; - this.useThreads = SettingsStore.useThreads; - this.replySameFolder = SettingsStore.replySameFolder; - this.layout = SettingsStore.layout; - this.usePreviewPane = SettingsStore.usePreviewPane; - this.isMessageSelected = MessageStore.isMessageSelected; - this.messageActiveDom = MessageStore.messageActiveDom; - this.messageError = MessageStore.messageError; + this.message = MessageStore.message; + this.messageListChecked = MessageStore.messageListChecked; + this.hasCheckedMessages = MessageStore.hasCheckedMessages; + this.messageListCheckedOrSelectedUidsWithSubMails = MessageStore.messageListCheckedOrSelectedUidsWithSubMails; + this.messageLoadingThrottle = MessageStore.messageLoadingThrottle; + this.messagesBodiesDom = MessageStore.messagesBodiesDom; + this.useThreads = SettingsStore.useThreads; + this.replySameFolder = SettingsStore.replySameFolder; + this.layout = SettingsStore.layout; + this.usePreviewPane = SettingsStore.usePreviewPane; + this.isMessageSelected = MessageStore.isMessageSelected; + this.messageActiveDom = MessageStore.messageActiveDom; + this.messageError = MessageStore.messageError; - this.fullScreenMode = MessageStore.messageFullScreenMode; + this.fullScreenMode = MessageStore.messageFullScreenMode; - this.messageListOfThreadsLoading = ko.observable(false).extend({'rateLimit': 1}); + this.messageListOfThreadsLoading = ko.observable(false).extend({rateLimit: 1}); + this.highlightUnselectedAttachments = ko.observable(false).extend({falseTimeout: 2000}); - this.highlightUnselectedAttachments = ko.observable(false).extend({'falseTimeout': 2000}); + this.showAttachmnetControls = ko.observable(false); - this.showAttachmnetControls = ko.observable(false); + this.allowAttachmnetControls = ko.computed( + () => 0 < this.attachmentsActions().length && Settings.capa(Capa.AttachmentsActions) + ); - this.allowAttachmnetControls = ko.computed(function() { - return 0 < this.attachmentsActions().length && - Settings.capa(Enums.Capa.AttachmentsActions); - }, this); + this.downloadAsZipAllowed = ko.computed( + () => -1 < inArray('zip', this.attachmentsActions()) && this.allowAttachmnetControls() + ); - this.downloadAsZipAllowed = ko.computed(function() { - return -1 < Utils.inArray('zip', this.attachmentsActions()) && - this.allowAttachmnetControls(); - }, this); + this.downloadAsZipLoading = ko.observable(false); + this.downloadAsZipError = ko.observable(false).extend({falseTimeout: 7000}); - this.downloadAsZipLoading = ko.observable(false); - this.downloadAsZipError = ko.observable(false).extend({'falseTimeout': 7000}); + this.saveToOwnCloudAllowed = ko.computed( + () => -1 < inArray('owncloud', this.attachmentsActions()) && this.allowAttachmnetControls() + ); - this.saveToOwnCloudAllowed = ko.computed(function() { - return -1 < Utils.inArray('owncloud', this.attachmentsActions()) && - this.allowAttachmnetControls(); - }, this); + this.saveToOwnCloudLoading = ko.observable(false); + this.saveToOwnCloudSuccess = ko.observable(false).extend({falseTimeout: 2000}); + this.saveToOwnCloudError = ko.observable(false).extend({falseTimeout: 7000}); - this.saveToOwnCloudLoading = ko.observable(false); - this.saveToOwnCloudSuccess = ko.observable(false).extend({'falseTimeout': 2000}); - this.saveToOwnCloudError = ko.observable(false).extend({'falseTimeout': 7000}); + this.saveToOwnCloudSuccess.subscribe((v) => { + if (v) + { + this.saveToOwnCloudError(false); + } + }); - this.saveToOwnCloudSuccess.subscribe(function(bV) { - if (bV) - { - this.saveToOwnCloudError(false); - } - }, this); + this.saveToOwnCloudError.subscribe((v) => { + if (v) + { + this.saveToOwnCloudSuccess(false); + } + }); - this.saveToOwnCloudError.subscribe(function(bV) { - if (bV) - { - this.saveToOwnCloudSuccess(false); - } - }, this); + this.saveToDropboxAllowed = ko.computed( + () => -1 < inArray('dropbox', this.attachmentsActions()) && this.allowAttachmnetControls() + ); - this.saveToDropboxAllowed = ko.computed(function() { - return -1 < Utils.inArray('dropbox', this.attachmentsActions()) && - this.allowAttachmnetControls(); - }, this); + this.saveToDropboxLoading = ko.observable(false); + this.saveToDropboxSuccess = ko.observable(false).extend({falseTimeout: 2000}); + this.saveToDropboxError = ko.observable(false).extend({falseTimeout: 7000}); - this.saveToDropboxLoading = ko.observable(false); - this.saveToDropboxSuccess = ko.observable(false).extend({'falseTimeout': 2000}); - this.saveToDropboxError = ko.observable(false).extend({'falseTimeout': 7000}); + this.saveToDropboxSuccess.subscribe((v) => { + if (v) + { + this.saveToDropboxError(false); + } + }); - this.saveToDropboxSuccess.subscribe(function(bV) { - if (bV) - { - this.saveToDropboxError(false); - } - }, this); + this.saveToDropboxError.subscribe((v) => { + if (v) + { + this.saveToDropboxSuccess(false); + } + }); - this.saveToDropboxError.subscribe(function(bV) { - if (bV) - { - this.saveToDropboxSuccess(false); - } - }, this); + this.showAttachmnetControls.subscribe((v) => { + if (this.message()) + { + _.each(this.message().attachments(), (item) => { + if (item) + { + item.checked(!!v); + } + }); + } + }); - this.showAttachmnetControls.subscribe(function(bV) { - if (this.message()) - { - _.each(this.message().attachments(), function(oItem) { - if (oItem) + this.lastReplyAction_ = ko.observable(''); + this.lastReplyAction = ko.computed({ + read: this.lastReplyAction_, + write: (value) => { + this.lastReplyAction_(-1 === inArray(value, [ + ComposeType.Reply, ComposeType.ReplyAll, ComposeType.Forward + ]) ? ComposeType.Reply : value); + } + }); + + this.lastReplyAction(Local.get(ClientSideKeyName.LastReplyAction) || ComposeType.Reply); + + this.lastReplyAction_.subscribe((value) => { + Local.set(ClientSideKeyName.LastReplyAction, value); + }); + + this.showFullInfo = ko.observable('1' === Local.get(ClientSideKeyName.MessageHeaderFullInfo)); + + this.moreDropdownTrigger = ko.observable(false); + this.messageDomFocused = ko.observable(false).extend({rateLimit: 0}); + + this.messageVisibility = ko.computed(() => !this.messageLoadingThrottle() && !!this.message()); + + this.message.subscribe((message) => { + if (!message) + { + MessageStore.selectorMessageSelected(null); + } + }); + + this.canBeRepliedOrForwarded = ko.computed(() => { + const v = this.messageVisibility(); + return !this.isDraftFolder() && v; + }); + + // commands + this.closeMessage = createCommand(() => { + MessageStore.message(null); + }); + + this.replyCommand = createCommandHelper(ComposeType.Reply); + this.replyAllCommand = createCommandHelper(ComposeType.ReplyAll); + this.forwardCommand = createCommandHelper(ComposeType.Forward); + this.forwardAsAttachmentCommand = createCommandHelper(ComposeType.ForwardAsAttachment); + this.editAsNewCommand = createCommandHelper(ComposeType.EditAsNew); + + this.messageVisibilityCommand = createCommand(noop, this.messageVisibility); + + this.messageEditCommand = createCommand(() => { + this.editMessage(); + }, this.messageVisibility); + + this.deleteCommand = createCommand(() => { + const message = this.message(); + if (message && this.allowMessageListActions) + { + this.message(null); + getApp().deleteMessagesFromFolder(FolderType.Trash, + message.folderFullNameRaw, [message.uid], true); + } + }, this.messageVisibility); + + this.deleteWithoutMoveCommand = createCommand(() => { + const message = this.message(); + if (message && this.allowMessageListActions) + { + this.message(null); + getApp().deleteMessagesFromFolder(FolderType.Trash, + message.folderFullNameRaw, [message.uid], false); + } + }, this.messageVisibility); + + this.archiveCommand = createCommand(() => { + const message = this.message(); + if (message && this.allowMessageListActions) + { + this.message(null); + getApp().deleteMessagesFromFolder(FolderType.Archive, + message.folderFullNameRaw, [message.uid], true); + } + }, this.messageVisibility); + + this.spamCommand = createCommand(() => { + const message = this.message(); + if (message && this.allowMessageListActions) + { + this.message(null); + getApp().deleteMessagesFromFolder(FolderType.Spam, + message.folderFullNameRaw, [message.uid], true); + } + }, this.messageVisibility); + + this.notSpamCommand = createCommand(() => { + const message = this.message(); + if (message && this.allowMessageListActions) + { + this.message(null); + getApp().deleteMessagesFromFolder(FolderType.NotSpam, + message.folderFullNameRaw, [message.uid], true); + } + }, this.messageVisibility); + + this.dropboxEnabled = SocialStore.dropbox.enabled; + this.dropboxApiKey = SocialStore.dropbox.apiKey; + + // viewer + + this.viewBodyTopValue = ko.observable(0); + + this.viewFolder = ''; + this.viewUid = ''; + this.viewHash = ''; + this.viewSubject = ko.observable(''); + this.viewFromShort = ko.observable(''); + this.viewFromDkimData = ko.observable(['none', '']); + this.viewToShort = ko.observable(''); + this.viewFrom = ko.observable(''); + this.viewTo = ko.observable(''); + this.viewCc = ko.observable(''); + this.viewBcc = ko.observable(''); + this.viewReplyTo = ko.observable(''); + this.viewTimeStamp = ko.observable(0); + this.viewSize = ko.observable(''); + this.viewLineAsCss = ko.observable(''); + this.viewViewLink = ko.observable(''); + this.viewUnsubscribeLink = ko.observable(''); + this.viewDownloadLink = ko.observable(''); + this.viewUserPic = ko.observable(DATA_IMAGE_USER_DOT_PIC); + this.viewUserPicVisible = ko.observable(false); + this.viewIsImportant = ko.observable(false); + this.viewIsFlagged = ko.observable(false); + + this.viewFromDkimVisibility = ko.computed(() => 'none' !== this.viewFromDkimData()[0]); + + this.viewFromDkimStatusIconClass = ko.computed(() => { + switch (this.viewFromDkimData()[0]) + { + case 'none': + return 'icon-none iconcolor-display-none'; + case 'pass': + return 'icon-ok iconcolor-green'; + default: + return 'icon-warning-alt iconcolor-red'; + } + }); + + this.viewFromDkimStatusTitle = ko.computed(() => { + + const status = this.viewFromDkimData(); + if (isNonEmptyArray(status)) + { + if (status[0] && status[1]) { - oItem.checked(!!bV); + return status[1]; + } + else if (status[0]) + { + return 'DKIM: ' + status[0]; } - }); - } - }, this); - - this.lastReplyAction_ = ko.observable(''); - this.lastReplyAction = ko.computed({ - read: this.lastReplyAction_, - write: function(sValue) { - sValue = -1 === Utils.inArray(sValue, [ - Enums.ComposeType.Reply, Enums.ComposeType.ReplyAll, Enums.ComposeType.Forward - ]) ? Enums.ComposeType.Reply : sValue; - this.lastReplyAction_(sValue); - }, - owner: this - }); - - this.lastReplyAction(Local.get(Enums.ClientSideKeyName.LastReplyAction) || Enums.ComposeType.Reply); - this.lastReplyAction_.subscribe(function(sValue) { - Local.set(Enums.ClientSideKeyName.LastReplyAction, sValue); - }); - - this.showFullInfo = ko.observable('1' === Local.get(Enums.ClientSideKeyName.MessageHeaderFullInfo)); - this.moreDropdownTrigger = ko.observable(false); - this.messageDomFocused = ko.observable(false).extend({'rateLimit': 0}); - - this.messageVisibility = ko.computed(function() { - return !this.messageLoadingThrottle() && !!this.message(); - }, this); - - this.message.subscribe(function(oMessage) { - if (!oMessage) - { - MessageStore.selectorMessageSelected(null); - } - }, this); - - this.canBeRepliedOrForwarded = ko.computed(function() { - var bV = this.messageVisibility(); - return !this.isDraftFolder() && bV; - }, this); - - // commands - this.closeMessage = Utils.createCommand(this, function() { - MessageStore.message(null); - }); - - this.replyCommand = createCommandHelper(Enums.ComposeType.Reply); - this.replyAllCommand = createCommandHelper(Enums.ComposeType.ReplyAll); - this.forwardCommand = createCommandHelper(Enums.ComposeType.Forward); - this.forwardAsAttachmentCommand = createCommandHelper(Enums.ComposeType.ForwardAsAttachment); - this.editAsNewCommand = createCommandHelper(Enums.ComposeType.EditAsNew); - - this.messageVisibilityCommand = Utils.createCommand(this, Utils.noop, this.messageVisibility); - - this.messageEditCommand = Utils.createCommand(this, function() { - this.editMessage(); - }, this.messageVisibility); - - this.deleteCommand = Utils.createCommand(this, function() { - var oMessage = this.message(); - if (oMessage && this.allowMessageListActions) - { - this.message(null); - require('App/User').default.deleteMessagesFromFolder(Enums.FolderType.Trash, - oMessage.folderFullNameRaw, [oMessage.uid], true); - } - }, this.messageVisibility); - - this.deleteWithoutMoveCommand = Utils.createCommand(this, function() { - var oMessage = this.message(); - if (oMessage && this.allowMessageListActions) - { - this.message(null); - require('App/User').default.deleteMessagesFromFolder(Enums.FolderType.Trash, - oMessage.folderFullNameRaw, [oMessage.uid], false); - } - }, this.messageVisibility); - - this.archiveCommand = Utils.createCommand(this, function() { - var oMessage = this.message(); - if (oMessage && this.allowMessageListActions) - { - this.message(null); - require('App/User').default.deleteMessagesFromFolder(Enums.FolderType.Archive, - oMessage.folderFullNameRaw, [oMessage.uid], true); - } - }, this.messageVisibility); - - this.spamCommand = Utils.createCommand(this, function() { - var oMessage = this.message(); - if (oMessage && this.allowMessageListActions) - { - this.message(null); - require('App/User').default.deleteMessagesFromFolder(Enums.FolderType.Spam, - oMessage.folderFullNameRaw, [oMessage.uid], true); - } - }, this.messageVisibility); - - this.notSpamCommand = Utils.createCommand(this, function() { - var oMessage = this.message(); - if (oMessage && this.allowMessageListActions) - { - this.message(null); - require('App/User').default.deleteMessagesFromFolder(Enums.FolderType.NotSpam, - oMessage.folderFullNameRaw, [oMessage.uid], true); - } - }, this.messageVisibility); - - this.dropboxEnabled = SocialStore.dropbox.enabled; - this.dropboxApiKey = SocialStore.dropbox.apiKey; - - // viewer - - this.viewBodyTopValue = ko.observable(0); - - this.viewFolder = ''; - this.viewUid = ''; - this.viewHash = ''; - this.viewSubject = ko.observable(''); - this.viewFromShort = ko.observable(''); - this.viewFromDkimData = ko.observable(['none', '']); - this.viewToShort = ko.observable(''); - this.viewFrom = ko.observable(''); - this.viewTo = ko.observable(''); - this.viewCc = ko.observable(''); - this.viewBcc = ko.observable(''); - this.viewReplyTo = ko.observable(''); - this.viewTimeStamp = ko.observable(0); - this.viewSize = ko.observable(''); - this.viewLineAsCss = ko.observable(''); - this.viewViewLink = ko.observable(''); - this.viewUnsubscribeLink = ko.observable(''); - this.viewDownloadLink = ko.observable(''); - this.viewUserPic = ko.observable(Consts.DATA_IMAGE_USER_DOT_PIC); - this.viewUserPicVisible = ko.observable(false); - this.viewIsImportant = ko.observable(false); - this.viewIsFlagged = ko.observable(false); - - this.viewFromDkimVisibility = ko.computed(function() { - return 'none' !== this.viewFromDkimData()[0]; - }, this); - - this.viewFromDkimStatusIconClass = ko.computed(function() { - switch (this.viewFromDkimData()[0]) - { - case 'none': - return 'icon-none iconcolor-display-none'; - case 'pass': - return 'icon-ok iconcolor-green'; - default: - return 'icon-warning-alt iconcolor-red'; - } - }, this); - - this.viewFromDkimStatusTitle = ko.computed(function() { - - var aStatus = this.viewFromDkimData(); - if (Utils.isNonEmptyArray(aStatus)) - { - if (aStatus[0] && aStatus[1]) - { - return aStatus[1]; } - else if (aStatus[0]) + + return ''; + }); + + this.messageActiveDom.subscribe((dom) => { + this.bodyBackgroundColor(dom ? this.detectDomBackgroundColor(dom) : ''); + }, this); + + this.message.subscribe((message) => { + + this.messageActiveDom(null); + + if (message) { - return 'DKIM: ' + aStatus[0]; + this.showAttachmnetControls(false); + + if (this.viewHash !== message.hash) + { + this.scrollMessageToTop(); + } + + this.viewFolder = message.folderFullNameRaw; + this.viewUid = message.uid; + this.viewHash = message.hash; + this.viewSubject(message.subject()); + this.viewFromShort(message.fromToLine(true, true)); + this.viewFromDkimData(message.fromDkimData()); + this.viewToShort(message.toToLine(true, true)); + this.viewFrom(message.fromToLine(false)); + this.viewTo(message.toToLine(false)); + this.viewCc(message.ccToLine(false)); + this.viewBcc(message.bccToLine(false)); + this.viewReplyTo(message.replyToToLine(false)); + this.viewTimeStamp(message.dateTimeStampInUTC()); + this.viewSize(message.friendlySize()); + this.viewLineAsCss(message.lineAsCss()); + this.viewViewLink(message.viewLink()); + this.viewUnsubscribeLink(message.getFirstUnsubsribeLink()); + this.viewDownloadLink(message.downloadLink()); + this.viewIsImportant(message.isImportant()); + this.viewIsFlagged(message.flagged()); + + lastEmail = message.fromAsSingleEmail(); + getUserPic(lastEmail, (pic, email) => { + if (pic !== this.viewUserPic() && lastEmail === email) + { + this.viewUserPicVisible(false); + this.viewUserPic(DATA_IMAGE_USER_DOT_PIC); + if ('' !== pic) + { + this.viewUserPicVisible(true); + this.viewUserPic(pic); + } + } + }); } - } - - return ''; - - }, this); - - this.messageActiveDom.subscribe(function(oDom) { - this.bodyBackgroundColor(oDom ? this.detectDomBackgroundColor(oDom) : ''); - }, this); - - this.message.subscribe(function(oMessage) { - - this.messageActiveDom(null); - - if (oMessage) - { - this.showAttachmnetControls(false); - - if (this.viewHash !== oMessage.hash) + else { + this.viewFolder = ''; + this.viewUid = ''; + this.viewHash = ''; + this.scrollMessageToTop(); } - this.viewFolder = oMessage.folderFullNameRaw; - this.viewUid = oMessage.uid; - this.viewHash = oMessage.hash; - this.viewSubject(oMessage.subject()); - this.viewFromShort(oMessage.fromToLine(true, true)); - this.viewFromDkimData(oMessage.fromDkimData()); - this.viewToShort(oMessage.toToLine(true, true)); - this.viewFrom(oMessage.fromToLine(false)); - this.viewTo(oMessage.toToLine(false)); - this.viewCc(oMessage.ccToLine(false)); - this.viewBcc(oMessage.bccToLine(false)); - this.viewReplyTo(oMessage.replyToToLine(false)); - this.viewTimeStamp(oMessage.dateTimeStampInUTC()); - this.viewSize(oMessage.friendlySize()); - this.viewLineAsCss(oMessage.lineAsCss()); - this.viewViewLink(oMessage.viewLink()); - this.viewUnsubscribeLink(oMessage.getFirstUnsubsribeLink()); - this.viewDownloadLink(oMessage.downloadLink()); - this.viewIsImportant(oMessage.isImportant()); - this.viewIsFlagged(oMessage.flagged()); + }); - sLastEmail = oMessage.fromAsSingleEmail(); - Cache.getUserPic(sLastEmail, function(sPic, sEmail) { - if (sPic !== self.viewUserPic() && sLastEmail === sEmail) + this.message.viewTrigger.subscribe(() => { + const message = this.message(); + if (message) + { + this.viewIsFlagged(message.flagged()); + } + else + { + this.viewIsFlagged(false); + } + }); + + this.fullScreenMode.subscribe((value) => { + $html.toggleClass('rl-message-fullscreen', value); + windowResize(); + }); + + this.messageLoadingThrottle.subscribe(windowResizeCallback); + + this.messageFocused = ko.computed(() => Focused.MessageView === AppStore.focusedState()); + + this.messageListAndMessageViewLoading = ko.computed( + () => MessageStore.messageListCompleteLoadingThrottle() || MessageStore.messageLoadingThrottle() + ); + + this.goUpCommand = createCommand(() => { + Events.pub('mailbox.message-list.selector.go-up', [ + Layout.NoPreview === this.layout() ? !!this.message() : true + ]); + }, () => !this.messageListAndMessageViewLoading()); + + this.goDownCommand = createCommand(() => { + Events.pub('mailbox.message-list.selector.go-down', [ + Layout.NoPreview === this.layout() ? !!this.message() : true + ]); + }, () => !this.messageListAndMessageViewLoading()); + + Events.sub('mailbox.message-view.toggle-full-screen', () => { + this.toggleFullScreen(); + }); + + this.attachmentPreview = _.bind(this.attachmentPreview, this); + } + + detectDomBackgroundColor(dom) { + let + limit = 5, + result = ''; + + const + fFindDom = function(inputDom) { + const children = inputDom ? inputDom.children() : null; + return (children && 1 === children.length && children.is('table,div,center')) ? children : null; + }, + fFindColor = function(inputDom) { + let color = ''; + if (inputDom) { - self.viewUserPicVisible(false); - self.viewUserPic(Consts.DATA_IMAGE_USER_DOT_PIC); - if ('' !== sPic) + color = inputDom.css('background-color') || ''; + if (!inputDom.is('table')) { - self.viewUserPicVisible(true); - self.viewUserPic(sPic); + color = 'rgba(0, 0, 0, 0)' === color || 'transparent' === color ? '' : color; } } + + return color; + }; + + if (dom && 1 === dom.length) + { + let aC = dom; + while ('' === result) + { + limit -= 1; + if (0 >= limit) + { + break; + } + + aC = fFindDom(aC); + if (aC) + { + result = fFindColor(aC); + } + else + { + break; + } + } + + result = 'rgba(0, 0, 0, 0)' === result || 'transparent' === result ? '' : result; + } + + return result; + } + + fullScreen() { + this.fullScreenMode(true); + windowResize(); + } + + unFullScreen() { + this.fullScreenMode(false); + windowResize(); + } + + toggleFullScreen() { + removeSelection(); + + this.fullScreenMode(!this.fullScreenMode()); + windowResize(); + } + + /** + * @param {string} sType + * @returns {void} + */ + replyOrforward(sType) { + if (Settings.capa(Capa.Composer)) + { + showScreenPopup(require('View/Popup/Compose'), [sType, MessageStore.message()]); + } + } + + checkHeaderHeight() { + if (this.oHeaderDom) + { + this.viewBodyTopValue(this.message() ? this.oHeaderDom.height() + + Magics.Size20px /* padding-(top/bottom): 20px */ + Magics.Size1px /* borded-bottom: 1px */ : 0); + } + } + + // displayMailToPopup(sMailToUrl) { + // sMailToUrl = sMailToUrl.replace(/\?.+$/, ''); + // + // var + // sResult = '', + // aTo = [], + // EmailModel = require('Model/Email').default, + // fParseEmailLine = function(sLine) { + // return sLine ? _.compact(_.map([window.decodeURIComponent(sLine)], function(sItem) { + // var oEmailModel = new EmailModel(); + // oEmailModel.mailsoParse(sItem); + // return '' !== oEmailModel.email ? oEmailModel : null; + // })) : null; + // } + // ; + // + // aTo = fParseEmailLine(sMailToUrl); + // sResult = aTo && aTo[0] ? aTo[0].email : ''; + // + // return sResult; + // } + + /** + * @param {Object} oAttachment + * @returns {boolean} + */ + attachmentPreview(attachment) { + if (attachment && attachment.isImage() && !attachment.isLinked && this.message() && this.message().attachments()) + { + let + index = 0, + listIndex = 0; + + const + div = $('
'), + dynamicEls = _.compact(_.map(this.message().attachments(), (item) => { + if (item && !item.isLinked && item.isImage()) + { + if (item === attachment) + { + index = listIndex; + } + + listIndex += 1; + + return { + src: item.linkPreview(), + thumb: item.linkThumbnail(), + subHtml: item.fileName, + downloadUrl: item.linkPreview() + }; + } + + return null; + })); + + if (0 < dynamicEls.length) + { + div.on('onBeforeOpen.lg', () => { + useKeyboardShortcuts(false); + removeInFocus(true); + }); + + div.on('onCloseAfter.lg', () => { + useKeyboardShortcuts(true); + }); + + div.lightGallery({ + dynamic: true, + loadYoutubeThumbnail: false, + loadVimeoThumbnail: false, + thumbWidth: 80, + thumbContHeight: 95, + showThumbByDefault: false, + mode: 'lg-lollipop', // 'lg-slide', + index: index, + dynamicEl: dynamicEls + }); + } + + return false; + } + + return true; + } + + onBuild(dom) { + + const + self = this, + fCheckHeaderHeight = _.bind(this.checkHeaderHeight, this); + + this.oDom = dom; + + this.fullScreenMode.subscribe((value) => { + if (value && this.message()) + { + AppStore.focusedState(Focused.MessageView); + } + }); + + this.showAttachmnetControls.subscribe(fCheckHeaderHeight); + this.fullScreenMode.subscribe(fCheckHeaderHeight); + this.showFullInfo.subscribe(fCheckHeaderHeight); + this.message.subscribe(fCheckHeaderHeight); + + Events.sub('window.resize', _.throttle(() => { + _.delay(fCheckHeaderHeight, 1); + _.delay(fCheckHeaderHeight, Magics.Time200ms); + _.delay(fCheckHeaderHeight, Magics.Time500ms); + }, Magics.Time50ms)); + + this.showFullInfo.subscribe((value) => { + windowResize(); + windowResize(Magics.Time200ms); + Local.set(ClientSideKeyName.MessageHeaderFullInfo, value ? '1' : '0'); + }); + + SocialStore.appendDropbox(); + + this.oHeaderDom = $('.messageItemHeader', dom); + this.oHeaderDom = this.oHeaderDom[0] ? this.oHeaderDom : null; + + if (this.mobile) + { + dom.on('click', () => { + leftPanelDisabled(true); + }); + } + + dom + .on('click', 'a', function(event) { // eslint-disable-line prefer-arrow-callback + // setup maito protocol + return !(!!event && Magics.EventWhichMouseMiddle !== event.which && mailToHelper( + $(this).attr('href'), Settings.capa(Capa.Composer) ? require('View/Popup/Compose') : null // eslint-disable-line no-invalid-this + )); + }) + .on('click', '.attachmentsPlace .attachmentIconParent', (event) => { + if (event && event.stopPropagation) + { + event.stopPropagation(); + } + }) + .on('click', '.attachmentsPlace .showPreplay', function(event) { // eslint-disable-line prefer-arrow-callback + if (event && event.stopPropagation) + { + event.stopPropagation(); + } + + const attachment = ko.dataFor(this); // eslint-disable-line no-invalid-this + if (attachment && Audio.supported) + { + switch (true) + { + case Audio.supportedMp3 && attachment.isMp3(): + Audio.playMp3(attachment.linkDownload(), attachment.fileName); + break; + case Audio.supportedOgg && attachment.isOgg(): + Audio.playOgg(attachment.linkDownload(), attachment.fileName); + break; + case Audio.supportedWav && attachment.isWav(): + Audio.playWav(attachment.linkDownload(), attachment.fileName); + break; + // no default + } + } + }) + .on('click', '.attachmentsPlace .attachmentItem .attachmentNameParent', function() { // eslint-disable-line prefer-arrow-callback + const attachment = ko.dataFor(this); // eslint-disable-line no-invalid-this + if (attachment && attachment.download) + { + getApp().download(attachment.linkDownload()); + } + }) + .on('click', '.messageItemHeader .subjectParent .flagParent', function() { // eslint-disable-line prefer-arrow-callback + const message = self.message(); + if (message) + { + getApp().messageListAction(message.folderFullNameRaw, message.uid, + message.flagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, [message]); + } + }) + .on('click', '.thread-list .flagParent', function() { // eslint-disable-line prefer-arrow-callback + const message = ko.dataFor(this); // eslint-disable-line no-invalid-this + if (message && message.folder && message.uid) + { + getApp().messageListAction( + message.folder, message.uid, + message.flagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, [message]); + } + + self.threadsDropdownTrigger(true); + + return false; + }); + + AppStore.focusedState.subscribe((value) => { + if (Focused.MessageView !== value) + { + this.scrollMessageToTop(); + this.scrollMessageToLeft(); + } + }); + + keyScopeReal.subscribe((value) => { + this.messageDomFocused(KeyState.MessageView === value && !inFocus()); + }); + + this.oMessageScrollerDom = dom.find('.messageItem .content'); + this.oMessageScrollerDom = this.oMessageScrollerDom && this.oMessageScrollerDom[0] ? this.oMessageScrollerDom : null; + + this.initShortcuts(); + } + + /** + * @returns {boolean} + */ + escShortcuts() { + if (this.viewModelVisibility() && this.message()) + { + if (this.fullScreenMode()) + { + this.fullScreenMode(false); + + if (Layout.NoPreview !== this.layout()) + { + AppStore.focusedState(Focused.MessageList); + } + } + else if (Layout.NoPreview === this.layout()) + { + this.message(null); + } + else + { + AppStore.focusedState(Focused.MessageList); + } + + return false; + } + + return true; + } + + initShortcuts() { + + // exit fullscreen, back + key('esc, backspace', KeyState.MessageView, _.bind(this.escShortcuts, this)); + + // fullscreen + key('enter', KeyState.MessageView, () => { + this.toggleFullScreen(); + return false; + }); + + // reply + key('r', [KeyState.MessageList, KeyState.MessageView], () => { + if (MessageStore.message()) + { + this.replyCommand(); + return false; + } + + return true; + }); + + // replaAll + key('a', [KeyState.MessageList, KeyState.MessageView], () => { + if (MessageStore.message()) + { + this.replyAllCommand(); + return false; + } + + return true; + }); + + // forward + key('f', [KeyState.MessageList, KeyState.MessageView], () => { + if (MessageStore.message()) + { + this.forwardCommand(); + return false; + } + + return true; + }); + + // message information + key('ctrl+i, command+i', [KeyState.MessageList, KeyState.MessageView], () => { + if (MessageStore.message()) + { + this.showFullInfo(!this.showFullInfo()); + } + return false; + }); + + // toggle message blockquotes + key('b', [KeyState.MessageList, KeyState.MessageView], () => { + if (MessageStore.message() && MessageStore.message().body) + { + MessageStore.message().body.find('.rlBlockquoteSwitcher').click(); + return false; + } + + return true; + }); + + key('ctrl+up, command+up, ctrl+left, command+left', [KeyState.MessageList, KeyState.MessageView], () => { + this.goUpCommand(); + return false; + }); + + key('ctrl+down, command+down, ctrl+right, command+right', [KeyState.MessageList, KeyState.MessageView], () => { + this.goDownCommand(); + return false; + }); + + // print + key('ctrl+p, command+p', [KeyState.MessageView, KeyState.MessageList], () => { + if (this.message()) + { + this.message().printMessage(); + } + + return false; + }); + + // delete + key('delete, shift+delete', KeyState.MessageView, (event, handler) => { + if (event) + { + if (handler && 'shift+delete' === handler.shortcut) + { + this.deleteWithoutMoveCommand(); + } + else + { + this.deleteCommand(); + } + + return false; + } + + return true; + }); + + // change focused state + key('tab, shift+tab, left', KeyState.MessageView, (event, handler) => { + if (!this.fullScreenMode() && this.message() && Layout.NoPreview !== this.layout()) + { + if (event && handler && 'left' === handler.shortcut) + { + if (this.oMessageScrollerDom && 0 < this.oMessageScrollerDom.scrollLeft()) + { + return true; + } + + AppStore.focusedState(Focused.MessageList); + } + else + { + AppStore.focusedState(Focused.MessageList); + } + } + else if (this.message() && Layout.NoPreview === this.layout() && event && handler && 'left' === handler.shortcut) + { + return true; + } + + return false; + }); + } + + /** + * @returns {boolean} + */ + isDraftFolder() { + return MessageStore.message() && FolderStore.draftFolder() === MessageStore.message().folderFullNameRaw; + } + + /** + * @returns {boolean} + */ + isSentFolder() { + return MessageStore.message() && FolderStore.sentFolder() === MessageStore.message().folderFullNameRaw; + } + + /** + * @returns {boolean} + */ + isSpamFolder() { + return MessageStore.message() && FolderStore.spamFolder() === MessageStore.message().folderFullNameRaw; + } + + /** + * @returns {boolean} + */ + isSpamDisabled() { + return MessageStore.message() && FolderStore.spamFolder() === UNUSED_OPTION_VALUE; + } + + /** + * @returns {boolean} + */ + isArchiveFolder() { + return MessageStore.message() && FolderStore.archiveFolder() === MessageStore.message().folderFullNameRaw; + } + + /** + * @returns {boolean} + */ + isArchiveDisabled() { + return MessageStore.message() && FolderStore.archiveFolder() === UNUSED_OPTION_VALUE; + } + + /** + * @returns {boolean} + */ + isDraftOrSentFolder() { + return this.isDraftFolder() || this.isSentFolder(); + } + + composeClick() { + if (Settings.capa(Capa.Composer)) + { + showScreenPopup(require('View/Popup/Compose')); + } + } + + editMessage() { + if (Settings.capa(Capa.Composer) && MessageStore.message()) + { + showScreenPopup(require('View/Popup/Compose'), [ComposeType.Draft, MessageStore.message()]); + } + } + + scrollMessageToTop() { + if (this.oMessageScrollerDom) + { + if (Magics.Size50px < this.oMessageScrollerDom.scrollTop()) + { + this.oMessageScrollerDom + .scrollTop(Magics.Size50px) + .animate({'scrollTop': 0}, Magics.Time200ms); + } + else + { + this.oMessageScrollerDom.scrollTop(0); + } + + windowResize(); + } + } + + scrollMessageToLeft() { + if (this.oMessageScrollerDom) + { + this.oMessageScrollerDom.scrollLeft(0); + windowResize(); + } + } + + getAttachmentsHashes() { + const atts = this.message() ? this.message().attachments() : []; + return _.compact(_.map(atts, (item) => (item && !item.isLinked && item.checked() ? item.download : ''))); + } + + downloadAsZip() { + const hashes = this.getAttachmentsHashes(); + if (0 < hashes.length) + { + Promises.attachmentsActions('Zip', hashes, this.downloadAsZipLoading).then((result) => { + if (result && result.Result && result.Result.Files && + result.Result.Files[0] && result.Result.Files[0].Hash) + { + getApp().download(attachmentDownload(result.Result.Files[0].Hash)); + } + else + { + this.downloadAsZipError(true); + } + }).catch(() => { + this.downloadAsZipError(true); }); } else { - this.viewFolder = ''; - this.viewUid = ''; - this.viewHash = ''; - - this.scrollMessageToTop(); + this.highlightUnselectedAttachments(true); } + } - }, this); + saveToOwnCloud() { - this.message.viewTrigger.subscribe(function() { - var oMessage = this.message(); - if (oMessage) + const hashes = this.getAttachmentsHashes(); + if (0 < hashes.length) { - this.viewIsFlagged(oMessage.flagged()); + Promises.attachmentsActions('OwnCloud', hashes, this.saveToOwnCloudLoading).then((result) => { + if (result && result.Result) + { + this.saveToOwnCloudSuccess(true); + } + else + { + this.saveToOwnCloudError(true); + } + }).catch(() => { + this.saveToOwnCloudError(true); + }); } else { - this.viewIsFlagged(false); + this.highlightUnselectedAttachments(true); } - }, this); + } - this.fullScreenMode.subscribe(function(bValue) { - Globals.$html.toggleClass('rl-message-fullscreen', bValue); - Utils.windowResize(); - }); + saveToDropbox() { - this.messageLoadingThrottle.subscribe(Utils.windowResizeCallback); + const + files = [], + hashes = this.getAttachmentsHashes(); - this.messageFocused = ko.computed(function() { - return Enums.Focused.MessageView === AppStore.focusedState(); - }); + if (0 < hashes.length) + { + if (window.Dropbox) + { + Promises.attachmentsActions('Dropbox', hashes, this.saveToDropboxLoading).then((result) => { + if (result && result.Result && result.Result.Url && result.Result.ShortLife && result.Result.Files) + { + if (window.Dropbox && isArray(result.Result.Files)) + { + _.each(result.Result.Files, (item) => { + files.push({ + url: result.Result.Url + attachmentDownload(item.Hash, result.Result.ShortLife), + filename: item.FileName + }); + }); - this.messageListAndMessageViewLoading = ko.computed(function() { - return MessageStore.messageListCompleteLoadingThrottle() || MessageStore.messageLoadingThrottle(); - }); + window.Dropbox.save({ + files: files, + progress: () => { + this.saveToDropboxLoading(true); + this.saveToDropboxError(false); + this.saveToDropboxSuccess(false); + }, + cancel: () => { + this.saveToDropboxSuccess(false); + this.saveToDropboxError(false); + this.saveToDropboxLoading(false); + }, + success: () => { + this.saveToDropboxSuccess(true); + this.saveToDropboxLoading(false); + }, + error: () => { + this.saveToDropboxError(true); + this.saveToDropboxLoading(false); + } + }); + } + else + { + this.saveToDropboxError(true); + } + } + }).catch(() => { + this.saveToDropboxError(true); + }); + } + } + else + { + this.highlightUnselectedAttachments(true); + } + } - this.goUpCommand = Utils.createCommand(this, function() { - Events.pub('mailbox.message-list.selector.go-up', [ - Enums.Layout.NoPreview === this.layout() ? !!this.message() : true - ]); - }, function() { - return !this.messageListAndMessageViewLoading(); - }); + /** + * @param {MessageModel} oMessage + * @returns {void} + */ + showImages(message) { + if (message && message.showExternalImages) + { + message.showExternalImages(true); + } - this.goDownCommand = Utils.createCommand(this, function() { - Events.pub('mailbox.message-list.selector.go-down', [ - Enums.Layout.NoPreview === this.layout() ? !!this.message() : true - ]); - }, function() { - return !this.messageListAndMessageViewLoading(); - }); + this.checkHeaderHeight(); + } - Events.sub('mailbox.message-view.toggle-full-screen', function() { - this.toggleFullScreen(); - }, this); + /** + * @returns {string} + */ + printableCheckedMessageCount() { + const cnt = this.messageListCheckedOrSelectedUidsWithSubMails().length; + return 0 < cnt ? (100 > cnt ? cnt : '99+') : ''; // eslint-disable-line no-magic-numbers + } - this.attachmentPreview = _.bind(this.attachmentPreview, this); + /** + * @param {MessageModel} oMessage + * @returns {void} + */ + readReceipt(oMessage) { + if (oMessage && '' !== oMessage.readReceipt()) + { + Remote.sendReadReceiptMessage(noop, oMessage.folderFullNameRaw, oMessage.uid, + oMessage.readReceipt(), + i18n('READ_RECEIPT/SUBJECT', {'SUBJECT': oMessage.subject()}), + i18n('READ_RECEIPT/BODY', {'READ-RECEIPT': AccountStore.email()})); - kn.constructorEnd(this); + oMessage.isReadReceipt(true); + + storeMessageFlagsToCache(oMessage); + + getApp().reloadFlagsCurrentMessageListAndMessageFromCache(); + } + + this.checkHeaderHeight(); + } } -kn.extendAsViewModel(['View/User/MailBox/MessageView', 'View/App/MailBox/MessageView', 'MailBoxMessageViewViewModel'], MessageViewMailBoxUserView); -_.extend(MessageViewMailBoxUserView.prototype, AbstractView.prototype); - -MessageViewMailBoxUserView.prototype.detectDomBackgroundColor = function(oDom) -{ - var - iLimit = 5, - sResult = '', - fFindDom = function(oInputDom) { - var children = oInputDom ? oInputDom.children() : null; - return (children && 1 === children.length && children.is('table,div,center')) ? children : null; - }, - fFindColor = function(oInputDom) { - var color = ''; - if (oInputDom) - { - color = oInputDom.css('background-color') || ''; - if (!oInputDom.is('table')) - { - color = 'rgba(0, 0, 0, 0)' === color || 'transparent' === color ? '' : color; - } - } - - return color; - }; - - if (oDom && 1 === oDom.length) - { - var aC = oDom; - while ('' === sResult) - { - iLimit -= 1; - if (0 >= iLimit) - { - break; - } - - aC = fFindDom(aC); - if (aC) - { - sResult = fFindColor(aC); - } - else - { - break; - } - } - - sResult = 'rgba(0, 0, 0, 0)' === sResult || 'transparent' === sResult ? '' : sResult; - } - - return sResult; -}; - -MessageViewMailBoxUserView.prototype.fullScreen = function() -{ - this.fullScreenMode(true); - Utils.windowResize(); -}; - -MessageViewMailBoxUserView.prototype.unFullScreen = function() -{ - this.fullScreenMode(false); - Utils.windowResize(); -}; - -MessageViewMailBoxUserView.prototype.toggleFullScreen = function() -{ - Utils.removeSelection(); - - this.fullScreenMode(!this.fullScreenMode()); - Utils.windowResize(); -}; - -/** - * @param {string} sType - * @returns {void} - */ -MessageViewMailBoxUserView.prototype.replyOrforward = function(sType) -{ - if (Settings.capa(Enums.Capa.Composer)) - { - kn.showScreenPopup(require('View/Popup/Compose'), [sType, MessageStore.message()]); - } -}; - -MessageViewMailBoxUserView.prototype.checkHeaderHeight = function() -{ - if (this.oHeaderDom) - { - this.viewBodyTopValue(this.message() ? this.oHeaderDom.height() + - Enums.Magics.Size20px /* padding-(top/bottom): 20px */ + Enums.Magics.Size1px /* borded-bottom: 1px */ : 0); - } -}; - -// MessageViewMailBoxUserView.prototype.displayMailToPopup = function(sMailToUrl) -// { -// sMailToUrl = sMailToUrl.replace(/\?.+$/, ''); -// -// var -// sResult = '', -// aTo = [], -// EmailModel = require('Model/Email').default, -// fParseEmailLine = function(sLine) { -// return sLine ? _.compact(_.map([window.decodeURIComponent(sLine)], function(sItem) { -// var oEmailModel = new EmailModel(); -// oEmailModel.mailsoParse(sItem); -// return '' !== oEmailModel.email ? oEmailModel : null; -// })) : null; -// } -// ; -// -// aTo = fParseEmailLine(sMailToUrl); -// sResult = aTo && aTo[0] ? aTo[0].email : ''; -// -// return sResult; -// }; - -/** - * @param {Object} oAttachment - * @returns {boolean} - */ -MessageViewMailBoxUserView.prototype.attachmentPreview = function(oAttachment) -{ - if (oAttachment && oAttachment.isImage() && !oAttachment.isLinked && this.message() && this.message().attachments()) - { - var - oDiv = $('
'), - iIndex = 0, - iListIndex = 0, - aDynamicEl = _.compact(_.map(this.message().attachments(), function(oItem) { - if (oItem && !oItem.isLinked && oItem.isImage()) - { - if (oItem === oAttachment) - { - iIndex = iListIndex; - } - - iListIndex += 1; - - return { - src: oItem.linkPreview(), - thumb: oItem.linkThumbnail(), - subHtml: oItem.fileName, - downloadUrl: oItem.linkPreview() - }; - } - - return null; - })); - - if (0 < aDynamicEl.length) - { - oDiv.on('onBeforeOpen.lg', function() { - Globals.useKeyboardShortcuts(false); - Utils.removeInFocus(true); - }); - - oDiv.on('onCloseAfter.lg', function() { - Globals.useKeyboardShortcuts(true); - }); - - oDiv.lightGallery({ - dynamic: true, - loadYoutubeThumbnail: false, - loadVimeoThumbnail: false, - thumbWidth: 80, - thumbContHeight: 95, - showThumbByDefault: false, - mode: 'lg-lollipop', // 'lg-slide', - index: iIndex, - dynamicEl: aDynamicEl - }); - } - - return false; - } - - return true; -}; - -MessageViewMailBoxUserView.prototype.onBuild = function(oDom) -{ - var - self = this, -// sErrorMessage = Translator.i18n('PREVIEW_POPUP/IMAGE_ERROR'), - fCheckHeaderHeight = _.bind(this.checkHeaderHeight, this); - - this.oDom = oDom; - - this.fullScreenMode.subscribe(function(bValue) { - if (bValue && self.message()) - { - AppStore.focusedState(Enums.Focused.MessageView); - } - }, this); - - this.showAttachmnetControls.subscribe(fCheckHeaderHeight); - this.fullScreenMode.subscribe(fCheckHeaderHeight); - this.showFullInfo.subscribe(fCheckHeaderHeight); - this.message.subscribe(fCheckHeaderHeight); - - Events.sub('window.resize', _.throttle(function() { - _.delay(fCheckHeaderHeight, 1); - _.delay(fCheckHeaderHeight, Enums.Magics.Time200ms); - _.delay(fCheckHeaderHeight, Enums.Magics.Time500ms); - }, Enums.Magics.Time50ms)); - - this.showFullInfo.subscribe(function(value) { - Utils.windowResize(); - Utils.windowResize(Enums.Magics.Time200ms); - Local.set(Enums.ClientSideKeyName.MessageHeaderFullInfo, value ? '1' : '0'); - }); - - if (this.dropboxEnabled() && this.dropboxApiKey() && !window.Dropbox) - { - var oScript = window.document.createElement('script'); - oScript.type = 'text/javascript'; - oScript.src = 'https://www.dropbox.com/static/api/2/dropins.js'; - $(oScript).attr('id', 'dropboxjs').attr('data-app-key', self.dropboxApiKey()); - - window.document.body.appendChild(oScript); - } - - this.oHeaderDom = $('.messageItemHeader', oDom); - this.oHeaderDom = this.oHeaderDom[0] ? this.oHeaderDom : null; - - if (this.mobile) - { - oDom - .on('click', function() { - Globals.leftPanelDisabled(true); - }); - } - - oDom - .on('click', 'a', function(oEvent) { - // setup maito protocol - return !(!!oEvent && Enums.Magics.EventWhichMouseMiddle !== oEvent.which && Utils.mailToHelper( - $(this).attr('href'), Settings.capa(Enums.Capa.Composer) ? require('View/Popup/Compose') : null - )); - }) -// .on('mouseover', 'a', _.debounce(function(oEvent) { -// -// if (oEvent) -// { -// var sMailToUrl = $(this).attr('href'); -// if (sMailToUrl && 'mailto:' === sMailToUrl.toString().substr(0, 7).toLowerCase()) -// { -// sMailToUrl = sMailToUrl.toString().substr(7); -// self.displayMailToPopup(sMailToUrl); -// } -// } -// -// return true; -// -// }, 1000)) - .on('click', '.attachmentsPlace .attachmentIconParent', function(oEvent) { - if (oEvent && oEvent.stopPropagation) - { - oEvent.stopPropagation(); - } - }) - .on('click', '.attachmentsPlace .showPreplay', function(oEvent) { - if (oEvent && oEvent.stopPropagation) - { - oEvent.stopPropagation(); - } - - var oAttachment = ko.dataFor(this); - if (oAttachment && Audio.supported) - { - switch (true) - { - case Audio.supportedMp3 && oAttachment.isMp3(): - Audio.playMp3(oAttachment.linkDownload(), oAttachment.fileName); - break; - case Audio.supportedOgg && oAttachment.isOgg(): - Audio.playOgg(oAttachment.linkDownload(), oAttachment.fileName); - break; - case Audio.supportedWav && oAttachment.isWav(): - Audio.playWav(oAttachment.linkDownload(), oAttachment.fileName); - break; - // no default - } - } - }) - .on('click', '.attachmentsPlace .attachmentItem .attachmentNameParent', function() { - - var - oAttachment = ko.dataFor(this); - - if (oAttachment && oAttachment.download) - { - require('App/User').default.download(oAttachment.linkDownload()); - } - }) - .on('click', '.messageItemHeader .subjectParent .flagParent', function() { - var oMessage = self.message(); - if (oMessage) - { - require('App/User').default.messageListAction(oMessage.folderFullNameRaw, oMessage.uid, - oMessage.flagged() ? Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, [oMessage]); - } - }) - .on('click', '.thread-list .flagParent', function() { - var oMessage = ko.dataFor(this); - if (oMessage && oMessage.folder && oMessage.uid) - { - require('App/User').default.messageListAction( - oMessage.folder, oMessage.uid, - oMessage.flagged() ? Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, [oMessage]); - } - - self.threadsDropdownTrigger(true); - - return false; - }); - - AppStore.focusedState.subscribe(function(sValue) { - if (Enums.Focused.MessageView !== sValue) - { - this.scrollMessageToTop(); - this.scrollMessageToLeft(); - } - }, this); - - Globals.keyScopeReal.subscribe(function(sValue) { - this.messageDomFocused(Enums.KeyState.MessageView === sValue && !Utils.inFocus()); - }, this); - - this.oMessageScrollerDom = oDom.find('.messageItem .content'); - this.oMessageScrollerDom = this.oMessageScrollerDom && this.oMessageScrollerDom[0] ? this.oMessageScrollerDom : null; - - this.initShortcuts(); -}; - -/** - * @returns {boolean} - */ -MessageViewMailBoxUserView.prototype.escShortcuts = function() -{ - if (this.viewModelVisibility() && this.message()) - { - if (this.fullScreenMode()) - { - this.fullScreenMode(false); - - if (Enums.Layout.NoPreview !== this.layout()) - { - AppStore.focusedState(Enums.Focused.MessageList); - } - } - else if (Enums.Layout.NoPreview === this.layout()) - { - this.message(null); - } - else - { - AppStore.focusedState(Enums.Focused.MessageList); - } - - return false; - } - - return true; -}; - -MessageViewMailBoxUserView.prototype.initShortcuts = function() -{ - var self = this; - - // exit fullscreen, back - key('esc, backspace', Enums.KeyState.MessageView, _.bind(this.escShortcuts, this)); - - // fullscreen - key('enter', Enums.KeyState.MessageView, function() { - self.toggleFullScreen(); - return false; - }); - - // reply - key('r', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function() { - if (MessageStore.message()) - { - self.replyCommand(); - return false; - } - - return true; - }); - - // replaAll - key('a', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function() { - if (MessageStore.message()) - { - self.replyAllCommand(); - return false; - } - - return true; - }); - - // forward - key('f', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function() { - if (MessageStore.message()) - { - self.forwardCommand(); - return false; - } - - return true; - }); - - // message information - key('ctrl+i, command+i', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function() { - if (MessageStore.message()) - { - self.showFullInfo(!self.showFullInfo()); - } - return false; - }); - - // toggle message blockquotes - key('b', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function() { - if (MessageStore.message() && MessageStore.message().body) - { - MessageStore.message().body.find('.rlBlockquoteSwitcher').click(); - return false; - } - - return true; - }); - - key('ctrl+up, command+up, ctrl+left, command+left', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function() { - self.goUpCommand(); - return false; - }); - - key('ctrl+down, command+down, ctrl+right, command+right', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function() { - self.goDownCommand(); - return false; - }); - - // print - key('ctrl+p, command+p', [Enums.KeyState.MessageView, Enums.KeyState.MessageList], function() { - if (self.message()) - { - self.message().printMessage(); - } - - return false; - }); - - // delete - key('delete, shift+delete', Enums.KeyState.MessageView, function(event, handler) { - if (event) - { - if (handler && 'shift+delete' === handler.shortcut) - { - self.deleteWithoutMoveCommand(); - } - else - { - self.deleteCommand(); - } - - return false; - } - - return true; - }); - - // change focused state - key('tab, shift+tab, left', Enums.KeyState.MessageView, function(event, handler) { - if (!self.fullScreenMode() && self.message() && Enums.Layout.NoPreview !== self.layout()) - { - if (event && handler && 'left' === handler.shortcut) - { - if (self.oMessageScrollerDom && 0 < self.oMessageScrollerDom.scrollLeft()) - { - return true; - } - - AppStore.focusedState(Enums.Focused.MessageList); - } - else - { - AppStore.focusedState(Enums.Focused.MessageList); - } - } - else if (self.message() && Enums.Layout.NoPreview === self.layout() && event && handler && 'left' === handler.shortcut) - { - return true; - } - - return false; - }); -}; - -/** - * @returns {boolean} - */ -MessageViewMailBoxUserView.prototype.isDraftFolder = function() -{ - return MessageStore.message() && FolderStore.draftFolder() === MessageStore.message().folderFullNameRaw; -}; - -/** - * @returns {boolean} - */ -MessageViewMailBoxUserView.prototype.isSentFolder = function() -{ - return MessageStore.message() && FolderStore.sentFolder() === MessageStore.message().folderFullNameRaw; -}; - -/** - * @returns {boolean} - */ -MessageViewMailBoxUserView.prototype.isSpamFolder = function() -{ - return MessageStore.message() && FolderStore.spamFolder() === MessageStore.message().folderFullNameRaw; -}; - -/** - * @returns {boolean} - */ -MessageViewMailBoxUserView.prototype.isSpamDisabled = function() -{ - return MessageStore.message() && FolderStore.spamFolder() === Consts.UNUSED_OPTION_VALUE; -}; - -/** - * @returns {boolean} - */ -MessageViewMailBoxUserView.prototype.isArchiveFolder = function() -{ - return MessageStore.message() && FolderStore.archiveFolder() === MessageStore.message().folderFullNameRaw; -}; - -/** - * @returns {boolean} - */ -MessageViewMailBoxUserView.prototype.isArchiveDisabled = function() -{ - return MessageStore.message() && FolderStore.archiveFolder() === Consts.UNUSED_OPTION_VALUE; -}; - -/** - * @returns {boolean} - */ -MessageViewMailBoxUserView.prototype.isDraftOrSentFolder = function() -{ - return this.isDraftFolder() || this.isSentFolder(); -}; - -MessageViewMailBoxUserView.prototype.composeClick = function() -{ - if (Settings.capa(Enums.Capa.Composer)) - { - kn.showScreenPopup(require('View/Popup/Compose')); - } -}; - -MessageViewMailBoxUserView.prototype.editMessage = function() -{ - if (Settings.capa(Enums.Capa.Composer) && MessageStore.message()) - { - kn.showScreenPopup(require('View/Popup/Compose'), [Enums.ComposeType.Draft, MessageStore.message()]); - } -}; - -MessageViewMailBoxUserView.prototype.scrollMessageToTop = function() -{ - if (this.oMessageScrollerDom) - { - if (Enums.Size50px < this.oMessageScrollerDom.scrollTop()) - { - this.oMessageScrollerDom - .scrollTop(Enums.Size50px) - .animate({'scrollTop': 0}, Enums.Time200ms); - } - else - { - this.oMessageScrollerDom.scrollTop(0); - } - - Utils.windowResize(); - } -}; - -MessageViewMailBoxUserView.prototype.scrollMessageToLeft = function() -{ - if (this.oMessageScrollerDom) - { - this.oMessageScrollerDom.scrollLeft(0); - Utils.windowResize(); - } -}; - -MessageViewMailBoxUserView.prototype.getAttachmentsHashes = function() -{ - return _.compact(_.map(this.message() ? this.message().attachments() : [], function(oItem) { - return oItem && !oItem.isLinked && oItem.checked() ? oItem.download : ''; - })); -}; - -MessageViewMailBoxUserView.prototype.downloadAsZip = function() -{ - var - self = this, - aHashes = this.getAttachmentsHashes(); - - if (0 < aHashes.length) - { - Promises.attachmentsActions('Zip', aHashes, this.downloadAsZipLoading).then(function(oResult) { - if (oResult && oResult.Result && oResult.Result.Files && - oResult.Result.Files[0] && oResult.Result.Files[0].Hash) - { - require('App/User').default.download( - Links.attachmentDownload(oResult.Result.Files[0].Hash)); - } - else - { - self.downloadAsZipError(true); - } - }).catch(function() { - self.downloadAsZipError(true); - }); - } - else - { - this.highlightUnselectedAttachments(true); - } -}; - -MessageViewMailBoxUserView.prototype.saveToOwnCloud = function() -{ - var - self = this, - aHashes = this.getAttachmentsHashes(); - - if (0 < aHashes.length) - { - Promises.attachmentsActions('OwnCloud', aHashes, this.saveToOwnCloudLoading).then(function(oResult) { - if (oResult && oResult.Result) - { - self.saveToOwnCloudSuccess(true); - } - else - { - self.saveToOwnCloudError(true); - } - }).catch(function() { - self.saveToOwnCloudError(true); - }); - } - else - { - this.highlightUnselectedAttachments(true); - } -}; - -MessageViewMailBoxUserView.prototype.saveToDropbox = function() -{ - var - self = this, - aFiles = [], - aHashes = this.getAttachmentsHashes(); - - if (0 < aHashes.length) - { - if (window.Dropbox) - { - Promises.attachmentsActions('Dropbox', aHashes, this.saveToDropboxLoading).then(function(oResult) { - if (oResult && oResult.Result && oResult.Result.Url && oResult.Result.ShortLife && oResult.Result.Files) - { - if (window.Dropbox && Utils.isArray(oResult.Result.Files)) - { - _.each(oResult.Result.Files, function(oItem) { - aFiles.push({ - 'url': oResult.Result.Url + - Links.attachmentDownload(oItem.Hash, oResult.Result.ShortLife), - 'filename': oItem.FileName - }); - }); - - window.Dropbox.save({ - 'files': aFiles, - 'progress': function() { - self.saveToDropboxLoading(true); - self.saveToDropboxError(false); - self.saveToDropboxSuccess(false); - }, - 'cancel': function() { - self.saveToDropboxSuccess(false); - self.saveToDropboxError(false); - self.saveToDropboxLoading(false); - }, - 'success': function() { - self.saveToDropboxSuccess(true); - self.saveToDropboxLoading(false); - }, - 'error': function() { - self.saveToDropboxError(true); - self.saveToDropboxLoading(false); - } - }); - } - else - { - self.saveToDropboxError(true); - } - } - }).catch(function() { - self.saveToDropboxError(true); - }); - } - } - else - { - this.highlightUnselectedAttachments(true); - } -}; - -/** - * @param {MessageModel} oMessage - * @returns {void} - */ -MessageViewMailBoxUserView.prototype.showImages = function(oMessage) -{ - if (oMessage && oMessage.showExternalImages) - { - oMessage.showExternalImages(true); - } - - this.checkHeaderHeight(); -}; - -/** - * @returns {string} - */ -MessageViewMailBoxUserView.prototype.printableCheckedMessageCount = function() -{ - var iCnt = this.messageListCheckedOrSelectedUidsWithSubMails().length; - return 0 < iCnt ? (100 > iCnt ? iCnt : '99+') : ''; // eslint-disable-line no-magic-numbers -}; - -/** - * @param {MessageModel} oMessage - * @returns {void} - */ -MessageViewMailBoxUserView.prototype.readReceipt = function(oMessage) -{ - if (oMessage && '' !== oMessage.readReceipt()) - { - Remote.sendReadReceiptMessage(Utils.noop, oMessage.folderFullNameRaw, oMessage.uid, - oMessage.readReceipt(), - Translator.i18n('READ_RECEIPT/SUBJECT', {'SUBJECT': oMessage.subject()}), - Translator.i18n('READ_RECEIPT/BODY', {'READ-RECEIPT': AccountStore.email()})); - - oMessage.isReadReceipt(true); - - Cache.storeMessageFlagsToCache(oMessage); - - require('App/User').default.reloadFlagsCurrentMessageListAndMessageFromCache(); - } - - this.checkHeaderHeight(); -}; - -module.exports = MessageViewMailBoxUserView; +export {MessageViewMailBoxUserView, MessageViewMailBoxUserView as default}; diff --git a/dev/View/User/MailBox/SystemDropDown.js b/dev/View/User/MailBox/SystemDropDown.js index 6f071b422..94b7b3257 100644 --- a/dev/View/User/MailBox/SystemDropDown.js +++ b/dev/View/User/MailBox/SystemDropDown.js @@ -1,21 +1,10 @@ -var - _ = require('_'), +import {view} from 'Knoin/Knoin'; +import {AbstractSystemDropDownUserView} from 'View/User/AbstractSystemDropDown'; - kn = require('Knoin/Knoin'), - AbstractSystemDropDownViewModel = require('View/User/AbstractSystemDropDown'); +@view({ + name: 'View/User/MailBox/SystemDropDown' +}) +class SystemDropDownMailBoxUserView extends AbstractSystemDropDownUserView {} -/** - * @constructor - * @extends AbstractSystemDropDownViewModel - */ -function SystemDropDownMailBoxUserView() -{ - AbstractSystemDropDownViewModel.call(this); - kn.constructorEnd(this); -} - -kn.extendAsViewModel(['View/User/MailBox/SystemDropDown', 'View/App/MailBox/SystemDropDown', 'MailBoxSystemDropDownViewModel'], SystemDropDownMailBoxUserView); -_.extend(SystemDropDownMailBoxUserView.prototype, AbstractSystemDropDownViewModel.prototype); - -module.exports = SystemDropDownMailBoxUserView; +export {SystemDropDownMailBoxUserView, SystemDropDownMailBoxUserView as default}; diff --git a/dev/View/User/Settings/Menu.js b/dev/View/User/Settings/Menu.js index a475991ca..7b0b9747b 100644 --- a/dev/View/User/Settings/Menu.js +++ b/dev/View/User/Settings/Menu.js @@ -1,85 +1,81 @@ -var - _ = require('_'), - $ = require('$'), - key = require('key'), +import _ from '_'; +import $ from '$'; +import key from 'key'; - Enums = require('Common/Enums'), - Globals = require('Common/Globals'), - Links = require('Common/Links'), +import {KeyState, Magics} from 'Common/Enums'; +import {leftPanelDisabled} from 'Common/Globals'; +import {settings, inbox} from 'Common/Links'; +import {getFolderInboxName} from 'Common/Cache'; - Cache = require('Common/Cache'), - Settings = require('Storage/Settings'), +import * as Settings from 'Storage/Settings'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType, setHash} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @param {Object} oScreen - */ -function MenuSettingsUserView(oScreen) +@view({ + name: 'View/User/Settings/Menu', + type: ViewType.Left, + templateID: 'SettingsMenu' +}) +class MenuSettingsUserView extends AbstractViewNext { - AbstractView.call(this, 'Left', 'SettingsMenu'); + /** + * @param {Object} screen + */ + constructor(screen) { + super(); - this.leftPanelDisabled = Globals.leftPanelDisabled; + this.leftPanelDisabled = leftPanelDisabled; - this.mobile = Settings.appSettingsGet('mobile'); + this.mobile = Settings.appSettingsGet('mobile'); - this.menu = oScreen.menu; - - kn.constructorEnd(this); -} - -kn.extendAsViewModel(['View/User/Settings/Menu', 'View/App/Settings/Menu', 'SettingsMenuViewModel'], MenuSettingsUserView); -_.extend(MenuSettingsUserView.prototype, AbstractView.prototype); - -MenuSettingsUserView.prototype.onBuild = function(oDom) -{ - if (this.mobile) - { - oDom - .on('click', '.b-settings-menu .e-item.selectable', function() { - Globals.leftPanelDisabled(true); - }); + this.menu = screen.menu; } - key('up, down', Enums.KeyState.Settings, _.throttle(function(event, handler) { - - var - bUp = handler && 'up' === handler.shortcut, - $items = $('.b-settings-menu .e-item', oDom); - - if (event && $items.length) + onBuild(dom) { + if (this.mobile) { - var iIndex = $items.index($items.filter('.selected')); - if (bUp && 0 < iIndex) - { - iIndex -= 1; - } - else if (!bUp && iIndex < $items.length - 1) - { - iIndex += 1; - } - - var sH = $items.eq(iIndex).attr('href'); - if (sH) - { - kn.setHash(sH, false, true); - } + dom.on('click', '.b-settings-menu .e-item.selectable', () => { + leftPanelDisabled(true); + }); } - }, 200)); // eslint-disable-line no-magic-numbers -}; + key('up, down', KeyState.Settings, _.throttle((event, handler) => { -MenuSettingsUserView.prototype.link = function(sRoute) -{ - return Links.settings(sRoute); -}; + const + up = handler && 'up' === handler.shortcut, + $items = $('.b-settings-menu .e-item', dom); -MenuSettingsUserView.prototype.backToMailBoxClick = function() -{ - kn.setHash(Links.inbox(Cache.getFolderInboxName())); -}; + if (event && $items.length) + { + let iIndex = $items.index($items.filter('.selected')); + if (up && 0 < iIndex) + { + iIndex -= 1; + } + else if (!up && iIndex < $items.length - 1) + { + iIndex += 1; + } -module.exports = MenuSettingsUserView; + const sH = $items.eq(iIndex).attr('href'); + if (sH) + { + setHash(sH, false, true); + } + } + + }, Magics.Time200ms)); + } + + link(sRoute) { + return settings(sRoute); + } + + backToMailBoxClick() { + setHash(inbox(getFolderInboxName())); + } +} + +export {MenuSettingsUserView, MenuSettingsUserView as default}; diff --git a/dev/View/User/Settings/Pane.js b/dev/View/User/Settings/Pane.js index f1d2aa248..878fbaa62 100644 --- a/dev/View/User/Settings/Pane.js +++ b/dev/View/User/Settings/Pane.js @@ -1,68 +1,60 @@ -var - _ = require('_'), +import {inbox} from 'Common/Links'; +import {getFolderInboxName} from 'Common/Cache'; +import {leftPanelDisabled} from 'Common/Globals'; - Globals = require('Common/Globals'), +import * as Settings from 'Storage/Settings'; - Settings = require('Storage/Settings'), +import MessageStore from 'Stores/User/Message'; - kn = require('Knoin/Knoin'), - AbstractView = require('Knoin/AbstractView'); +import {view, ViewType, setHash} from 'Knoin/Knoin'; +import {AbstractViewNext} from 'Knoin/AbstractViewNext'; -/** - * @constructor - * @extends AbstractView - */ -function PaneSettingsUserView() +@view({ + name: 'View/User/Settings/Pane', + type: ViewType.Right, + templateID: 'SettingsPane' +}) +class PaneSettingsUserView extends AbstractViewNext { - AbstractView.call(this, 'Right', 'SettingsPane'); + constructor() { + super(); - this.mobile = Settings.appSettingsGet('mobile'); + this.mobile = Settings.appSettingsGet('mobile'); - this.leftPanelDisabled = Globals.leftPanelDisabled; + this.leftPanelDisabled = leftPanelDisabled; + } - kn.constructorEnd(this); + onShow() { + MessageStore.message(null); + } + + hideLeft(oItem, oEvent) { + oEvent.preventDefault(); + oEvent.stopPropagation(); + + leftPanelDisabled(true); + } + + showLeft(oItem, oEvent) { + oEvent.preventDefault(); + oEvent.stopPropagation(); + + leftPanelDisabled(false); + } + + onBuild(dom) { + if (this.mobile) + { + dom.on('click', () => { + leftPanelDisabled(true); + }); + } + } + + backToMailBoxClick() { + setHash(inbox(getFolderInboxName())); + } } -kn.extendAsViewModel(['View/User/Settings/Pane', 'View/App/Settings/Pane', 'SettingsPaneViewModel'], PaneSettingsUserView); -_.extend(PaneSettingsUserView.prototype, AbstractView.prototype); - -PaneSettingsUserView.prototype.onShow = function() -{ - require('Stores/User/Message').message(null); -}; - -PaneSettingsUserView.prototype.hideLeft = function(oItem, oEvent) -{ - oEvent.preventDefault(); - oEvent.stopPropagation(); - - Globals.leftPanelDisabled(true); -}; - -PaneSettingsUserView.prototype.showLeft = function(oItem, oEvent) -{ - oEvent.preventDefault(); - oEvent.stopPropagation(); - - Globals.leftPanelDisabled(false); -}; - -PaneSettingsUserView.prototype.onBuild = function(oDom) -{ - if (this.mobile) - { - oDom - .on('click', function() { - Globals.leftPanelDisabled(true); - }); - } -}; - -PaneSettingsUserView.prototype.backToMailBoxClick = function() -{ - kn.setHash(require('Common/Links').inbox( - require('Common/Cache').getFolderInboxName())); -}; - -module.exports = PaneSettingsUserView; +export {PaneSettingsUserView, PaneSettingsUserView as default}; diff --git a/dev/View/User/Settings/SystemDropDown.js b/dev/View/User/Settings/SystemDropDown.js index 78c6901c3..67b39ae18 100644 --- a/dev/View/User/Settings/SystemDropDown.js +++ b/dev/View/User/Settings/SystemDropDown.js @@ -1,21 +1,10 @@ -var - _ = require('_'), +import {view} from 'Knoin/Knoin'; +import {AbstractSystemDropDownUserView} from 'View/User/AbstractSystemDropDown'; - kn = require('Knoin/Knoin'), - AbstractSystemDropDownUserView = require('View/User/AbstractSystemDropDown'); +@view({ + name: 'View/User/Settings/SystemDropDown' +}) +class SystemDropDownSettingsUserView extends AbstractSystemDropDownUserView {} -/** - * @constructor - * @extends AbstractSystemDropDownUserView - */ -function SystemDropDownSettingsUserView() -{ - AbstractSystemDropDownUserView.call(this); - kn.constructorEnd(this); -} - -kn.extendAsViewModel(['View/User/Settings/SystemDropDown', 'View/App/Settings/SystemDropDown', 'SettingsSystemDropDownViewModel'], SystemDropDownSettingsUserView); -_.extend(SystemDropDownSettingsUserView.prototype, AbstractSystemDropDownUserView.prototype); - -module.exports = SystemDropDownSettingsUserView; +export {SystemDropDownSettingsUserView, SystemDropDownSettingsUserView as default}; diff --git a/dev/boot.js b/dev/boot.js index dfc668456..2fb116e85 100644 --- a/dev/boot.js +++ b/dev/boot.js @@ -3,9 +3,7 @@ import window from 'window'; import {Promise} from 'es6-promise-polyfill/promise.js'; import {progressJs} from '../node_modules/Progress.js/src/progress.js'; -import {jassl} from 'jassl'; -window.jassl = jassl; window.Promise = window.Promise || Promise; window.progressJs = window.progressJs || progressJs(); @@ -25,7 +23,6 @@ window.progressJs.onbeforeend(() => { require('json3'); require('../vendors/modernizr/modernizr-custom.js'); - require('Common/Booter'); if (window.__runBoot) diff --git a/dev/bootstrap.js b/dev/bootstrap.js index 074c755de..a93ac862a 100644 --- a/dev/bootstrap.js +++ b/dev/bootstrap.js @@ -1,7 +1,7 @@ import window from 'window'; import $ from '$'; -import {killCtrlACtrlS, detectDropdownVisibility, createCommand} from 'Common/Utils'; +import {killCtrlACtrlS, detectDropdownVisibility, createCommandLegacy} from 'Common/Utils'; import {$win, $html, data as GlobalsData, bMobileDevice} from 'Common/Globals'; import * as Enums from 'Common/Enums'; import * as Plugins from 'Common/Plugins'; @@ -27,7 +27,7 @@ export default (App) => { const rl = window.rl || {}; rl.i18n = i18n; - rl.createCommand = createCommand; + rl.createCommand = createCommandLegacy; rl.addSettingsViewModel = Plugins.addSettingsViewModel; rl.addSettingsViewModelForAdmin = Plugins.addSettingsViewModelForAdmin; diff --git a/gulpfile.js b/gulpfile.js index 37429ba36..8a3c861fe 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -52,37 +52,12 @@ var cache = require('gulp-cached'), ignore = require('gulp-ignore'), filter = require('gulp-filter'), - gutil = require('gulp-util') -; + gutil = require('gulp-util'); cfg.community = !argv.pro; cfg.next = !!argv.next; // webpack -function initWebpackCfg(wpCfg) -{ - if (wpCfg) - { - if (wpCfg.output) - { - wpCfg.output.publicPath = cfg.paths.staticJS; - } - - if (wpCfg.plugins) - { - wpCfg.plugins.push(new webpack.DefinePlugin({ - 'RL_COMMUNITY': cfg.community, - 'RL_ES6': cfg.next, - 'process.env': { - NODE_ENV: '"production"' - } - })); - } - } - - return wpCfg; -} - function webpackCallback(callback) { return function(err, stats) { @@ -185,8 +160,7 @@ function signFileTask(callback) { } }; -cfg.paths.globall = 'dev/**/*.{js,html,css}'; -cfg.paths.globjs = 'dev/**/*.{js}'; +cfg.paths.globjs = 'dev/**/*.js'; cfg.paths.static = 'rainloop/v/' + cfg.devVersion + '/static/'; cfg.paths.staticJS = 'rainloop/v/' + cfg.devVersion + '/static/js/'; cfg.paths.staticMinJS = 'rainloop/v/' + cfg.devVersion + '/static/js/min/'; @@ -235,18 +209,6 @@ cfg.paths.css = { }; cfg.paths.js = { - openpgp: { - name: 'openpgp.min.js', - src: [ - 'node_modules/openpgp/dist/openpgp.min.js' - ] - }, - openpgpworker: { - name: 'openpgp.worker.min.js', - src: [ - 'node_modules/openpgp/dist/openpgp.worker.min.js' - ] - }, moment: { locales: [ 'node_modules/moment/locale/*.js' @@ -358,20 +320,6 @@ gulp.task('css:social:min', ['css:social'], function() { gulp.task('css:min', ['css:main:min', 'css:social:min']); // JS -gulp.task('js:openpgp', function() { - return gulp.src(cfg.paths.js.openpgp.src) - .pipe(rename(cfg.paths.js.openpgp.name)) - .pipe(eol('\n', true)) - .pipe(gulp.dest(cfg.paths.staticMinJS)); -}); - -gulp.task('js:openpgpworker', function() { - return gulp.src(cfg.paths.js.openpgpworker.src) - .pipe(rename(cfg.paths.js.openpgpworker.name)) - .pipe(eol('\n', true)) - .pipe(gulp.dest(cfg.paths.staticMinJS)); -}); - gulp.task('moment:locales-clear', function() { return cleanDir('rainloop/v/' + cfg.devVersion + '/app/localization/moment/*.js'); }); @@ -405,13 +353,13 @@ gulp.task('js:clean', function() { }); gulp.task('js:webpack:main', function(callback) { - webpack(initWebpackCfg(webpackCfgBuilder()), webpackCallback(callback)); + webpack(webpackCfgBuilder(cfg.paths.staticJS, !cfg.community, false), webpackCallback(callback)); }); gulp.task('js:webpack:next', function(callback) { if (cfg.next) { - webpack(initWebpackCfg(webpackCfgBuilder(true)), webpackCallback(callback)); + webpack(webpackCfgBuilder(cfg.paths.staticJS, !cfg.community, true), webpackCallback(callback)); } else { @@ -438,7 +386,7 @@ gulp.task('js:admin', ['js:webpack'], function() { }); // - min -gulp.task('js:min', ['js:app', 'js:admin', 'js:validate'], function() { +gulp.task('js:min', ['js:app', 'js:admin'], function() { return gulp.src(cfg.paths.staticJS + '*.js') .pipe(ignore.exclude('*.next.js')) .pipe(replace(/"rainloop\/v\/([^\/]+)\/static\/js\/"/g, '"rainloop/v/$1/static/js/min/"')) @@ -464,7 +412,7 @@ gulp.task('js:eslint', function() { gulp.task('js:validate', ['js:eslint']); -// OTHER +// other gulp.task('lightgallery-fonts:clear', function() { return cleanDir('rainloop/v/' + cfg.devVersion + '/static/css/fonts/lg.*'); }); @@ -516,7 +464,7 @@ gulp.task('ckeditor', ['ckeditor:copy-plugins'], function () { .pipe(gulp.dest('rainloop/v/' + cfg.devVersion + '/static/ckeditor')); }); -// BUILD (RainLoop) +// build (RainLoop) gulp.task('rainloop:copy', ['default'], function() { var @@ -552,7 +500,7 @@ gulp.task('rainloop:setup', ['rainloop:copy'], function() { if (cfg.community) { - require('rimraf').sync(dist + 'rainloop/v/' + versionFull + '/app/libraries/RainLoop/Prem/'); + require('rimraf').sync(dist + 'rainloop/v/' + versionFull + '/app/libraries/RainLoop/Providers/Prem.php'); } cfg.destPath = cfg.releasesPath + '/webmail/' + versionFull + '/'; @@ -579,7 +527,7 @@ gulp.task('rainloop:shortname', ['rainloop:zip'], function(callback) { gulp.task('rainloop:sign', ['rainloop:shortname'], signFileTask); -// BUILD (OwnCloud) +// build (OwnCloud) gulp.task('rainloop:owncloud:copy', function() { var @@ -652,23 +600,15 @@ gulp.task('rainloop:owncloud:shortname', ['rainloop:owncloud:zip'], function(cal gulp.task('rainloop:owncloud:sign', ['rainloop:owncloud:shortname'], signFileTask); -// MAIN +// main gulp.task('moment', ['moment:locales']); -gulp.task('openpgp', ['js:openpgp', 'js:openpgpworker']); - -gulp.task('js', ['js:libs', 'js:min']); +gulp.task('js', ['js:libs', 'js:min', 'js:validate']); gulp.task('css', ['css:min']); -gulp.task('vendors', ['moment', 'openpgp', 'ckeditor', 'fontastic', 'lightgallery']); +gulp.task('vendors', ['moment', 'ckeditor', 'fontastic', 'lightgallery']); gulp.task('clean', ['js:clean', 'css:clean']); -gulp.task('default', function(callback) { - runSequence('clean', ['js', 'css', 'vendors'], callback); -}); - -gulp.task('fast', ['js:app', 'js:admin', 'css:main']); - gulp.task('rainloop:start', ['rainloop:copy', 'rainloop:setup']); gulp.task('rainloop', ['rainloop:start', 'rainloop:zip', 'rainloop:clean', 'rainloop:shortname', 'rainloop:sign']); @@ -677,24 +617,31 @@ gulp.task('owncloud', ['rainloop:owncloud:copy', 'rainloop:owncloud:copy-rainloop', 'rainloop:owncloud:copy-rainloop:clean', 'rainloop:owncloud:setup', 'rainloop:owncloud:zip', 'rainloop:owncloud:clean', 'rainloop:owncloud:shortname', 'rainloop:owncloud:sign']); -//WATCH -gulp.task('watch', ['fast'], function() { +// default +gulp.task('default', function(callback) { + runSequence('clean', ['js', 'css', 'vendors'], callback); +}); + +// watch +gulp.task('css:watch', ['css:main'], function() { cfg.watch = true; livereload.listen(); - gulp.watch(cfg.paths.globjs, {interval: cfg.watchInterval}, ['js:app', 'js:admin']); - gulp.watch(cfg.paths.globjs, {interval: cfg.watchInterval}, ['js:validate']); gulp.watch(cfg.paths.less.main.watch, {interval: cfg.watchInterval}, ['css:main']); }); -// ALIASES -gulp.task('build', ['rainloop']); +gulp.task('js:validate:watch', ['js:validate'], function() { + cfg.watch = true; + gulp.watch(cfg.paths.globjs, {interval: cfg.watchInterval}, ['js:validate']); +}); -gulp.task('js:v', ['js:validate']); -gulp.task('v', ['js:v']); +// aliases +gulp.task('build', ['rainloop']); +gulp.task('watch', ['css:watch', 'js:validate:watch']); gulp.task('d', ['default']); gulp.task('w', ['watch']); -gulp.task('f', ['fast']); +gulp.task('l', ['js:libs']); +gulp.task('v', ['js:validate']); gulp.task('b', ['build']); gulp.task('o', ['owncloud']); diff --git a/jsconfig.json b/jsconfig.json index c29daeb36..2e7f3b080 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -1,21 +1,22 @@ -{ - "compilerOptions": { - "target": "es2015", - "module": "commonjs", - "allowSyntheticDefaultImports": true - }, - "exclude": [ - "build", - "data", - "vendors", - "rainloop", - "plugins", - "node_modules", - "bower_components", - "jspm_packages", - "nbproject", - "tests", - "tmp", - "temp" - ] -} +{ + "compilerOptions": { + "target": "es2015", + "module": "commonjs", + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true + }, + "exclude": [ + "build", + "data", + "vendors", + "rainloop", + "plugins", + "node_modules", + "bower_components", + "jspm_packages", + "nbproject", + "tests", + "tmp", + "temp" + ] +} diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 9051f777b..b232fa62d 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,5 +1,5 @@ { - "name": "RainLoop", + "name": "rainloop", "version": "1.10.3", "dependencies": { "abbrev": { @@ -171,6 +171,11 @@ } } }, + "babel-eslint": { + "version": "6.1.2", + "from": "babel-eslint@>=6.1.2 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-6.1.2.tgz" + }, "babel-generator": { "version": "6.11.4", "from": "babel-generator@>=6.11.4 <7.0.0", @@ -247,9 +252,9 @@ "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.8.0.tgz" }, "babel-loader": { - "version": "6.2.4", - "from": "babel-loader@>=6.1.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-6.2.4.tgz" + "version": "6.2.5", + "from": "babel-loader@>=6.2.5 <7.0.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-6.2.5.tgz" }, "babel-messages": { "version": "6.8.0", @@ -278,7 +283,7 @@ }, "babel-plugin-syntax-decorators": { "version": "6.13.0", - "from": "babel-plugin-syntax-decorators@>=6.13.0 <7.0.0", + "from": "babel-plugin-syntax-decorators@>=6.1.18 <7.0.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz" }, "babel-plugin-syntax-do-expressions": { @@ -331,6 +336,11 @@ "from": "babel-plugin-transform-decorators@>=6.13.0 <7.0.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.13.0.tgz" }, + "babel-plugin-transform-decorators-legacy": { + "version": "1.3.4", + "from": "babel-plugin-transform-decorators-legacy@>=1.3.4 <2.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.4.tgz" + }, "babel-plugin-transform-do-expressions": { "version": "6.8.0", "from": "babel-plugin-transform-do-expressions@>=6.3.13 <7.0.0", @@ -544,9 +554,9 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.13.0.tgz" }, "babylon": { - "version": "6.8.4", + "version": "6.9.0", "from": "babylon@>=6.7.0 <7.0.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.8.4.tgz" + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.9.0.tgz" }, "balanced-match": { "version": "0.4.2", @@ -589,9 +599,9 @@ "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-1.0.1.tgz" }, "bluebird": { - "version": "3.4.1", - "from": "bluebird@>=3.1.1 <4.0.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.1.tgz" + "version": "2.10.2", + "from": "bluebird@>=2.10.2 <3.0.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.10.2.tgz" }, "bn.js": { "version": "4.11.6", @@ -666,9 +676,9 @@ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.3.5.tgz" }, "buffer": { - "version": "4.9.0", + "version": "4.9.1", "from": "buffer@>=4.3.0 <5.0.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.0.tgz", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "dependencies": { "isarray": { "version": "1.0.0", @@ -728,9 +738,9 @@ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz" }, "caniuse-db": { - "version": "1.0.30000520", + "version": "1.0.30000525", "from": "caniuse-db@>=1.0.30000515 <2.0.0", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000520.tgz" + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000525.tgz" }, "cardinal": { "version": "0.5.0", @@ -762,6 +772,11 @@ "from": "circular-json@>=0.3.0 <0.4.0", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz" }, + "classnames": { + "version": "2.2.5", + "from": "classnames@>=2.2.5 <3.0.0", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.5.tgz" + }, "clean-css": { "version": "3.4.19", "from": "clean-css@>=3.4.19 <4.0.0", @@ -838,6 +853,11 @@ "from": "commander@>=2.8.0 <2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz" }, + "commondir": { + "version": "1.0.1", + "from": "commondir@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz" + }, "concat-map": { "version": "0.0.1", "from": "concat-map@0.0.1", @@ -890,6 +910,11 @@ "from": "convert-source-map@>=1.1.0 <2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.3.0.tgz" }, + "copy-webpack-plugin": { + "version": "3.0.1", + "from": "copy-webpack-plugin@>=3.0.1 <4.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-3.0.1.tgz" + }, "core-js": { "version": "2.4.1", "from": "core-js@>=2.4.0 <3.0.0", @@ -961,9 +986,9 @@ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz" }, "del": { - "version": "2.2.1", + "version": "2.2.2", "from": "del@>=2.0.2 <3.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.1.tgz" + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz" }, "depd": { "version": "1.1.0", @@ -1003,15 +1028,10 @@ "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz" }, "doctrine": { - "version": "1.2.2", + "version": "1.2.3", "from": "doctrine@>=1.2.2 <2.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.2.2.tgz", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.2.3.tgz", "dependencies": { - "esutils": { - "version": "1.1.6", - "from": "esutils@>=1.1.6 <2.0.0", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz" - }, "isarray": { "version": "1.0.0", "from": "isarray@>=1.0.0 <2.0.0", @@ -1055,9 +1075,9 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "readable-stream": { - "version": "2.1.4", + "version": "2.1.5", "from": "readable-stream@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz" + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz" } } }, @@ -1147,9 +1167,9 @@ "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz" }, "eslint": { - "version": "3.2.2", + "version": "3.3.1", "from": "eslint@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.2.2.tgz", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.3.1.tgz", "dependencies": { "glob": { "version": "7.0.5", @@ -1173,6 +1193,11 @@ } } }, + "eslint-loader": { + "version": "1.5.0", + "from": "eslint-loader@>=1.5.0 <2.0.0", + "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-1.5.0.tgz" + }, "espree": { "version": "3.1.7", "from": "espree@>=3.1.6 <4.0.0", @@ -1290,6 +1315,11 @@ "from": "fill-range@>=2.1.0 <3.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz" }, + "find-cache-dir": { + "version": "0.1.1", + "from": "find-cache-dir@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz" + }, "find-index": { "version": "0.1.1", "from": "find-index@>=0.1.1 <0.2.0", @@ -1362,6 +1392,11 @@ "from": "fs-exists-sync@>=0.1.0 <0.2.0", "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz" }, + "fs-extra": { + "version": "0.26.7", + "from": "fs-extra@>=0.26.4 <0.27.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz" + }, "fs.realpath": { "version": "1.0.0", "from": "fs.realpath@>=1.0.0 <2.0.0", @@ -1393,16 +1428,9 @@ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz" }, "glob": { - "version": "4.5.3", - "from": "glob@>=4.3.1 <5.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "dependencies": { - "minimatch": { - "version": "2.0.10", - "from": "minimatch@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz" - } - } + "version": "6.0.4", + "from": "glob@>=6.0.4 <7.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz" }, "glob-base": { "version": "0.3.0", @@ -1419,6 +1447,11 @@ "from": "glob-stream@>=3.1.5 <4.0.0", "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", "dependencies": { + "glob": { + "version": "4.5.3", + "from": "glob@>=4.3.1 <5.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz" + }, "minimatch": { "version": "2.0.10", "from": "minimatch@>=2.0.1 <3.0.0", @@ -1511,9 +1544,9 @@ "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz" }, "graceful-fs": { - "version": "4.1.5", + "version": "4.1.6", "from": "graceful-fs@>=4.1.2 <5.0.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.5.tgz" + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.6.tgz" }, "graceful-readlink": { "version": "1.0.1", @@ -1527,7 +1560,7 @@ }, "gulp": { "version": "3.9.1", - "from": "gulp@>=3.9.0 <3.10.0", + "from": "gulp@>=3.9.1 <4.0.0", "resolved": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", "dependencies": { "semver": { @@ -1538,9 +1571,9 @@ } }, "gulp-autoprefixer": { - "version": "3.1.0", - "from": "gulp-autoprefixer@>=3.1.0 <4.0.0", - "resolved": "https://registry.npmjs.org/gulp-autoprefixer/-/gulp-autoprefixer-3.1.0.tgz" + "version": "3.1.1", + "from": "gulp-autoprefixer@>=3.1.1 <4.0.0", + "resolved": "https://registry.npmjs.org/gulp-autoprefixer/-/gulp-autoprefixer-3.1.1.tgz" }, "gulp-beautify": { "version": "2.0.0", @@ -1580,16 +1613,23 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "readable-stream": { - "version": "2.1.4", + "version": "2.1.5", "from": "readable-stream@>=2.1.4 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz" + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz" } } }, "gulp-concat-util": { "version": "0.5.5", "from": "gulp-concat-util@>=0.5.5 <0.6.0", - "resolved": "https://registry.npmjs.org/gulp-concat-util/-/gulp-concat-util-0.5.5.tgz" + "resolved": "https://registry.npmjs.org/gulp-concat-util/-/gulp-concat-util-0.5.5.tgz", + "dependencies": { + "lodash.assign": { + "version": "3.2.0", + "from": "lodash.assign@>=3.2.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz" + } + } }, "gulp-eol": { "version": "0.1.2", @@ -1713,15 +1753,15 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "readable-stream": { - "version": "2.1.4", + "version": "2.1.5", "from": "readable-stream@>=2.0.2 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz" + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz" } } }, "gulp-filter": { "version": "4.0.0", - "from": "gulp-filter@*", + "from": "gulp-filter@>=4.0.0 <5.0.0", "resolved": "https://registry.npmjs.org/gulp-filter/-/gulp-filter-4.0.0.tgz" }, "gulp-header": { @@ -1746,7 +1786,7 @@ }, "gulp-livereload": { "version": "3.8.1", - "from": "gulp-livereload@>=3.8.0 <3.9.0", + "from": "gulp-livereload@>=3.8.1 <4.0.0", "resolved": "https://registry.npmjs.org/gulp-livereload/-/gulp-livereload-3.8.1.tgz", "dependencies": { "ansi-regex": { @@ -1769,6 +1809,11 @@ "from": "has-ansi@>=0.1.0 <0.2.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz" }, + "lodash.assign": { + "version": "3.2.0", + "from": "lodash.assign@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz" + }, "strip-ansi": { "version": "0.3.0", "from": "strip-ansi@>=0.3.0 <0.4.0", @@ -1788,7 +1833,7 @@ }, "gulp-notify": { "version": "2.2.0", - "from": "gulp-notify@>=2.2.0 <2.3.0", + "from": "gulp-notify@>=2.2.0 <3.0.0", "resolved": "https://registry.npmjs.org/gulp-notify/-/gulp-notify-2.2.0.tgz", "dependencies": { "readable-stream": { @@ -1824,9 +1869,9 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "readable-stream": { - "version": "2.1.4", + "version": "2.1.5", "from": "readable-stream@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz" + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz" } } }, @@ -1865,12 +1910,26 @@ "gulp-through": { "version": "0.4.0", "from": "gulp-through@>=0.4.0 <0.5.0", - "resolved": "https://registry.npmjs.org/gulp-through/-/gulp-through-0.4.0.tgz" + "resolved": "https://registry.npmjs.org/gulp-through/-/gulp-through-0.4.0.tgz", + "dependencies": { + "bluebird": { + "version": "3.4.1", + "from": "bluebird@>=3.0.6 <4.0.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.1.tgz" + } + } }, "gulp-uglify": { "version": "2.0.0", "from": "gulp-uglify@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-2.0.0.tgz", + "dependencies": { + "uglify-js": { + "version": "2.7.0", + "from": "uglify-js@2.7.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.0.tgz" + } + } }, "gulp-util": { "version": "3.0.7", @@ -1955,9 +2014,9 @@ "resolved": "https://registry.npmjs.org/ifvisible.js/-/ifvisible.js-1.0.6.tgz" }, "ignore": { - "version": "3.1.3", + "version": "3.1.5", "from": "ignore@>=3.1.2 <4.0.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.1.3.tgz" + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.1.5.tgz" }, "image-size": { "version": "0.5.0", @@ -2193,14 +2252,9 @@ "from": "jasmine-reporters@>=0.2.1 <0.3.0", "resolved": "https://registry.npmjs.org/jasmine-reporters/-/jasmine-reporters-0.2.1.tgz" }, - "jassl": { - "version": "1.2.0", - "from": "rainloop/jassl", - "resolved": "git://github.com/rainloop/jassl.git#8243909fc281c2310e7ae854629c62a171c943c3" - }, "jquery": { "version": "2.2.4", - "from": "jquery@>=2.0.0 <3.0.0", + "from": "jquery@>=2.2.4 <3.0.0", "resolved": "https://registry.npmjs.org/jquery/-/jquery-2.2.4.tgz" }, "jquery-lazyload": { @@ -2273,6 +2327,11 @@ "from": "json5@>=0.4.0 <0.5.0", "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz" }, + "jsonfile": { + "version": "2.3.1", + "from": "jsonfile@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.3.1.tgz" + }, "jsonify": { "version": "0.0.0", "from": "jsonify@>=0.0.0 <0.1.0", @@ -2288,6 +2347,11 @@ "from": "kind-of@>=3.0.2 <4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.4.tgz" }, + "klaw": { + "version": "1.3.0", + "from": "klaw@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.0.tgz" + }, "knockout": { "version": "3.4.0", "from": "knockout@>=3.4.0 <4.0.0", @@ -2368,9 +2432,9 @@ } }, "lodash": { - "version": "4.14.2", + "version": "4.15.0", "from": "lodash@>=4.2.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.14.2.tgz" + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.15.0.tgz" }, "lodash._arraycopy": { "version": "3.0.0", @@ -2495,19 +2559,19 @@ "resolved": "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz" }, "lodash.assign": { - "version": "3.2.0", - "from": "lodash.assign@>=3.2.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz" + "version": "4.2.0", + "from": "lodash.assign@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz" }, "lodash.assignwith": { - "version": "4.1.0", + "version": "4.2.0", "from": "lodash.assignwith@>=4.0.7 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash.assignwith/-/lodash.assignwith-4.1.0.tgz" + "resolved": "https://registry.npmjs.org/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz" }, "lodash.clonedeep": { - "version": "4.4.1", + "version": "4.5.0", "from": "lodash.clonedeep@>=4.3.2 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.4.1.tgz" + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz" }, "lodash.defaults": { "version": "2.4.1", @@ -2527,9 +2591,9 @@ "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz" }, "lodash.isarguments": { - "version": "3.0.9", + "version": "3.1.0", "from": "lodash.isarguments@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.9.tgz" + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz" }, "lodash.isarray": { "version": "3.0.4", @@ -2537,9 +2601,9 @@ "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" }, "lodash.isempty": { - "version": "4.3.1", + "version": "4.4.0", "from": "lodash.isempty@>=4.2.1 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.3.1.tgz" + "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz" }, "lodash.isobject": { "version": "2.4.1", @@ -2547,9 +2611,9 @@ "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz" }, "lodash.isplainobject": { - "version": "4.0.5", + "version": "4.0.6", "from": "lodash.isplainobject@>=4.0.4 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.5.tgz" + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" }, "lodash.isstring": { "version": "4.0.1", @@ -2562,14 +2626,19 @@ "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz" }, "lodash.mapvalues": { - "version": "4.5.1", + "version": "4.6.0", "from": "lodash.mapvalues@>=4.4.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.5.1.tgz" + "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz" }, "lodash.pick": { - "version": "4.3.0", + "version": "4.4.0", "from": "lodash.pick@>=4.2.1 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.3.0.tgz" + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz" + }, + "lodash.pickby": { + "version": "4.6.0", + "from": "lodash.pickby@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz" }, "lodash.restparam": { "version": "3.6.1", @@ -2663,7 +2732,14 @@ "marked-terminal": { "version": "1.6.1", "from": "marked-terminal@>=1.6.1 <2.0.0", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-1.6.1.tgz" + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-1.6.1.tgz", + "dependencies": { + "lodash.assign": { + "version": "3.2.0", + "from": "lodash.assign@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz" + } + } }, "matchmedia-polyfill": { "version": "0.3.0", @@ -2686,9 +2762,9 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "readable-stream": { - "version": "2.1.4", + "version": "2.1.5", "from": "readable-stream@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz" + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz" } } }, @@ -2708,9 +2784,9 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "readable-stream": { - "version": "2.1.4", + "version": "2.1.5", "from": "readable-stream@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz" + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz" } } }, @@ -2796,6 +2872,16 @@ "from": "mute-stream@0.0.5", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz" }, + "natural-compare": { + "version": "1.4.0", + "from": "natural-compare@>=1.4.0 <2.0.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + }, + "node-dir": { + "version": "0.1.16", + "from": "node-dir@>=0.1.10 <0.2.0", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.16.tgz" + }, "node-emoji": { "version": "0.1.0", "from": "node-emoji@>=0.1.0 <0.2.0", @@ -2822,16 +2908,16 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "readable-stream": { - "version": "2.1.4", + "version": "2.1.5", "from": "readable-stream@>=2.0.5 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz" + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz" } } }, "node-localstorage": { - "version": "1.1.2", - "from": "node-localstorage@>=1.1.2 <1.2.0", - "resolved": "https://registry.npmjs.org/node-localstorage/-/node-localstorage-1.1.2.tgz" + "version": "1.3.0", + "from": "node-localstorage@>=1.3.0 <1.4.0", + "resolved": "https://registry.npmjs.org/node-localstorage/-/node-localstorage-1.3.0.tgz" }, "node-notifier": { "version": "4.6.0", @@ -2907,7 +2993,7 @@ }, "once": { "version": "1.3.3", - "from": "once@>=1.3.0 <1.4.0", + "from": "once@>=1.3.0 <2.0.0", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz" }, "onetime": { @@ -2916,9 +3002,9 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz" }, "openpgp": { - "version": "2.3.2", - "from": "openpgp@>=2.3.2 <3.0.0", - "resolved": "https://registry.npmjs.org/openpgp/-/openpgp-2.3.2.tgz" + "version": "2.3.3", + "from": "openpgp@>=2.3.3 <3.0.0", + "resolved": "https://registry.npmjs.org/openpgp/-/openpgp-2.3.3.tgz" }, "opentip": { "version": "2.4.3", @@ -3060,6 +3146,11 @@ "from": "pinkie-promise@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" }, + "pkg-dir": { + "version": "1.0.0", + "from": "pkg-dir@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz" + }, "pluralize": { "version": "1.2.1", "from": "pluralize@>=1.2.1 <2.0.0", @@ -3237,9 +3328,9 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "readable-stream": { - "version": "2.1.4", + "version": "2.1.5", "from": "readable-stream@>=2.0.2 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz" + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz" } } }, @@ -3336,9 +3427,9 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz" }, "readable-stream": { - "version": "2.1.4", + "version": "2.1.5", "from": "readable-stream@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz" + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz" } } }, @@ -3416,7 +3507,7 @@ }, "run-sequence": { "version": "1.2.2", - "from": "run-sequence@*", + "from": "run-sequence@>=1.2.2 <2.0.0", "resolved": "https://registry.npmjs.org/run-sequence/-/run-sequence-1.2.2.tgz" }, "rx-lite": { @@ -3489,6 +3580,11 @@ "from": "slice-ansi@0.0.4", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz" }, + "slide": { + "version": "1.1.6", + "from": "slide@>=1.1.5 <2.0.0", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz" + }, "source-list-map": { "version": "0.1.6", "from": "source-list-map@>=0.1.0 <0.2.0", @@ -3562,9 +3658,9 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "readable-stream": { - "version": "2.1.4", + "version": "2.1.5", "from": "readable-stream@>=2.0.2 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz" + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz" } } }, @@ -3589,9 +3685,9 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "readable-stream": { - "version": "2.1.4", + "version": "2.1.5", "from": "readable-stream@>=2.0.2 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz" + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz" } } }, @@ -3616,9 +3712,9 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "readable-stream": { - "version": "2.1.4", + "version": "2.1.5", "from": "readable-stream@>=2.0.2 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz" + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz" } } }, @@ -3628,9 +3724,9 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" }, "string-width": { - "version": "1.0.1", + "version": "1.0.2", "from": "string-width@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" }, "strip-ansi": { "version": "3.0.1", @@ -3652,6 +3748,11 @@ "from": "strip-json-comments@>=1.0.1 <1.1.0", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz" }, + "style-loader": { + "version": "0.13.1", + "from": "style-loader@>=0.13.1 <0.14.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.13.1.tgz" + }, "supports-color": { "version": "2.0.0", "from": "supports-color@>=2.0.0 <3.0.0", @@ -3660,7 +3761,14 @@ "table": { "version": "3.7.8", "from": "table@>=3.7.8 <4.0.0", - "resolved": "https://registry.npmjs.org/table/-/table-3.7.8.tgz" + "resolved": "https://registry.npmjs.org/table/-/table-3.7.8.tgz", + "dependencies": { + "bluebird": { + "version": "3.4.1", + "from": "bluebird@>=3.1.1 <4.0.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.1.tgz" + } + } }, "tapable": { "version": "0.2.4", @@ -3720,9 +3828,9 @@ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz" }, "tinycon": { - "version": "0.6.5", + "version": "0.6.6", "from": "tommoor/tinycon", - "resolved": "git://github.com/tommoor/tinycon.git#27158e7ace699c6ebd4600aa7c872548268dcc8a" + "resolved": "git://github.com/tommoor/tinycon.git#83e7ef5765f1b29e1abeee6262f9b5b3f9242c24" }, "to-fast-properties": { "version": "1.0.2", @@ -3765,9 +3873,9 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" }, "uglify-js": { - "version": "2.7.0", + "version": "2.7.3", "from": "uglify-js@>=2.6.0 <3.0.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.0.tgz" + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.3.tgz" }, "uglify-save-license": { "version": "0.4.1", @@ -3857,9 +3965,9 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz" }, "graceful-fs": { - "version": "3.0.8", + "version": "3.0.9", "from": "graceful-fs@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz" + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.9.tgz" }, "readable-stream": { "version": "1.0.34", @@ -3906,9 +4014,9 @@ } }, "webpack": { - "version": "2.1.0-beta.20", - "from": "webpack@>=2.1.0-beta.20 <3.0.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-2.1.0-beta.20.tgz", + "version": "2.1.0-beta.21", + "from": "webpack@>=2.1.0-beta.21 <3.0.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-2.1.0-beta.21.tgz", "dependencies": { "async": { "version": "1.5.2", @@ -3920,11 +4028,6 @@ "from": "camelcase@>=1.0.2 <2.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz" }, - "lodash.assign": { - "version": "4.1.0", - "from": "lodash.assign@>=4.0.3 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.1.0.tgz" - }, "supports-color": { "version": "3.1.2", "from": "supports-color@>=3.1.0 <4.0.0", @@ -3964,6 +4067,11 @@ } } }, + "webpack-notifier": { + "version": "1.3.2", + "from": "webpack-notifier@>=1.3.2 <2.0.0", + "resolved": "https://registry.npmjs.org/webpack-notifier/-/webpack-notifier-1.3.2.tgz" + }, "webpack-sources": { "version": "0.1.2", "from": "webpack-sources@>=0.1.0 <0.2.0", @@ -4019,6 +4127,11 @@ "from": "write@>=0.2.1 <0.3.0", "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz" }, + "write-file-atomic": { + "version": "1.2.0", + "from": "write-file-atomic@>=1.1.4 <2.0.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.2.0.tgz" + }, "xregexp": { "version": "3.1.1", "from": "xregexp@>=3.0.0 <4.0.0", @@ -4055,11 +4168,6 @@ "version": "3.0.0", "from": "camelcase@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz" - }, - "lodash.assign": { - "version": "4.1.0", - "from": "lodash.assign@>=4.0.6 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.1.0.tgz" } } }, diff --git a/package.json b/package.json index 738ea9eac..58fdff633 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { - "name": "RainLoop", + "name": "rainloop", "title": "RainLoop Webmail", - "version": "1.10.3", - "release": "151", - "ownCloudPackageVersion": "4.23", - "private": true, "description": "Simple, modern & fast web-based email client", + "private": true, + "version": "1.10.3", + "release": "155", + "ownCloudPackageVersion": "4.23", "homepage": "http://rainloop.net", "main": "gulpfile.js", "author": { @@ -40,6 +40,7 @@ "web-based", "email", "client", + "openpgp", "plugins" ], "readmeFilename": "README.md", @@ -50,15 +51,19 @@ "Progress.js": "github:usablica/progress.js", "autolinker": "^0.27.0", "babel-core": "^6.13.2", - "babel-loader": "^6.1.0", + "babel-eslint": "^6.1.2", + "babel-loader": "^6.2.5", + "babel-plugin-transform-decorators-legacy": "^1.3.4", "babel-plugin-transform-runtime": "^6.9.0", "babel-preset-es2015": "^6.13.2", "babel-preset-es2016": "^6.11.3", "babel-preset-stage-0": "^6.5.0", "babel-runtime": "^6.1.18", + "classnames": "^2.2.5", + "copy-webpack-plugin": "^3.0.1", "es6-promise-polyfill": "^1.2.0", - "gulp": "~3.9.0", - "gulp-autoprefixer": "^3.1.0", + "gulp": "^3.9.1", + "gulp-autoprefixer": "^3.1.1", "gulp-beautify": "^2.0.0", "gulp-cached": "^1.1.0", "gulp-clean-css": "^2.0.7", @@ -70,8 +75,8 @@ "gulp-if": "^2.0.1", "gulp-ignore": "^2.0.1", "gulp-less": "^3.1.0", - "gulp-livereload": "~3.8.0", - "gulp-notify": "~2.2.0", + "gulp-livereload": "^3.8.1", + "gulp-notify": "^2.2.0", "gulp-plumber": "^1.1.0", "gulp-rename": "^1.2.2", "gulp-replace": "^0.5.4", @@ -82,8 +87,7 @@ "gulp-util": "^3.0.7", "gulp-zip": "^3.2.0", "ifvisible.js": "^1.0.6", - "jassl": "github:rainloop/jassl", - "jquery": "^2", + "jquery": "^2.2.4", "jquery-lazyload": "^1.9.7", "jquery-mousewheel": "^3.1.13", "jquery-scrollstop": "^1.2.0", @@ -100,7 +104,7 @@ "node-fs": "^0.1.7", "node-notifier": "^4.6.0", "normalize.css": "^4.2.0", - "openpgp": "^2.3.2", + "openpgp": "^2.3.3", "opentip": "^2.4.3", "pikaday": "^1.4.0", "raw-loader": "^0.5.1", @@ -108,8 +112,10 @@ "rimraf": "^2.5.4", "run-sequence": "^1.2.2", "simplestatemanager": "^3.1.3", + "style-loader": "^0.13.1", "tinycon": "github:tommoor/tinycon", "underscore": "^1.8.3", - "webpack": "^2.1.0-beta.20" + "webpack": "^2.1.0-beta.21", + "webpack-notifier": "^1.3.2" } } diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php b/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php index 0a3c96b94..f007b4069 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php @@ -1,1565 +1,1565 @@ -hasAttributes() && isset($oElement->attributes) && $oElement->attributes) - { - foreach ($oElement->attributes as $oAttr) - { - if ($oAttr && !empty($oAttr->nodeName)) - { - $sAttrName = \trim(\strtolower($oAttr->nodeName)); - $aResult[$sAttrName] = $oAttr->nodeValue; - } - } - } - } - - return $aResult; - } - - /** - * @param string $sText - * - * @return \DOMDocument|bool - */ - public static function GetDomFromText($sText) - { - $bState = true; - if (\MailSo\Base\Utils::FunctionExistsAndEnabled('libxml_use_internal_errors')) - { - $bState = \libxml_use_internal_errors(true); - } - - $sHtmlAttrs = $sBodyAttrs = ''; - - $sText = \MailSo\Base\HtmlUtils::FixSchemas($sText); - $sText = \MailSo\Base\HtmlUtils::ClearFastTags($sText); - $sText = \MailSo\Base\HtmlUtils::ClearBodyAndHtmlTag($sText, $sHtmlAttrs, $sBodyAttrs); - - $oDom = self::createDOMDocument(); - @$oDom->loadHTML('<'.'?xml version="1.0" encoding="utf-8"?'.'>'. - ''. - ''. - '
'.$sText.'
'); - - @$oDom->normalizeDocument(); - - if (\MailSo\Base\Utils::FunctionExistsAndEnabled('libxml_clear_errors')) - { - @\libxml_clear_errors(); - } - - if (\MailSo\Base\Utils::FunctionExistsAndEnabled('libxml_use_internal_errors')) - { - \libxml_use_internal_errors($bState); - } - - return $oDom; - } - - /** - * @return \DOMDocument - */ - private static function createDOMDocument() - { - $oDoc = new \DOMDocument('1.0', 'UTF-8'); - $oDoc->encoding = 'UTF-8'; - $oDoc->strictErrorChecking = false; - $oDoc->formatOutput = false; - $oDoc->preserveWhiteSpace = false; - - return $oDoc; - } - - /** - * @return boolean - */ - private static function comparedVersion() - { - return \version_compare(PHP_VERSION, '5.3.6') >= 0; - } - - /** - * @param \DOMDocument|\DOMElement $oElem - * - * @return type - */ - private static function domToString($oElem, $oDom = null) - { - $sResult = ''; - if ($oElem instanceof \DOMDocument) - { - if (isset($oElem->documentElement) && self::comparedVersion()) - { - $sResult = $oElem->saveHTML($oElem->documentElement); - } - else - { - $sResult = $oElem->saveHTML(); - } - } - else if ($oElem) - { - if ($oDom && self::comparedVersion()) - { - $sResult = $oDom->saveHTML($oElem); - } - else - { - $oTempDoc = self::createDOMDocument(); - $oTempDoc->appendChild($oTempDoc->importNode($oElem->cloneNode(true), true)); - $sResult = $oTempDoc->saveHTML(); - } - } - - return \trim($sResult); - } - - /** - * @param \DOMDocument $oDom - * @param bool $bWrapByFakeHtmlAndBodyDiv = true - * - * @return string - */ - public static function GetTextFromDom($oDom, $bWrapByFakeHtmlAndBodyDiv = true) - { - $sResult = ''; - - $aHtmlAttrs = $aBodylAttrs = array(); - if ($bWrapByFakeHtmlAndBodyDiv) - { - $oHtml = $oDom->getElementsByTagName('html')->item(0); - $oBody = $oDom->getElementsByTagName('body')->item(0); - - $aHtmlAttrs = \MailSo\Base\HtmlUtils::GetElementAttributesAsArray($oHtml); - $aBodylAttrs = \MailSo\Base\HtmlUtils::GetElementAttributesAsArray($oBody); - } - - $oDiv = $oDom->getElementsByTagName('div')->item(0); - if ($oDiv && $oDiv->hasAttribute('data-wrp') && 'rainloop' === $oDiv->getAttribute('data-wrp')) - { - $oDiv->removeAttribute('data-wrp'); - if ($bWrapByFakeHtmlAndBodyDiv) - { - $oWrap = $oDom->createElement('div'); - - $oWrap->setAttribute('data-x-div-type', 'html'); - foreach ($aHtmlAttrs as $sKey => $sValue) - { - $oWrap->setAttribute($sKey, $sValue); - } - - $oDiv->setAttribute('data-x-div-type', 'body'); - foreach ($aBodylAttrs as $sKey => $sValue) - { - $oDiv->setAttribute($sKey, $sValue); - } - - $oWrap->appendChild($oDiv); - $sResult = self::domToString($oWrap, $oDom); - } - else - { - $sResult = self::domToString($oDiv, $oDom); - if (0 === strpos($sResult, '
') && '
' === substr($sResult, -6)) - { - $sResult = substr($sResult, 5); - $sResult = substr($sResult, 0, -6); - $sResult = \trim($sResult); - } - } - } - else - { - $sResult = self::domToString($oDom); - } - - $sResult = \str_replace(\MailSo\Base\HtmlUtils::$KOS, ':', $sResult); - $sResult = \MailSo\Base\Utils::StripSpaces($sResult); - - return $sResult; - } - - /** - * @param string $sHtml - * @param string $sHtmlAttrs = ' - * @param string $sBodyAttrs = '' - * - * @return string - */ - public static function ClearBodyAndHtmlTag($sHtml, &$sHtmlAttrs = '', &$sBodyAttrs = '') - { - $aMatch = array(); - if (\preg_match('/]+)>/im', $sHtml, $aMatch) && !empty($aMatch[1])) - { - $sHtmlAttrs = $aMatch[1]; - } - - $aMatch = array(); - if (\preg_match('/]+)>/im', $sHtml, $aMatch) && !empty($aMatch[1])) - { - $sBodyAttrs = $aMatch[1]; - } - - $iPos = \stripos($sHtml, ''); - if (0 < $iPos) - { - $sHtml = \substr($sHtml, $iPos); - } - else - { - $iPos = \stripos($sHtml, ']*)>/si', '', $sHtml); - $sHtml = \preg_replace('/<\/body>/i', '', $sHtml); - $sHtml = \preg_replace('/]*)>/i', '', $sHtml); - $sHtml = \preg_replace('/<\/html>/i', '', $sHtml); - - $sHtmlAttrs = \preg_replace('/xmlns:[a-z]="[^"]*"/i', '', $sHtmlAttrs); - $sHtmlAttrs = \preg_replace('/xmlns="[^"]*"/i', '', $sHtmlAttrs); - $sBodyAttrs = \preg_replace('/xmlns:[a-z]="[^"]*"/i', '', $sBodyAttrs); - - return $sHtml; - } - - /** - * @param string $sHtml - * @param bool $bClearEmpty = true - * - * @return string - */ - public static function FixSchemas($sHtml, $bClearEmpty = true) - { - if ($bClearEmpty) - { - $sHtml = \str_replace('', '', $sHtml); - } - - $sHtml = \str_replace('', '', $sHtml); - $sHtml = \str_replace('', '', $sHtml); - - return $sHtml; - } - - /** - * @param string $sHtml - * - * @return string - */ - public static function ClearFastTags($sHtml) - { - return \preg_replace(array( - '/]*><\/p>/i', - '/]*>/i', - '/<\?xml [^>]*\?>/i' - ), '', $sHtml); - } - - /** - * @param mixed $oDom - */ - public static function ClearComments(&$oDom) - { - $aRemove = array(); - - $oXpath = new \DOMXpath($oDom); - $oComments = $oXpath->query('//comment()'); - if ($oComments) - { - foreach ($oComments as $oComment) - { - $aRemove[] = $oComment; - } - } - - unset($oXpath, $oComments); - - foreach ($aRemove as /* @var $oElement \DOMElement */ $oElement) - { - if (isset($oElement->parentNode)) - { - @$oElement->parentNode->removeChild($oElement); - } - } - } - - /** - * @param mixed $oDom - * @param bool $bClearStyleAndHead = true - */ - public static function ClearTags(&$oDom, $bClearStyleAndHead = true) - { - $aRemoveTags = array( - 'svg', 'link', 'base', 'meta', 'title', 'x-script', 'script', 'bgsound', 'keygen', 'source', - 'object', 'embed', 'applet', 'mocha', 'iframe', 'frame', 'frameset', 'video', 'audio', 'area', 'map' - ); - - if ($bClearStyleAndHead) - { - $aRemoveTags[] = 'head'; - $aRemoveTags[] = 'style'; - } - - $aHtmlAllowedTags = isset(\MailSo\Config::$HtmlStrictAllowedTags) && - \is_array(\MailSo\Config::$HtmlStrictAllowedTags) && 0 < \count(\MailSo\Config::$HtmlStrictAllowedTags) ? - \MailSo\Config::$HtmlStrictAllowedTags : null; - - $aRemove = array(); - $aNodes = $oDom->getElementsByTagName('*'); - foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement) - { - if ($oElement) - { - $sTagNameLower = \trim(\strtolower($oElement->tagName)); - if ('' !== $sTagNameLower) - { - if (\in_array($sTagNameLower, $aRemoveTags) || ($aHtmlAllowedTags && !\in_array($sTagNameLower, $aHtmlAllowedTags))) - { - $aRemove[] = @$oElement; - } - } - } - } - - foreach ($aRemove as /* @var $oElement \DOMElement */ $oElement) - { - if (isset($oElement->parentNode)) - { - @$oElement->parentNode->removeChild($oElement); - } - } - } - -/* -// public static function ClearStyleUrlValueParserHelper($oUrlValue, $oRule, $oRuleSet, -// $oElem = null, -// &$bHasExternals = false, &$aFoundCIDs = array(), -// $aContentLocationUrls = array(), &$aFoundedContentLocationUrls = array(), -// $bDoNotReplaceExternalUrl = false, $fAdditionalExternalFilter = null -// ) -// { -// if ($oUrlValue instanceof \Sabberworm\CSS\Value\URL) -// { -// $oNewRule = new \Sabberworm\CSS\Rule\Rule('x-rl-orig-'.$oRule->getRule()); -// $oNewRule->setValue((string) $oRule->getValue()); -// $oNewRule->setIsImportant($oRule->getIsImportant()); -// -// $oRuleSet->addRule($oNewRule); -// -// $oUrl = $oUrlValue->getURL(); -// $sUrl = $oUrl ? $oUrl->getString() : ''; -// -// if ('cid:' === \strtolower(\substr($sUrl, 0, 4))) -// { -// $aFoundCIDs[] = \substr($sUrl, 4); -// -// $oRule->setRule('x-rl-mod-'.$oRule->getRule()); -// -// if ($oElem) -// { -// $oElem->setAttribute('data-x-style-mod', '1'); -// } -// } -// else -// { -// if (\preg_match('/http[s]?:\/\//i', $sUrl) || '//' === \substr($sUrl, 0, 2)) -// { -// $oRule->setRule('x-rl-mod-'.$oRule->getRule()); -// -// if (\in_array($sUrl, $aContentLocationUrls)) -// { -// $aFoundedContentLocationUrls[] = $sUrl; -// } -// else -// { -// $bHasExternals = true; -// if (!$bDoNotReplaceExternalUrl) -// { -// if ($fAdditionalExternalFilter) -// { -// $sAdditionalResult = \call_user_func($fAdditionalExternalFilter, $sUrl); -// if (0 < \strlen($sAdditionalResult) && $oUrl) -// { -// $oUrl->setString($sAdditionalResult); -// } -// } -// } -// } -// -// if ($oElem) -// { -// $oElem->setAttribute('data-x-style-mod', '1'); -// } -// } -// else if ('data:image/' !== \strtolower(\substr(\trim($sUrl), 0, 11))) -// { -// $oRuleSet->removeRule($oRule); -// } -// } -// } -// else if ($oRule instanceof \Sabberworm\CSS\Rule\Rule) -// { -// if ('x-rl-' !== \substr($oRule->getRule(), 0, 5)) -// { -// $oValue = $oRule->getValue(); -// if ($oValue instanceof \Sabberworm\CSS\Value\URL) -// { -// \MailSo\Base\HtmlUtils::ClearStyleUrlValueParserHelper($oValue, $oRule, $oRuleSet, $oElem, -// $bHasExternals, $aFoundCIDs, -// $aContentLocationUrls, $aFoundedContentLocationUrls, -// $bDoNotReplaceExternalUrl, $fAdditionalExternalFilter); -// } -// else if ($oValue instanceof \Sabberworm\CSS\Value\RuleValueList) -// { -// $aComps = $oValue->getListComponents(); -// foreach ($aComps as $oValue) -// { -// if ($oValue instanceof \Sabberworm\CSS\Value\URL) -// { -// \MailSo\Base\HtmlUtils::ClearStyleUrlValueParserHelper($oValue, $oRule, $oRuleSet, $oElem, -// $bHasExternals, $aFoundCIDs, -// $aContentLocationUrls, $aFoundedContentLocationUrls, -// $bDoNotReplaceExternalUrl, $fAdditionalExternalFilter); -// } -// } -// } -// } -// } -// } -// -// public static function ClearStyleSmart($sStyle, $oElement = null, -// &$bHasExternals = false, &$aFoundCIDs = array(), -// $aContentLocationUrls = array(), &$aFoundedContentLocationUrls = array(), -// $bDoNotReplaceExternalUrl = false, $fAdditionalExternalFilter = null, -// $sSelectorPrefix = '') -// { -// $mResult = false; -// $oCss = null; -// -// if (!\class_exists('Sabberworm\CSS\Parser')) -// { -// return $mResult; -// } -// -// $sStyle = \trim($sStyle); -// if (empty($sStyle)) -// { -// return ''; -// } -// -// $sStyle = \trim(\preg_replace('/[\r\n\t\s]+/', ' ', $sStyle)); -// -// try -// { -// $oSettings = \Sabberworm\CSS\Settings::create(); -// $oSettings->beStrict(); -// $oSettings->withMultibyteSupport(false); -// -// $oCssParser = new \Sabberworm\CSS\Parser($sStyle, $oSettings); -// $oCss = $oCssParser->parse(); -// } -// catch (\Exception $oEception) -// { -// unset($oEception); -// $mResult = false; -// } -// -// if ($oCss) -// { -// foreach ($oCss->getAllDeclarationBlocks() as $oBlock) -// { -// foreach($oBlock->getSelectors() as $oSelector) -// { -// $sS = ' '.\trim($oSelector->getSelector()).' '; -// $sS = \preg_replace('/ body([\.# ])/i', ' [data-x-div-type="body"]$1', $sS); -// $sS = \preg_replace('/ html([\.# ])/i', ' [data-x-div-type="html"]$1', $sS); -// -// if (0 < \strlen($sSelectorPrefix)) -// { -// $sS = \trim($sSelectorPrefix.' '.\trim($sS)); -// } -// -// $oSelector->setSelector(\trim($sS)); -// } -// } -// -// $aRulesToRemove = array( -// 'pointer-events', 'content', 'behavior', 'cursor', -// ); -// -// foreach($oCss->getAllRuleSets() as $oRuleSet) -// { -// foreach ($aRulesToRemove as $sRuleToRemove) -// { -// $oRuleSet->removeRule($sRuleToRemove); -// } -// -// // position: fixed -> position: fixed -> absolute -// $aRules = $oRuleSet->getRules('position'); -// if (\is_array($aRules)) -// { -// foreach ($aRules as $oRule) -// { -// $mValue = $oRule->getValue(); -// if (\is_string($mValue) && 'fixed' === \trim(\strtolower($mValue))) -// { -// $oRule->setValue('absolute'); -// } -// } -// } -// } -// -// foreach($oCss->getAllDeclarationBlocks() as $oRuleSet) -// { -// if ($oRuleSet instanceof \Sabberworm\CSS\RuleSet\RuleSet) -// { -// if ($oRuleSet instanceof \Sabberworm\CSS\RuleSet\DeclarationBlock) -// { -// $oRuleSet->expandBackgroundShorthand(); -// $oRuleSet->expandListStyleShorthand(); -// } -// -// $aRules = $oRuleSet->getRules(); -// if (\is_array($aRules) && 0 < \count($aRules)) -// { -// foreach ($aRules as $oRule) -// { -// if ($oRule instanceof \Sabberworm\CSS\Rule\Rule) -// { -// \MailSo\Base\HtmlUtils::ClearStyleUrlValueParserHelper(null, $oRule, $oRuleSet, -// $oElement, -// $bHasExternals, $aFoundCIDs, -// $aContentLocationUrls, $aFoundedContentLocationUrls, -// $bDoNotReplaceExternalUrl, $fAdditionalExternalFilter -// ); -// } -// } -// } -// } -// } -// -// try -// { -// $mResult = $oCss->render(\Sabberworm\CSS\OutputFormat::createCompact()); -// } -// catch (\Exception $oEception) -// { -// unset($oEception); -// $mResult = false; -// } -// } -// -// return $mResult; -// } -*/ - - /** - * - * @param string $sStyle - * @param \DOMElement $oElement - * @param bool $bHasExternals - * @param array $aFoundCIDs - * @param array $aContentLocationUrls - * @param array $aFoundedContentLocationUrls - * @param bool $bDoNotReplaceExternalUrl = false - * @param callback|null $fAdditionalExternalFilter = null - * - * @return string - */ - public static function ClearStyle($sStyle, $oElement, &$bHasExternals, &$aFoundCIDs, - $aContentLocationUrls, &$aFoundedContentLocationUrls, $bDoNotReplaceExternalUrl = false, $fAdditionalExternalFilter = null) - { - $sStyle = \trim($sStyle); - $aOutStyles = array(); - $aStyles = \explode(';', $sStyle); - - if ($fAdditionalExternalFilter && !\is_callable($fAdditionalExternalFilter)) - { - $fAdditionalExternalFilter = null; - } - - $aMatch = array(); - foreach ($aStyles as $sStyleItem) - { - $aStyleValue = \explode(':', $sStyleItem, 2); - $sName = \trim(\strtolower($aStyleValue[0])); - $sValue = isset($aStyleValue[1]) ? \trim($aStyleValue[1]) : ''; - - if ('position' === $sName && 'fixed' === \strtolower($sValue)) - { - $sValue = 'absolute'; - } - - if (0 === \strlen($sName) || 0 === \strlen($sValue)) - { - continue; - } - - $sStyleItem = $sName.': '.$sValue; - $aStyleValue = array($sName, $sValue); - - /*if (\in_array($sName, array('position', 'left', 'right', 'top', 'bottom', 'behavior', 'cursor'))) - { - // skip - } - else */if (\in_array($sName, array('behavior', 'pointer-events')) || - ('cursor' === $sName && !\in_array(\strtolower($sValue), array('none', 'cursor'))) || - ('display' === $sName && 'none' === \strtolower($sValue)) || - \preg_match('/expression/i', $sValue) || - ('text-indent' === $sName && '-' === \substr(trim($sValue), 0, 1)) - ) - { - // skip - } - else if (\in_array($sName, array('background-image', 'background', 'list-style', 'list-style-image', 'content')) - && \preg_match('/url[\s]?\(([^)]+)\)/im', $sValue, $aMatch) && !empty($aMatch[1])) - { - $sFullUrl = \trim($aMatch[0], '"\' '); - $sUrl = \trim($aMatch[1], '"\' '); - $sStyleValue = \trim(\preg_replace('/[\s]+/', ' ', \str_replace($sFullUrl, '', $sValue))); - $sStyleItem = empty($sStyleValue) ? '' : $sName.': '.$sStyleValue; - - if ('cid:' === \strtolower(\substr($sUrl, 0, 4))) - { - if ($oElement) - { - $oElement->setAttribute('data-x-style-cid-name', - 'background' === $sName ? 'background-image' : $sName); - - $oElement->setAttribute('data-x-style-cid', \substr($sUrl, 4)); - - $aFoundCIDs[] = \substr($sUrl, 4); - } - } - else - { - if ($oElement) - { - if (\preg_match('/http[s]?:\/\//i', $sUrl) || '//' === \substr($sUrl, 0, 2)) - { - $bHasExternals = true; - if (!$bDoNotReplaceExternalUrl) - { - if (\in_array($sName, array('background-image', 'list-style-image', 'content'))) - { - $sStyleItem = ''; - } - - $sTemp = ''; - if ($oElement->hasAttribute('data-x-style-url')) - { - $sTemp = \trim($oElement->getAttribute('data-x-style-url')); - } - - $sTemp = empty($sTemp) ? '' : (';' === \substr($sTemp, -1) ? $sTemp.' ' : $sTemp.'; '); - - $oElement->setAttribute('data-x-style-url', \trim($sTemp. - ('background' === $sName ? 'background-image' : $sName).': '.$sFullUrl, ' ;')); - - if ($fAdditionalExternalFilter) - { - $sAdditionalResult = \call_user_func($fAdditionalExternalFilter, $sUrl); - if (0 < \strlen($sAdditionalResult)) - { - $oElement->setAttribute('data-x-additional-style-url', - ('background' === $sName ? 'background-image' : $sName).': url('.$sAdditionalResult.')'); - } - } - } - } - else if ('data:image/' !== \strtolower(\substr(\trim($sUrl), 0, 11))) - { - $oElement->setAttribute('data-x-broken-style-src', $sFullUrl); - } - } - } - - if (!empty($sStyleItem)) - { - $aOutStyles[] = $sStyleItem; - } - } - else if ('height' === $sName) - { -// $aOutStyles[] = 'min-'.ltrim($sStyleItem); - $aOutStyles[] = $sStyleItem; - } - else - { - $aOutStyles[] = $sStyleItem; - } - } - - return \implode(';', $aOutStyles); - } - - /** - * @param \DOMDocument $oDom - */ - public static function FindLinksInDOM(&$oDom) - { - $aNodes = $oDom->getElementsByTagName('*'); - foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement) - { - $sTagNameLower = \strtolower($oElement->tagName); - $sParentTagNameLower = isset($oElement->parentNode) && isset($oElement->parentNode->tagName) ? - \strtolower($oElement->parentNode->tagName) : ''; - - if (!\in_array($sTagNameLower, array('html', 'meta', 'head', 'style', 'script', 'img', 'button', 'input', 'textarea', 'a')) && - 'a' !== $sParentTagNameLower && $oElement->childNodes && 0 < $oElement->childNodes->length) - { - $oSubItem = null; - $aTextNodes = array(); - $iIndex = $oElement->childNodes->length - 1; - while ($iIndex > -1) - { - $oSubItem = $oElement->childNodes->item($iIndex); - if ($oSubItem && XML_TEXT_NODE === $oSubItem->nodeType) - { - $aTextNodes[] = $oSubItem; - } - - $iIndex--; - } - - unset($oSubItem); - - foreach ($aTextNodes as $oTextNode) - { - if ($oTextNode && 0 < \strlen($oTextNode->wholeText)/* && \preg_match('/http[s]?:\/\//i', $oTextNode->wholeText)*/) - { - $sText = \MailSo\Base\LinkFinder::NewInstance() - ->Text($oTextNode->wholeText) - ->UseDefaultWrappers(true) - ->CompileText() - ; - - $oSubDom = \MailSo\Base\HtmlUtils::GetDomFromText($sText); - if ($oSubDom) - { - $oBodyNodes = $oSubDom->getElementsByTagName('body'); - if ($oBodyNodes && 0 < $oBodyNodes->length) - { - $oBodyChildNodes = $oBodyNodes->item(0)->childNodes; - if ($oBodyChildNodes && $oBodyChildNodes->length) - { - for ($iIndex = 0, $iLen = $oBodyChildNodes->length; $iIndex < $iLen; $iIndex++) - { - $oSubItem = $oBodyChildNodes->item($iIndex); - if ($oSubItem) - { - if (XML_ELEMENT_NODE === $oSubItem->nodeType && - 'a' === \strtolower($oSubItem->tagName)) - { - $oLink = $oDom->createElement('a', - \str_replace(':', \MailSo\Base\HtmlUtils::$KOS, \htmlspecialchars($oSubItem->nodeValue))); - - $sHref = $oSubItem->getAttribute('href'); - if ($sHref) - { - $oLink->setAttribute('href', $sHref); - } - - $oElement->insertBefore($oLink, $oTextNode); - } - else - { - $oElement->insertBefore($oDom->importNode($oSubItem), $oTextNode); - } - } - } - - $oElement->removeChild($oTextNode); - } - } - - unset($oBodyNodes); - } - - unset($oSubDom, $sText); - } - } - } - } - - unset($aNodes); - } - - /** - * @param string $sHtml - * @param bool $bDoNotReplaceExternalUrl = false - * @param bool $bFindLinksInHtml = false - * @param bool $bWrapByFakeHtmlAndBodyDiv = true - * - * @return string - */ - public static function ClearHtmlSimple($sHtml, $bDoNotReplaceExternalUrl = false, $bFindLinksInHtml = false, $bWrapByFakeHtmlAndBodyDiv = true) - { - $bHasExternals = false; - $aFoundCIDs = array(); - $aContentLocationUrls = array(); - $aFoundedContentLocationUrls = array(); - $fAdditionalExternalFilter = null; - $fAdditionalDomReader = null; - $bTryToDetectHiddenImages = false; - - return \MailSo\Base\HtmlUtils::ClearHtml($sHtml, $bHasExternals, $aFoundCIDs, - $aContentLocationUrls, $aFoundedContentLocationUrls, $bDoNotReplaceExternalUrl, $bFindLinksInHtml, - $fAdditionalExternalFilter, $fAdditionalDomReader, $bTryToDetectHiddenImages, - $bWrapByFakeHtmlAndBodyDiv); - } - - /** - * @param string $sHtml - * @param bool $bHasExternals = false - * @param array $aFoundCIDs = array() - * @param array $aContentLocationUrls = array() - * @param array $aFoundedContentLocationUrls = array() - * @param bool $bDoNotReplaceExternalUrl = false - * @param bool $bFindLinksInHtml = false - * @param callback|null $fAdditionalExternalFilter = null - * @param callback|null $fAdditionalDomReader = null - * @param bool $bTryToDetectHiddenImages = false - * @param bool $bWrapByFakeHtmlAndBodyDiv = true - * - * @return string - */ - public static function ClearHtml($sHtml, &$bHasExternals = false, &$aFoundCIDs = array(), - $aContentLocationUrls = array(), &$aFoundedContentLocationUrls = array(), - $bDoNotReplaceExternalUrl = false, $bFindLinksInHtml = false, - $fAdditionalExternalFilter = null, $fAdditionalDomReader = false, - $bTryToDetectHiddenImages = false, $bWrapByFakeHtmlAndBodyDiv = true) - { - $sResult = ''; - - $sHtml = null === $sHtml ? '' : (string) $sHtml; - $sHtml = \trim($sHtml); - if (0 === \strlen($sHtml)) - { - return ''; - } - - if ($fAdditionalExternalFilter && !\is_callable($fAdditionalExternalFilter)) - { - $fAdditionalExternalFilter = null; - } - - if ($fAdditionalDomReader && !\is_callable($fAdditionalDomReader)) - { - $fAdditionalDomReader = null; - } - - $bHasExternals = false; - - // Dom Part - $oDom = \MailSo\Base\HtmlUtils::GetDomFromText($sHtml); - unset($sHtml); - - if (!$oDom) - { - return ''; - } - - if ($fAdditionalDomReader) - { - $oResDom = \call_user_func($fAdditionalDomReader, $oDom); - if ($oResDom) - { - $oDom = $oResDom; - } - - unset($oResDom); - } - - if ($bFindLinksInHtml) - { - \MailSo\Base\HtmlUtils::FindLinksInDOM($oDom); - } - - \MailSo\Base\HtmlUtils::ClearComments($oDom); - \MailSo\Base\HtmlUtils::ClearTags($oDom); - - $sLinkColor = ''; - $aNodes = $oDom->getElementsByTagName('*'); - foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement) - { - $aRemovedAttrs = array(); - $sTagNameLower = \strtolower($oElement->tagName); - - // convert body attributes to styles - if ('body' === $sTagNameLower) - { - $aAttrs = array( - 'link' => '', - 'text' => '', - 'topmargin' => '', - 'leftmargin' => '', - 'bottommargin' => '', - 'rightmargin' => '' - ); - - if (isset($oElement->attributes)) - { - foreach ($oElement->attributes as $sAttrName => /* @var $oAttributeNode \DOMNode */ $oAttributeNode) - { - if ($oAttributeNode && isset($oAttributeNode->nodeValue)) - { - $sAttrNameLower = \trim(\strtolower($sAttrName)); - if (isset($aAttrs[$sAttrNameLower]) && '' === $aAttrs[$sAttrNameLower]) - { - $aAttrs[$sAttrNameLower] = array($sAttrName, \trim($oAttributeNode->nodeValue)); - } - } - } - } - - $aStyles = array(); - foreach ($aAttrs as $sIndex => $aItem) - { - if (\is_array($aItem)) - { - $oElement->removeAttribute($aItem[0]); - - switch ($sIndex) - { - case 'link': - $sLinkColor = \trim($aItem[1]); - if (!\preg_match('/^#[abcdef0-9]{3,6}$/i', $sLinkColor)) - { - $sLinkColor = ''; - } - break; - case 'text': - $aStyles[] = 'color: '.$aItem[1]; - break; - case 'topmargin': - $aStyles[] = 'margin-top: '.((int) $aItem[1]).'px'; - break; - case 'leftmargin': - $aStyles[] = 'margin-left: '.((int) $aItem[1]).'px'; - break; - case 'bottommargin': - $aStyles[] = 'margin-bottom: '.((int) $aItem[1]).'px'; - break; - case 'rightmargin': - $aStyles[] = 'margin-right: '.((int) $aItem[1]).'px'; - break; - } - } - } - - if (0 < \count($aStyles)) - { - $sStyles = $oElement->hasAttribute('style') ? \trim(\trim(\trim($oElement->getAttribute('style')), ';')) : ''; - $oElement->setAttribute('style', (empty($sStyles) ? '' : $sStyles.'; ').\implode('; ', $aStyles)); - } - } - - if ('iframe' === $sTagNameLower || 'frame' === $sTagNameLower) - { - $oElement->setAttribute('src', 'javascript:false'); - } - - if ('a' === $sTagNameLower && !empty($sLinkColor)) - { - $sStyles = $oElement->hasAttribute('style') - ? \trim(\trim(\trim($oElement->getAttribute('style')), ';')) : ''; - - $oElement->setAttribute('style', - 'color: '.$sLinkColor.\trim((empty($sStyles) ? '' : '; '.$sStyles))); - } - - if ($oElement->hasAttributes() && isset($oElement->attributes) && $oElement->attributes) - { - $aHtmlAllowedAttributes = isset(\MailSo\Config::$HtmlStrictAllowedAttributes) && - \is_array(\MailSo\Config::$HtmlStrictAllowedAttributes) && 0 < \count(\MailSo\Config::$HtmlStrictAllowedAttributes) ? - \MailSo\Config::$HtmlStrictAllowedAttributes : null; - - $sAttrsForRemove = array(); - foreach ($oElement->attributes as $sAttrName => $oAttr) - { - if ($sAttrName && $oAttr) - { - $sAttrNameLower = \trim(\strtolower($sAttrName)); - if ($aHtmlAllowedAttributes && !\in_array($sAttrNameLower, $aHtmlAllowedAttributes)) - { - $sAttrsForRemove[] = $sAttrName; - } - else if ('on' === \substr($sAttrNameLower, 0, 2) || in_array($sAttrNameLower, array( - 'id', 'class', 'contenteditable', 'designmode', 'formaction', 'manifest', 'action', - 'data-bind', 'data-reactid', 'xmlns', 'srcset', 'data-x-skip-style', - 'fscommand', 'seeksegmenttime' - ))) - { - $sAttrsForRemove[] = $sAttrName; - } - } - } - - if (0 < \count($sAttrsForRemove)) - { - foreach ($sAttrsForRemove as $sName) - { - @$oElement->removeAttribute($sName); - $aRemovedAttrs[\trim(\strtolower($sName))] = true; - } - } - - unset($sAttrsForRemove); - } - - if ($oElement->hasAttribute('href')) - { - $sHref = \trim($oElement->getAttribute('href')); - if (!\preg_match('/^(http[s]?|ftp|skype|mailto):/i', $sHref) && '//' !== \substr($sHref, 0, 2)) - { - $oElement->setAttribute('data-x-broken-href', $sHref); - $oElement->setAttribute('href', 'javascript:false'); - } - - if ('a' === $sTagNameLower) - { - $oElement->setAttribute('rel', 'external nofollow noopener noreferrer'); - } - } - - if (\in_array($sTagNameLower, array('a', 'form', 'area'))) - { - $oElement->setAttribute('target', '_blank'); - } - - if (\in_array($sTagNameLower, array('a', 'form', 'area', 'input', 'button', 'textarea'))) - { - $oElement->setAttribute('tabindex', '-1'); - } - - if ($bTryToDetectHiddenImages && 'img' === $sTagNameLower) - { - $sAlt = $oElement->hasAttribute('alt') - ? \trim($oElement->getAttribute('alt')) : ''; - - if ($oElement->hasAttribute('src') && '' === $sAlt) - { - $aH = array( - 'email.microsoftemail.com/open', - 'github.com/notifications/beacon/', - 'mandrillapp.com/track/open', - 'list-manage.com/track/open' - ); - - $sH = $oElement->hasAttribute('height') - ? \trim($oElement->getAttribute('height')) : ''; - -// $sW = $oElement->hasAttribute('width') -// ? \trim($oElement->getAttribute('width')) : ''; - - $sStyles = $oElement->hasAttribute('style') - ? \preg_replace('/[\s]+/', '', \trim(\trim(\trim($oElement->getAttribute('style')), ';'))) : ''; - - $sSrc = \trim($oElement->getAttribute('src')); - - $bC = \in_array($sH, array('1', '0', '1px', '0px')) || - \preg_match('/(display:none|visibility:hidden|height:0|height:[01][a-z][a-z])/i', $sStyles); - - if (!$bC) - { - $sSrcLower = \strtolower($sSrc); - foreach ($aH as $sLine) - { - if (false !== \strpos($sSrcLower, $sLine)) - { - $bC = true; - break; - } - } - } - - if ($bC) - { - $oElement->setAttribute('style', 'display:none'); - $oElement->setAttribute('data-x-skip-style', 'true'); - $oElement->setAttribute('data-x-hidden-src', $sSrc); - - $oElement->removeAttribute('src'); - } - } - } - - if ($oElement->hasAttribute('src')) - { - $sSrc = \trim($oElement->getAttribute('src')); - $oElement->removeAttribute('src'); - - if (\in_array($sSrc, $aContentLocationUrls)) - { - $oElement->setAttribute('data-x-src-location', $sSrc); - $aFoundedContentLocationUrls[] = $sSrc; - } - else if ('cid:' === \strtolower(\substr($sSrc, 0, 4))) - { - $oElement->setAttribute('data-x-src-cid', \substr($sSrc, 4)); - $aFoundCIDs[] = \substr($sSrc, 4); - } - else - { - if (\preg_match('/^http[s]?:\/\//i', $sSrc) || '//' === \substr($sSrc, 0, 2)) - { - if ($bDoNotReplaceExternalUrl) - { - $oElement->setAttribute('src', $sSrc); - } - else - { - $oElement->setAttribute('data-x-src', $sSrc); - if ($fAdditionalExternalFilter) - { - $sCallResult = \call_user_func($fAdditionalExternalFilter, $sSrc); - if (0 < \strlen($sCallResult)) - { - $oElement->setAttribute('data-x-additional-src', $sCallResult); - } - } - } - - $bHasExternals = true; - } - else if ('data:image/' === \strtolower(\substr($sSrc, 0, 11))) - { - $oElement->setAttribute('src', $sSrc); - } - else - { - $oElement->setAttribute('data-x-broken-src', $sSrc); - } - } - } - - $sBackground = $oElement->hasAttribute('background') - ? \trim($oElement->getAttribute('background')) : ''; - $sBackgroundColor = $oElement->hasAttribute('bgcolor') - ? \trim($oElement->getAttribute('bgcolor')) : ''; - - if (!empty($sBackground) || !empty($sBackgroundColor)) - { - $aStyles = array(); - $sStyles = $oElement->hasAttribute('style') - ? \trim(\trim(\trim($oElement->getAttribute('style')), ';')) : ''; - - if (!empty($sBackground)) - { - $aStyles[] = 'background-image: url(\''.$sBackground.'\')'; - $oElement->removeAttribute('background'); - } - - if (!empty($sBackgroundColor)) - { - $aStyles[] = 'background-color: '.$sBackgroundColor; - $oElement->removeAttribute('bgcolor'); - } - - $oElement->setAttribute('style', (empty($sStyles) ? '' : $sStyles.'; ').\implode('; ', $aStyles)); - } - - if ($oElement->hasAttribute('style') && !$oElement->hasAttribute('data-x-skip-style')) - { - $oElement->setAttribute('style', - \MailSo\Base\HtmlUtils::ClearStyle($oElement->getAttribute('style'), $oElement, $bHasExternals, - $aFoundCIDs, $aContentLocationUrls, $aFoundedContentLocationUrls, $bDoNotReplaceExternalUrl, $fAdditionalExternalFilter)); - } - - $oElement->removeAttribute('data-x-skip-style'); - - if (\MailSo\Config::$HtmlStrictDebug && 0 < \count($aRemovedAttrs)) - { - unset($aRemovedAttrs['class'], $aRemovedAttrs['target'], $aRemovedAttrs['id'], $aRemovedAttrs['name']); - - $aRemovedAttrs = \array_keys($aRemovedAttrs); - if (0 < \count($aRemovedAttrs)) - { - $oElement->setAttribute('data-removed-attrs', \implode(',', $aRemovedAttrs)); - } - } - } - - $sResult = \MailSo\Base\HtmlUtils::GetTextFromDom($oDom, $bWrapByFakeHtmlAndBodyDiv); - unset($oDom); - - return $sResult; - } - - /** - * @param string $sHtml - * @param array $aFoundCids = array() - * @param array|null $mFoundDataURL = null - * @param array $aFoundedContentLocationUrls = array() - * - * @return string - */ - public static function BuildHtml($sHtml, &$aFoundCids = array(), &$mFoundDataURL = null, &$aFoundedContentLocationUrls = array()) - { - $oDom = \MailSo\Base\HtmlUtils::GetDomFromText($sHtml); - - \MailSo\Base\HtmlUtils::ClearTags($oDom); - unset($sHtml); - - $aNodes = $oDom->getElementsByTagName('*'); - foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement) - { - $sTagNameLower = \strtolower($oElement->tagName); - - if ($oElement->hasAttribute('data-x-src-cid')) - { - $sCid = $oElement->getAttribute('data-x-src-cid'); - $oElement->removeAttribute('data-x-src-cid'); - - if (!empty($sCid)) - { - $aFoundCids[] = $sCid; - - @$oElement->removeAttribute('src'); - $oElement->setAttribute('src', 'cid:'.$sCid); - } - } - - if ($oElement->hasAttribute('data-x-src-location')) - { - $sSrc = $oElement->getAttribute('data-x-src-location'); - $oElement->removeAttribute('data-x-src-location'); - - if (!empty($sSrc)) - { - $aFoundedContentLocationUrls[] = $sSrc; - - @$oElement->removeAttribute('src'); - $oElement->setAttribute('src', $sSrc); - } - } - - if ($oElement->hasAttribute('data-x-broken-src')) - { - $oElement->setAttribute('src', $oElement->getAttribute('data-x-broken-src')); - $oElement->removeAttribute('data-x-broken-src'); - } - - if ($oElement->hasAttribute('data-x-src')) - { - $oElement->setAttribute('src', $oElement->getAttribute('data-x-src')); - $oElement->removeAttribute('data-x-src'); - } - - if ($oElement->hasAttribute('data-x-href')) - { - $oElement->setAttribute('href', $oElement->getAttribute('data-x-href')); - $oElement->removeAttribute('data-x-href'); - } - - if ($oElement->hasAttribute('data-x-style-cid-name') && $oElement->hasAttribute('data-x-style-cid')) - { - $sCidName = $oElement->getAttribute('data-x-style-cid-name'); - $sCid = $oElement->getAttribute('data-x-style-cid'); - - $oElement->removeAttribute('data-x-style-cid-name'); - $oElement->removeAttribute('data-x-style-cid'); - if (!empty($sCidName) && !empty($sCid) && \in_array($sCidName, - array('background-image', 'background', 'list-style-image', 'content'))) - { - $sStyles = ''; - if ($oElement->hasAttribute('style')) - { - $sStyles = \trim(\trim($oElement->getAttribute('style')), ';'); - } - - $sBack = $sCidName.': url(cid:'.$sCid.')'; - $sStyles = \preg_replace('/'.\preg_quote($sCidName, '/').':\s?[^;]+/i', $sBack, $sStyles); - if (false === \strpos($sStyles, $sBack)) - { - $sStyles .= empty($sStyles) ? '': '; '; - $sStyles .= $sBack; - } - - $oElement->setAttribute('style', $sStyles); - $aFoundCids[] = $sCid; - } - } - - foreach (array( - 'data-x-additional-src', 'data-x-additional-style-url', 'data-removed-attrs', - 'data-original', 'data-x-div-type', 'data-wrp', 'data-bind' - ) as $sName) - { - if ($oElement->hasAttribute($sName)) - { - $oElement->removeAttribute($sName); - } - } - - if ($oElement->hasAttribute('data-x-style-url')) - { - $sAddStyles = $oElement->getAttribute('data-x-style-url'); - $oElement->removeAttribute('data-x-style-url'); - - if (!empty($sAddStyles)) - { - $sStyles = ''; - if ($oElement->hasAttribute('style')) - { - $sStyles = \trim(\trim($oElement->getAttribute('style')), ';'); - } - - $oElement->setAttribute('style', (empty($sStyles) ? '' : $sStyles.'; ').$sAddStyles); - } - } - - if ('img' === $sTagNameLower && \is_array($mFoundDataURL)) - { - $sSrc = $oElement->getAttribute('src'); - if ('data:image/' === \strtolower(\substr($sSrc, 0, 11))) - { - $sHash = \md5($sSrc); - $mFoundDataURL[$sHash] = $sSrc; - - $oElement->setAttribute('src', 'cid:'.$sHash); - } - } - } - - $sResult = \MailSo\Base\HtmlUtils::GetTextFromDom($oDom, false); - unset($oDom); - - return ''. - ''.$sResult.''; - } - - /** - * @param string $sText - * @param bool $bLinksWithTargetBlank = true - * - * @return string - */ - public static function ConvertPlainToHtml($sText, $bLinksWithTargetBlank = true) - { - $sText = \trim($sText); - if (0 === \strlen($sText)) - { - return ''; - } - - $sText = \MailSo\Base\LinkFinder::NewInstance() - ->Text($sText) - ->UseDefaultWrappers($bLinksWithTargetBlank) - ->CompileText() - ; - - $sText = \str_replace("\r", '', $sText); - - $aText = \explode("\n", $sText); - unset($sText); - - $bIn = false; - $bDo = true; - do - { - $bDo = false; - $aNextText = array(); - foreach ($aText as $sTextLine) - { - $bStart = 0 === \strpos(\ltrim($sTextLine), '>'); - if ($bStart && !$bIn) - { - $bDo = true; - $bIn = true; - $aNextText[] = '
'; - $aNextText[] = \substr(\ltrim($sTextLine), 4); - } - else if (!$bStart && $bIn) - { - $bIn = false; - $aNextText[] = '
'; - $aNextText[] = $sTextLine; - } - else if ($bStart && $bIn) - { - $aNextText[] = \substr(\ltrim($sTextLine), 4); - } - else - { - $aNextText[] = $sTextLine; - } - } - - if ($bIn) - { - $bIn = false; - $aNextText[] = ''; - } - - $aText = $aNextText; - } - while ($bDo); - - $sText = \join("\n", $aText); - unset($aText); - - $sText = \preg_replace('/[\n][ ]+/', "\n", $sText); -// $sText = \preg_replace('/[\s]+([\s])/', '\\1', $sText); - - $sText = \preg_replace('/
[\s]+/i', '
', $sText); - $sText = \preg_replace('/[\s]+<\/blockquote>/i', '
', $sText); - - $sText = \preg_replace('/<\/blockquote>([\n]{0,2})
/i', '\\1', $sText); - $sText = \preg_replace('/[\n]{3,}/', "\n\n", $sText); - - $sText = \strtr($sText, array( - "\n" => "
", - "\t" => '   ', - ' ' => '  ' - )); - - return $sText; - } - - /** - * @param string $sText - * - * @return string - */ - public static function ConvertHtmlToPlain($sText) - { - $sText = \trim(\stripslashes($sText)); - $sText = \MailSo\Base\Utils::StripSpaces($sText); - - $sText = \preg_replace(array( - "/\r/", - "/[\n\t]+/", - '/]*>.*?<\/script>/i', - '/]*>.*?<\/style>/i', - '/]*>.*?<\/title>/i', - '/]*>(.+?)<\/h[123]>/i', - '/]*>(.+?)<\/h[456]>/i', - '/]*>/i', - '/]*>/i', - '/]*>(.+?)<\/b>/i', - '/]*>(.+?)<\/i>/i', - '/(]*>|<\/ul>)/i', - '/(]*>|<\/ol>)/i', - '/]*>/i', - '/]*href="([^"]+)"[^>]*>(.+?)<\/a>/i', - '/]*>/i', - '/(]*>|<\/table>)/i', - '/(]*>|<\/tr>)/i', - '/]*>(.+?)<\/td>/i', - '/]*>(.+?)<\/th>/i', - '/ /i', - '/"/i', - '/>/i', - '/</i', - '/&/i', - '/©/i', - '/™/i', - '/“/', - '/”/', - '/–/', - '/’/', - '/&/', - '/©/', - '/™/', - '/—/', - '/“/', - '/”/', - '/•/', - '/®/i', - '/•/i', - '/&[&;]+;/i', - '/'/', - '/ /' - ), array( - '', - ' ', - '', - '', - '', - "\n\n\\1\n\n", - "\n\n\\1\n\n", - "\n\n\t", - "\n", - '\\1', - '\\1', - "\n\n", - "\n\n", - "\n\t* ", - '\\2 (\\1)', - "\n------------------------------------\n", - "\n", - "\n", - "\t\\1\n", - "\t\\1\n", - ' ', - '"', - '>', - '<', - '&', - '(c)', - '(tm)', - '"', - '"', - '-', - "'", - '&', - '(c)', - '(tm)', - '--', - '"', - '"', - '*', - '(R)', - '*', - '', - '\'', - '' - ), $sText); - - $sText = \str_ireplace('
',"\n
", $sText); - $sText = \strip_tags($sText, ''); - $sText = \preg_replace("/\n\\s+\n/", "\n", $sText); - $sText = \preg_replace("/[\n]{3,}/", "\n\n", $sText); - - return \trim($sText); - } -} +hasAttributes() && isset($oElement->attributes) && $oElement->attributes) + { + foreach ($oElement->attributes as $oAttr) + { + if ($oAttr && !empty($oAttr->nodeName)) + { + $sAttrName = \trim(\strtolower($oAttr->nodeName)); + $aResult[$sAttrName] = $oAttr->nodeValue; + } + } + } + } + + return $aResult; + } + + /** + * @param string $sText + * + * @return \DOMDocument|bool + */ + public static function GetDomFromText($sText) + { + $bState = true; + if (\MailSo\Base\Utils::FunctionExistsAndEnabled('libxml_use_internal_errors')) + { + $bState = \libxml_use_internal_errors(true); + } + + $sHtmlAttrs = $sBodyAttrs = ''; + + $sText = \MailSo\Base\HtmlUtils::FixSchemas($sText); + $sText = \MailSo\Base\HtmlUtils::ClearFastTags($sText); + $sText = \MailSo\Base\HtmlUtils::ClearBodyAndHtmlTag($sText, $sHtmlAttrs, $sBodyAttrs); + + $oDom = self::createDOMDocument(); + @$oDom->loadHTML('<'.'?xml version="1.0" encoding="utf-8"?'.'>'. + ''. + ''. + '
'.$sText.'
'); + + @$oDom->normalizeDocument(); + + if (\MailSo\Base\Utils::FunctionExistsAndEnabled('libxml_clear_errors')) + { + @\libxml_clear_errors(); + } + + if (\MailSo\Base\Utils::FunctionExistsAndEnabled('libxml_use_internal_errors')) + { + \libxml_use_internal_errors($bState); + } + + return $oDom; + } + + /** + * @return \DOMDocument + */ + private static function createDOMDocument() + { + $oDoc = new \DOMDocument('1.0', 'UTF-8'); + $oDoc->encoding = 'UTF-8'; + $oDoc->strictErrorChecking = false; + $oDoc->formatOutput = false; + $oDoc->preserveWhiteSpace = false; + + return $oDoc; + } + + /** + * @return boolean + */ + private static function comparedVersion() + { + return \version_compare(PHP_VERSION, '5.3.6') >= 0; + } + + /** + * @param \DOMDocument|\DOMElement $oElem + * + * @return type + */ + private static function domToString($oElem, $oDom = null) + { + $sResult = ''; + if ($oElem instanceof \DOMDocument) + { + if (isset($oElem->documentElement) && self::comparedVersion()) + { + $sResult = $oElem->saveHTML($oElem->documentElement); + } + else + { + $sResult = $oElem->saveHTML(); + } + } + else if ($oElem) + { + if ($oDom && self::comparedVersion()) + { + $sResult = $oDom->saveHTML($oElem); + } + else + { + $oTempDoc = self::createDOMDocument(); + $oTempDoc->appendChild($oTempDoc->importNode($oElem->cloneNode(true), true)); + $sResult = $oTempDoc->saveHTML(); + } + } + + return \trim($sResult); + } + + /** + * @param \DOMDocument $oDom + * @param bool $bWrapByFakeHtmlAndBodyDiv = true + * + * @return string + */ + public static function GetTextFromDom($oDom, $bWrapByFakeHtmlAndBodyDiv = true) + { + $sResult = ''; + + $aHtmlAttrs = $aBodylAttrs = array(); + if ($bWrapByFakeHtmlAndBodyDiv) + { + $oHtml = $oDom->getElementsByTagName('html')->item(0); + $oBody = $oDom->getElementsByTagName('body')->item(0); + + $aHtmlAttrs = \MailSo\Base\HtmlUtils::GetElementAttributesAsArray($oHtml); + $aBodylAttrs = \MailSo\Base\HtmlUtils::GetElementAttributesAsArray($oBody); + } + + $oDiv = $oDom->getElementsByTagName('div')->item(0); + if ($oDiv && $oDiv->hasAttribute('data-wrp') && 'rainloop' === $oDiv->getAttribute('data-wrp')) + { + $oDiv->removeAttribute('data-wrp'); + if ($bWrapByFakeHtmlAndBodyDiv) + { + $oWrap = $oDom->createElement('div'); + + $oWrap->setAttribute('data-x-div-type', 'html'); + foreach ($aHtmlAttrs as $sKey => $sValue) + { + $oWrap->setAttribute($sKey, $sValue); + } + + $oDiv->setAttribute('data-x-div-type', 'body'); + foreach ($aBodylAttrs as $sKey => $sValue) + { + $oDiv->setAttribute($sKey, $sValue); + } + + $oWrap->appendChild($oDiv); + $sResult = self::domToString($oWrap, $oDom); + } + else + { + $sResult = self::domToString($oDiv, $oDom); + if (0 === strpos($sResult, '
') && '
' === substr($sResult, -6)) + { + $sResult = substr($sResult, 5); + $sResult = substr($sResult, 0, -6); + $sResult = \trim($sResult); + } + } + } + else + { + $sResult = self::domToString($oDom); + } + + $sResult = \str_replace(\MailSo\Base\HtmlUtils::$KOS, ':', $sResult); + $sResult = \MailSo\Base\Utils::StripSpaces($sResult); + + return $sResult; + } + + /** + * @param string $sHtml + * @param string $sHtmlAttrs = ' + * @param string $sBodyAttrs = '' + * + * @return string + */ + public static function ClearBodyAndHtmlTag($sHtml, &$sHtmlAttrs = '', &$sBodyAttrs = '') + { + $aMatch = array(); + if (\preg_match('/]+)>/im', $sHtml, $aMatch) && !empty($aMatch[1])) + { + $sHtmlAttrs = $aMatch[1]; + } + + $aMatch = array(); + if (\preg_match('/]+)>/im', $sHtml, $aMatch) && !empty($aMatch[1])) + { + $sBodyAttrs = $aMatch[1]; + } + +// $iPos = \stripos($sHtml, ''); +// if (0 < $iPos) +// { +// $sHtml = \substr($sHtml, $iPos); +// } +// else +// { +// $iPos = \stripos($sHtml, ']*)>/si', '', $sHtml); + $sHtml = \preg_replace('/<\/body>/i', '', $sHtml); + $sHtml = \preg_replace('/]*)>/i', '', $sHtml); + $sHtml = \preg_replace('/<\/html>/i', '', $sHtml); + + $sHtmlAttrs = \preg_replace('/xmlns:[a-z]="[^"]*"/i', '', $sHtmlAttrs); + $sHtmlAttrs = \preg_replace('/xmlns="[^"]*"/i', '', $sHtmlAttrs); + $sBodyAttrs = \preg_replace('/xmlns:[a-z]="[^"]*"/i', '', $sBodyAttrs); + + return $sHtml; + } + + /** + * @param string $sHtml + * @param bool $bClearEmpty = true + * + * @return string + */ + public static function FixSchemas($sHtml, $bClearEmpty = true) + { + if ($bClearEmpty) + { + $sHtml = \str_replace('', '', $sHtml); + } + + $sHtml = \str_replace('', '', $sHtml); + $sHtml = \str_replace('', '', $sHtml); + + return $sHtml; + } + + /** + * @param string $sHtml + * + * @return string + */ + public static function ClearFastTags($sHtml) + { + return \preg_replace(array( + '/]*><\/p>/i', + '/]*>/i', + '/<\?xml [^>]*\?>/i' + ), '', $sHtml); + } + + /** + * @param mixed $oDom + */ + public static function ClearComments(&$oDom) + { + $aRemove = array(); + + $oXpath = new \DOMXpath($oDom); + $oComments = $oXpath->query('//comment()'); + if ($oComments) + { + foreach ($oComments as $oComment) + { + $aRemove[] = $oComment; + } + } + + unset($oXpath, $oComments); + + foreach ($aRemove as /* @var $oElement \DOMElement */ $oElement) + { + if (isset($oElement->parentNode)) + { + @$oElement->parentNode->removeChild($oElement); + } + } + } + + /** + * @param mixed $oDom + * @param bool $bClearStyleAndHead = true + */ + public static function ClearTags(&$oDom, $bClearStyleAndHead = true) + { + $aRemoveTags = array( + 'svg', 'link', 'base', 'meta', 'title', 'x-script', 'script', 'bgsound', 'keygen', 'source', + 'object', 'embed', 'applet', 'mocha', 'iframe', 'frame', 'frameset', 'video', 'audio', 'area', 'map' + ); + + if ($bClearStyleAndHead) + { + $aRemoveTags[] = 'head'; + $aRemoveTags[] = 'style'; + } + + $aHtmlAllowedTags = isset(\MailSo\Config::$HtmlStrictAllowedTags) && + \is_array(\MailSo\Config::$HtmlStrictAllowedTags) && 0 < \count(\MailSo\Config::$HtmlStrictAllowedTags) ? + \MailSo\Config::$HtmlStrictAllowedTags : null; + + $aRemove = array(); + $aNodes = $oDom->getElementsByTagName('*'); + foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement) + { + if ($oElement) + { + $sTagNameLower = \trim(\strtolower($oElement->tagName)); + if ('' !== $sTagNameLower) + { + if (\in_array($sTagNameLower, $aRemoveTags) || ($aHtmlAllowedTags && !\in_array($sTagNameLower, $aHtmlAllowedTags))) + { + $aRemove[] = @$oElement; + } + } + } + } + + foreach ($aRemove as /* @var $oElement \DOMElement */ $oElement) + { + if (isset($oElement->parentNode)) + { + @$oElement->parentNode->removeChild($oElement); + } + } + } + +/* +// public static function ClearStyleUrlValueParserHelper($oUrlValue, $oRule, $oRuleSet, +// $oElem = null, +// &$bHasExternals = false, &$aFoundCIDs = array(), +// $aContentLocationUrls = array(), &$aFoundedContentLocationUrls = array(), +// $bDoNotReplaceExternalUrl = false, $fAdditionalExternalFilter = null +// ) +// { +// if ($oUrlValue instanceof \Sabberworm\CSS\Value\URL) +// { +// $oNewRule = new \Sabberworm\CSS\Rule\Rule('x-rl-orig-'.$oRule->getRule()); +// $oNewRule->setValue((string) $oRule->getValue()); +// $oNewRule->setIsImportant($oRule->getIsImportant()); +// +// $oRuleSet->addRule($oNewRule); +// +// $oUrl = $oUrlValue->getURL(); +// $sUrl = $oUrl ? $oUrl->getString() : ''; +// +// if ('cid:' === \strtolower(\substr($sUrl, 0, 4))) +// { +// $aFoundCIDs[] = \substr($sUrl, 4); +// +// $oRule->setRule('x-rl-mod-'.$oRule->getRule()); +// +// if ($oElem) +// { +// $oElem->setAttribute('data-x-style-mod', '1'); +// } +// } +// else +// { +// if (\preg_match('/http[s]?:\/\//i', $sUrl) || '//' === \substr($sUrl, 0, 2)) +// { +// $oRule->setRule('x-rl-mod-'.$oRule->getRule()); +// +// if (\in_array($sUrl, $aContentLocationUrls)) +// { +// $aFoundedContentLocationUrls[] = $sUrl; +// } +// else +// { +// $bHasExternals = true; +// if (!$bDoNotReplaceExternalUrl) +// { +// if ($fAdditionalExternalFilter) +// { +// $sAdditionalResult = \call_user_func($fAdditionalExternalFilter, $sUrl); +// if (0 < \strlen($sAdditionalResult) && $oUrl) +// { +// $oUrl->setString($sAdditionalResult); +// } +// } +// } +// } +// +// if ($oElem) +// { +// $oElem->setAttribute('data-x-style-mod', '1'); +// } +// } +// else if ('data:image/' !== \strtolower(\substr(\trim($sUrl), 0, 11))) +// { +// $oRuleSet->removeRule($oRule); +// } +// } +// } +// else if ($oRule instanceof \Sabberworm\CSS\Rule\Rule) +// { +// if ('x-rl-' !== \substr($oRule->getRule(), 0, 5)) +// { +// $oValue = $oRule->getValue(); +// if ($oValue instanceof \Sabberworm\CSS\Value\URL) +// { +// \MailSo\Base\HtmlUtils::ClearStyleUrlValueParserHelper($oValue, $oRule, $oRuleSet, $oElem, +// $bHasExternals, $aFoundCIDs, +// $aContentLocationUrls, $aFoundedContentLocationUrls, +// $bDoNotReplaceExternalUrl, $fAdditionalExternalFilter); +// } +// else if ($oValue instanceof \Sabberworm\CSS\Value\RuleValueList) +// { +// $aComps = $oValue->getListComponents(); +// foreach ($aComps as $oValue) +// { +// if ($oValue instanceof \Sabberworm\CSS\Value\URL) +// { +// \MailSo\Base\HtmlUtils::ClearStyleUrlValueParserHelper($oValue, $oRule, $oRuleSet, $oElem, +// $bHasExternals, $aFoundCIDs, +// $aContentLocationUrls, $aFoundedContentLocationUrls, +// $bDoNotReplaceExternalUrl, $fAdditionalExternalFilter); +// } +// } +// } +// } +// } +// } +// +// public static function ClearStyleSmart($sStyle, $oElement = null, +// &$bHasExternals = false, &$aFoundCIDs = array(), +// $aContentLocationUrls = array(), &$aFoundedContentLocationUrls = array(), +// $bDoNotReplaceExternalUrl = false, $fAdditionalExternalFilter = null, +// $sSelectorPrefix = '') +// { +// $mResult = false; +// $oCss = null; +// +// if (!\class_exists('Sabberworm\CSS\Parser')) +// { +// return $mResult; +// } +// +// $sStyle = \trim($sStyle); +// if (empty($sStyle)) +// { +// return ''; +// } +// +// $sStyle = \trim(\preg_replace('/[\r\n\t\s]+/', ' ', $sStyle)); +// +// try +// { +// $oSettings = \Sabberworm\CSS\Settings::create(); +// $oSettings->beStrict(); +// $oSettings->withMultibyteSupport(false); +// +// $oCssParser = new \Sabberworm\CSS\Parser($sStyle, $oSettings); +// $oCss = $oCssParser->parse(); +// } +// catch (\Exception $oEception) +// { +// unset($oEception); +// $mResult = false; +// } +// +// if ($oCss) +// { +// foreach ($oCss->getAllDeclarationBlocks() as $oBlock) +// { +// foreach($oBlock->getSelectors() as $oSelector) +// { +// $sS = ' '.\trim($oSelector->getSelector()).' '; +// $sS = \preg_replace('/ body([\.# ])/i', ' [data-x-div-type="body"]$1', $sS); +// $sS = \preg_replace('/ html([\.# ])/i', ' [data-x-div-type="html"]$1', $sS); +// +// if (0 < \strlen($sSelectorPrefix)) +// { +// $sS = \trim($sSelectorPrefix.' '.\trim($sS)); +// } +// +// $oSelector->setSelector(\trim($sS)); +// } +// } +// +// $aRulesToRemove = array( +// 'pointer-events', 'content', 'behavior', 'cursor', +// ); +// +// foreach($oCss->getAllRuleSets() as $oRuleSet) +// { +// foreach ($aRulesToRemove as $sRuleToRemove) +// { +// $oRuleSet->removeRule($sRuleToRemove); +// } +// +// // position: fixed -> position: fixed -> absolute +// $aRules = $oRuleSet->getRules('position'); +// if (\is_array($aRules)) +// { +// foreach ($aRules as $oRule) +// { +// $mValue = $oRule->getValue(); +// if (\is_string($mValue) && 'fixed' === \trim(\strtolower($mValue))) +// { +// $oRule->setValue('absolute'); +// } +// } +// } +// } +// +// foreach($oCss->getAllDeclarationBlocks() as $oRuleSet) +// { +// if ($oRuleSet instanceof \Sabberworm\CSS\RuleSet\RuleSet) +// { +// if ($oRuleSet instanceof \Sabberworm\CSS\RuleSet\DeclarationBlock) +// { +// $oRuleSet->expandBackgroundShorthand(); +// $oRuleSet->expandListStyleShorthand(); +// } +// +// $aRules = $oRuleSet->getRules(); +// if (\is_array($aRules) && 0 < \count($aRules)) +// { +// foreach ($aRules as $oRule) +// { +// if ($oRule instanceof \Sabberworm\CSS\Rule\Rule) +// { +// \MailSo\Base\HtmlUtils::ClearStyleUrlValueParserHelper(null, $oRule, $oRuleSet, +// $oElement, +// $bHasExternals, $aFoundCIDs, +// $aContentLocationUrls, $aFoundedContentLocationUrls, +// $bDoNotReplaceExternalUrl, $fAdditionalExternalFilter +// ); +// } +// } +// } +// } +// } +// +// try +// { +// $mResult = $oCss->render(\Sabberworm\CSS\OutputFormat::createCompact()); +// } +// catch (\Exception $oEception) +// { +// unset($oEception); +// $mResult = false; +// } +// } +// +// return $mResult; +// } +*/ + + /** + * + * @param string $sStyle + * @param \DOMElement $oElement + * @param bool $bHasExternals + * @param array $aFoundCIDs + * @param array $aContentLocationUrls + * @param array $aFoundedContentLocationUrls + * @param bool $bDoNotReplaceExternalUrl = false + * @param callback|null $fAdditionalExternalFilter = null + * + * @return string + */ + public static function ClearStyle($sStyle, $oElement, &$bHasExternals, &$aFoundCIDs, + $aContentLocationUrls, &$aFoundedContentLocationUrls, $bDoNotReplaceExternalUrl = false, $fAdditionalExternalFilter = null) + { + $sStyle = \trim($sStyle); + $aOutStyles = array(); + $aStyles = \explode(';', $sStyle); + + if ($fAdditionalExternalFilter && !\is_callable($fAdditionalExternalFilter)) + { + $fAdditionalExternalFilter = null; + } + + $aMatch = array(); + foreach ($aStyles as $sStyleItem) + { + $aStyleValue = \explode(':', $sStyleItem, 2); + $sName = \trim(\strtolower($aStyleValue[0])); + $sValue = isset($aStyleValue[1]) ? \trim($aStyleValue[1]) : ''; + + if ('position' === $sName && 'fixed' === \strtolower($sValue)) + { + $sValue = 'absolute'; + } + + if (0 === \strlen($sName) || 0 === \strlen($sValue)) + { + continue; + } + + $sStyleItem = $sName.': '.$sValue; + $aStyleValue = array($sName, $sValue); + + /*if (\in_array($sName, array('position', 'left', 'right', 'top', 'bottom', 'behavior', 'cursor'))) + { + // skip + } + else */if (\in_array($sName, array('behavior', 'pointer-events')) || + ('cursor' === $sName && !\in_array(\strtolower($sValue), array('none', 'cursor'))) || + ('display' === $sName && 'none' === \strtolower($sValue)) || + \preg_match('/expression/i', $sValue) || + ('text-indent' === $sName && '-' === \substr(trim($sValue), 0, 1)) + ) + { + // skip + } + else if (\in_array($sName, array('background-image', 'background', 'list-style', 'list-style-image', 'content')) + && \preg_match('/url[\s]?\(([^)]+)\)/im', $sValue, $aMatch) && !empty($aMatch[1])) + { + $sFullUrl = \trim($aMatch[0], '"\' '); + $sUrl = \trim($aMatch[1], '"\' '); + $sStyleValue = \trim(\preg_replace('/[\s]+/', ' ', \str_replace($sFullUrl, '', $sValue))); + $sStyleItem = empty($sStyleValue) ? '' : $sName.': '.$sStyleValue; + + if ('cid:' === \strtolower(\substr($sUrl, 0, 4))) + { + if ($oElement) + { + $oElement->setAttribute('data-x-style-cid-name', + 'background' === $sName ? 'background-image' : $sName); + + $oElement->setAttribute('data-x-style-cid', \substr($sUrl, 4)); + + $aFoundCIDs[] = \substr($sUrl, 4); + } + } + else + { + if ($oElement) + { + if (\preg_match('/http[s]?:\/\//i', $sUrl) || '//' === \substr($sUrl, 0, 2)) + { + $bHasExternals = true; + if (!$bDoNotReplaceExternalUrl) + { + if (\in_array($sName, array('background-image', 'list-style-image', 'content'))) + { + $sStyleItem = ''; + } + + $sTemp = ''; + if ($oElement->hasAttribute('data-x-style-url')) + { + $sTemp = \trim($oElement->getAttribute('data-x-style-url')); + } + + $sTemp = empty($sTemp) ? '' : (';' === \substr($sTemp, -1) ? $sTemp.' ' : $sTemp.'; '); + + $oElement->setAttribute('data-x-style-url', \trim($sTemp. + ('background' === $sName ? 'background-image' : $sName).': '.$sFullUrl, ' ;')); + + if ($fAdditionalExternalFilter) + { + $sAdditionalResult = \call_user_func($fAdditionalExternalFilter, $sUrl); + if (0 < \strlen($sAdditionalResult)) + { + $oElement->setAttribute('data-x-additional-style-url', + ('background' === $sName ? 'background-image' : $sName).': url('.$sAdditionalResult.')'); + } + } + } + } + else if ('data:image/' !== \strtolower(\substr(\trim($sUrl), 0, 11))) + { + $oElement->setAttribute('data-x-broken-style-src', $sFullUrl); + } + } + } + + if (!empty($sStyleItem)) + { + $aOutStyles[] = $sStyleItem; + } + } + else if ('height' === $sName) + { +// $aOutStyles[] = 'min-'.ltrim($sStyleItem); + $aOutStyles[] = $sStyleItem; + } + else + { + $aOutStyles[] = $sStyleItem; + } + } + + return \implode(';', $aOutStyles); + } + + /** + * @param \DOMDocument $oDom + */ + public static function FindLinksInDOM(&$oDom) + { + $aNodes = $oDom->getElementsByTagName('*'); + foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement) + { + $sTagNameLower = \strtolower($oElement->tagName); + $sParentTagNameLower = isset($oElement->parentNode) && isset($oElement->parentNode->tagName) ? + \strtolower($oElement->parentNode->tagName) : ''; + + if (!\in_array($sTagNameLower, array('html', 'meta', 'head', 'style', 'script', 'img', 'button', 'input', 'textarea', 'a')) && + 'a' !== $sParentTagNameLower && $oElement->childNodes && 0 < $oElement->childNodes->length) + { + $oSubItem = null; + $aTextNodes = array(); + $iIndex = $oElement->childNodes->length - 1; + while ($iIndex > -1) + { + $oSubItem = $oElement->childNodes->item($iIndex); + if ($oSubItem && XML_TEXT_NODE === $oSubItem->nodeType) + { + $aTextNodes[] = $oSubItem; + } + + $iIndex--; + } + + unset($oSubItem); + + foreach ($aTextNodes as $oTextNode) + { + if ($oTextNode && 0 < \strlen($oTextNode->wholeText)/* && \preg_match('/http[s]?:\/\//i', $oTextNode->wholeText)*/) + { + $sText = \MailSo\Base\LinkFinder::NewInstance() + ->Text($oTextNode->wholeText) + ->UseDefaultWrappers(true) + ->CompileText() + ; + + $oSubDom = \MailSo\Base\HtmlUtils::GetDomFromText($sText); + if ($oSubDom) + { + $oBodyNodes = $oSubDom->getElementsByTagName('body'); + if ($oBodyNodes && 0 < $oBodyNodes->length) + { + $oBodyChildNodes = $oBodyNodes->item(0)->childNodes; + if ($oBodyChildNodes && $oBodyChildNodes->length) + { + for ($iIndex = 0, $iLen = $oBodyChildNodes->length; $iIndex < $iLen; $iIndex++) + { + $oSubItem = $oBodyChildNodes->item($iIndex); + if ($oSubItem) + { + if (XML_ELEMENT_NODE === $oSubItem->nodeType && + 'a' === \strtolower($oSubItem->tagName)) + { + $oLink = $oDom->createElement('a', + \str_replace(':', \MailSo\Base\HtmlUtils::$KOS, \htmlspecialchars($oSubItem->nodeValue))); + + $sHref = $oSubItem->getAttribute('href'); + if ($sHref) + { + $oLink->setAttribute('href', $sHref); + } + + $oElement->insertBefore($oLink, $oTextNode); + } + else + { + $oElement->insertBefore($oDom->importNode($oSubItem), $oTextNode); + } + } + } + + $oElement->removeChild($oTextNode); + } + } + + unset($oBodyNodes); + } + + unset($oSubDom, $sText); + } + } + } + } + + unset($aNodes); + } + + /** + * @param string $sHtml + * @param bool $bDoNotReplaceExternalUrl = false + * @param bool $bFindLinksInHtml = false + * @param bool $bWrapByFakeHtmlAndBodyDiv = true + * + * @return string + */ + public static function ClearHtmlSimple($sHtml, $bDoNotReplaceExternalUrl = false, $bFindLinksInHtml = false, $bWrapByFakeHtmlAndBodyDiv = true) + { + $bHasExternals = false; + $aFoundCIDs = array(); + $aContentLocationUrls = array(); + $aFoundedContentLocationUrls = array(); + $fAdditionalExternalFilter = null; + $fAdditionalDomReader = null; + $bTryToDetectHiddenImages = false; + + return \MailSo\Base\HtmlUtils::ClearHtml($sHtml, $bHasExternals, $aFoundCIDs, + $aContentLocationUrls, $aFoundedContentLocationUrls, $bDoNotReplaceExternalUrl, $bFindLinksInHtml, + $fAdditionalExternalFilter, $fAdditionalDomReader, $bTryToDetectHiddenImages, + $bWrapByFakeHtmlAndBodyDiv); + } + + /** + * @param string $sHtml + * @param bool $bHasExternals = false + * @param array $aFoundCIDs = array() + * @param array $aContentLocationUrls = array() + * @param array $aFoundedContentLocationUrls = array() + * @param bool $bDoNotReplaceExternalUrl = false + * @param bool $bFindLinksInHtml = false + * @param callback|null $fAdditionalExternalFilter = null + * @param callback|null $fAdditionalDomReader = null + * @param bool $bTryToDetectHiddenImages = false + * @param bool $bWrapByFakeHtmlAndBodyDiv = true + * + * @return string + */ + public static function ClearHtml($sHtml, &$bHasExternals = false, &$aFoundCIDs = array(), + $aContentLocationUrls = array(), &$aFoundedContentLocationUrls = array(), + $bDoNotReplaceExternalUrl = false, $bFindLinksInHtml = false, + $fAdditionalExternalFilter = null, $fAdditionalDomReader = false, + $bTryToDetectHiddenImages = false, $bWrapByFakeHtmlAndBodyDiv = true) + { + $sResult = ''; + + $sHtml = null === $sHtml ? '' : (string) $sHtml; + $sHtml = \trim($sHtml); + if (0 === \strlen($sHtml)) + { + return ''; + } + + if ($fAdditionalExternalFilter && !\is_callable($fAdditionalExternalFilter)) + { + $fAdditionalExternalFilter = null; + } + + if ($fAdditionalDomReader && !\is_callable($fAdditionalDomReader)) + { + $fAdditionalDomReader = null; + } + + $bHasExternals = false; + + // Dom Part + $oDom = \MailSo\Base\HtmlUtils::GetDomFromText($sHtml); + unset($sHtml); + + if (!$oDom) + { + return ''; + } + + if ($fAdditionalDomReader) + { + $oResDom = \call_user_func($fAdditionalDomReader, $oDom); + if ($oResDom) + { + $oDom = $oResDom; + } + + unset($oResDom); + } + + if ($bFindLinksInHtml) + { + \MailSo\Base\HtmlUtils::FindLinksInDOM($oDom); + } + + \MailSo\Base\HtmlUtils::ClearComments($oDom); + \MailSo\Base\HtmlUtils::ClearTags($oDom); + + $sLinkColor = ''; + $aNodes = $oDom->getElementsByTagName('*'); + foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement) + { + $aRemovedAttrs = array(); + $sTagNameLower = \strtolower($oElement->tagName); + + // convert body attributes to styles + if ('body' === $sTagNameLower) + { + $aAttrs = array( + 'link' => '', + 'text' => '', + 'topmargin' => '', + 'leftmargin' => '', + 'bottommargin' => '', + 'rightmargin' => '' + ); + + if (isset($oElement->attributes)) + { + foreach ($oElement->attributes as $sAttrName => /* @var $oAttributeNode \DOMNode */ $oAttributeNode) + { + if ($oAttributeNode && isset($oAttributeNode->nodeValue)) + { + $sAttrNameLower = \trim(\strtolower($sAttrName)); + if (isset($aAttrs[$sAttrNameLower]) && '' === $aAttrs[$sAttrNameLower]) + { + $aAttrs[$sAttrNameLower] = array($sAttrName, \trim($oAttributeNode->nodeValue)); + } + } + } + } + + $aStyles = array(); + foreach ($aAttrs as $sIndex => $aItem) + { + if (\is_array($aItem)) + { + $oElement->removeAttribute($aItem[0]); + + switch ($sIndex) + { + case 'link': + $sLinkColor = \trim($aItem[1]); + if (!\preg_match('/^#[abcdef0-9]{3,6}$/i', $sLinkColor)) + { + $sLinkColor = ''; + } + break; + case 'text': + $aStyles[] = 'color: '.$aItem[1]; + break; + case 'topmargin': + $aStyles[] = 'margin-top: '.((int) $aItem[1]).'px'; + break; + case 'leftmargin': + $aStyles[] = 'margin-left: '.((int) $aItem[1]).'px'; + break; + case 'bottommargin': + $aStyles[] = 'margin-bottom: '.((int) $aItem[1]).'px'; + break; + case 'rightmargin': + $aStyles[] = 'margin-right: '.((int) $aItem[1]).'px'; + break; + } + } + } + + if (0 < \count($aStyles)) + { + $sStyles = $oElement->hasAttribute('style') ? \trim(\trim(\trim($oElement->getAttribute('style')), ';')) : ''; + $oElement->setAttribute('style', (empty($sStyles) ? '' : $sStyles.'; ').\implode('; ', $aStyles)); + } + } + + if ('iframe' === $sTagNameLower || 'frame' === $sTagNameLower) + { + $oElement->setAttribute('src', 'javascript:false'); + } + + if ('a' === $sTagNameLower && !empty($sLinkColor)) + { + $sStyles = $oElement->hasAttribute('style') + ? \trim(\trim(\trim($oElement->getAttribute('style')), ';')) : ''; + + $oElement->setAttribute('style', + 'color: '.$sLinkColor.\trim((empty($sStyles) ? '' : '; '.$sStyles))); + } + + if ($oElement->hasAttributes() && isset($oElement->attributes) && $oElement->attributes) + { + $aHtmlAllowedAttributes = isset(\MailSo\Config::$HtmlStrictAllowedAttributes) && + \is_array(\MailSo\Config::$HtmlStrictAllowedAttributes) && 0 < \count(\MailSo\Config::$HtmlStrictAllowedAttributes) ? + \MailSo\Config::$HtmlStrictAllowedAttributes : null; + + $sAttrsForRemove = array(); + foreach ($oElement->attributes as $sAttrName => $oAttr) + { + if ($sAttrName && $oAttr) + { + $sAttrNameLower = \trim(\strtolower($sAttrName)); + if ($aHtmlAllowedAttributes && !\in_array($sAttrNameLower, $aHtmlAllowedAttributes)) + { + $sAttrsForRemove[] = $sAttrName; + } + else if ('on' === \substr($sAttrNameLower, 0, 2) || in_array($sAttrNameLower, array( + 'id', 'class', 'contenteditable', 'designmode', 'formaction', 'manifest', 'action', + 'data-bind', 'data-reactid', 'xmlns', 'srcset', 'data-x-skip-style', + 'fscommand', 'seeksegmenttime' + ))) + { + $sAttrsForRemove[] = $sAttrName; + } + } + } + + if (0 < \count($sAttrsForRemove)) + { + foreach ($sAttrsForRemove as $sName) + { + @$oElement->removeAttribute($sName); + $aRemovedAttrs[\trim(\strtolower($sName))] = true; + } + } + + unset($sAttrsForRemove); + } + + if ($oElement->hasAttribute('href')) + { + $sHref = \trim($oElement->getAttribute('href')); + if (!\preg_match('/^(http[s]?|ftp|skype|mailto):/i', $sHref) && '//' !== \substr($sHref, 0, 2)) + { + $oElement->setAttribute('data-x-broken-href', $sHref); + $oElement->setAttribute('href', 'javascript:false'); + } + + if ('a' === $sTagNameLower) + { + $oElement->setAttribute('rel', 'external nofollow noopener noreferrer'); + } + } + + if (\in_array($sTagNameLower, array('a', 'form', 'area'))) + { + $oElement->setAttribute('target', '_blank'); + } + + if (\in_array($sTagNameLower, array('a', 'form', 'area', 'input', 'button', 'textarea'))) + { + $oElement->setAttribute('tabindex', '-1'); + } + + if ($bTryToDetectHiddenImages && 'img' === $sTagNameLower) + { + $sAlt = $oElement->hasAttribute('alt') + ? \trim($oElement->getAttribute('alt')) : ''; + + if ($oElement->hasAttribute('src') && '' === $sAlt) + { + $aH = array( + 'email.microsoftemail.com/open', + 'github.com/notifications/beacon/', + 'mandrillapp.com/track/open', + 'list-manage.com/track/open' + ); + + $sH = $oElement->hasAttribute('height') + ? \trim($oElement->getAttribute('height')) : ''; + +// $sW = $oElement->hasAttribute('width') +// ? \trim($oElement->getAttribute('width')) : ''; + + $sStyles = $oElement->hasAttribute('style') + ? \preg_replace('/[\s]+/', '', \trim(\trim(\trim($oElement->getAttribute('style')), ';'))) : ''; + + $sSrc = \trim($oElement->getAttribute('src')); + + $bC = \in_array($sH, array('1', '0', '1px', '0px')) || + \preg_match('/(display:none|visibility:hidden|height:0|height:[01][a-z][a-z])/i', $sStyles); + + if (!$bC) + { + $sSrcLower = \strtolower($sSrc); + foreach ($aH as $sLine) + { + if (false !== \strpos($sSrcLower, $sLine)) + { + $bC = true; + break; + } + } + } + + if ($bC) + { + $oElement->setAttribute('style', 'display:none'); + $oElement->setAttribute('data-x-skip-style', 'true'); + $oElement->setAttribute('data-x-hidden-src', $sSrc); + + $oElement->removeAttribute('src'); + } + } + } + + if ($oElement->hasAttribute('src')) + { + $sSrc = \trim($oElement->getAttribute('src')); + $oElement->removeAttribute('src'); + + if (\in_array($sSrc, $aContentLocationUrls)) + { + $oElement->setAttribute('data-x-src-location', $sSrc); + $aFoundedContentLocationUrls[] = $sSrc; + } + else if ('cid:' === \strtolower(\substr($sSrc, 0, 4))) + { + $oElement->setAttribute('data-x-src-cid', \substr($sSrc, 4)); + $aFoundCIDs[] = \substr($sSrc, 4); + } + else + { + if (\preg_match('/^http[s]?:\/\//i', $sSrc) || '//' === \substr($sSrc, 0, 2)) + { + if ($bDoNotReplaceExternalUrl) + { + $oElement->setAttribute('src', $sSrc); + } + else + { + $oElement->setAttribute('data-x-src', $sSrc); + if ($fAdditionalExternalFilter) + { + $sCallResult = \call_user_func($fAdditionalExternalFilter, $sSrc); + if (0 < \strlen($sCallResult)) + { + $oElement->setAttribute('data-x-additional-src', $sCallResult); + } + } + } + + $bHasExternals = true; + } + else if ('data:image/' === \strtolower(\substr($sSrc, 0, 11))) + { + $oElement->setAttribute('src', $sSrc); + } + else + { + $oElement->setAttribute('data-x-broken-src', $sSrc); + } + } + } + + $sBackground = $oElement->hasAttribute('background') + ? \trim($oElement->getAttribute('background')) : ''; + $sBackgroundColor = $oElement->hasAttribute('bgcolor') + ? \trim($oElement->getAttribute('bgcolor')) : ''; + + if (!empty($sBackground) || !empty($sBackgroundColor)) + { + $aStyles = array(); + $sStyles = $oElement->hasAttribute('style') + ? \trim(\trim(\trim($oElement->getAttribute('style')), ';')) : ''; + + if (!empty($sBackground)) + { + $aStyles[] = 'background-image: url(\''.$sBackground.'\')'; + $oElement->removeAttribute('background'); + } + + if (!empty($sBackgroundColor)) + { + $aStyles[] = 'background-color: '.$sBackgroundColor; + $oElement->removeAttribute('bgcolor'); + } + + $oElement->setAttribute('style', (empty($sStyles) ? '' : $sStyles.'; ').\implode('; ', $aStyles)); + } + + if ($oElement->hasAttribute('style') && !$oElement->hasAttribute('data-x-skip-style')) + { + $oElement->setAttribute('style', + \MailSo\Base\HtmlUtils::ClearStyle($oElement->getAttribute('style'), $oElement, $bHasExternals, + $aFoundCIDs, $aContentLocationUrls, $aFoundedContentLocationUrls, $bDoNotReplaceExternalUrl, $fAdditionalExternalFilter)); + } + + $oElement->removeAttribute('data-x-skip-style'); + + if (\MailSo\Config::$HtmlStrictDebug && 0 < \count($aRemovedAttrs)) + { + unset($aRemovedAttrs['class'], $aRemovedAttrs['target'], $aRemovedAttrs['id'], $aRemovedAttrs['name']); + + $aRemovedAttrs = \array_keys($aRemovedAttrs); + if (0 < \count($aRemovedAttrs)) + { + $oElement->setAttribute('data-removed-attrs', \implode(',', $aRemovedAttrs)); + } + } + } + + $sResult = \MailSo\Base\HtmlUtils::GetTextFromDom($oDom, $bWrapByFakeHtmlAndBodyDiv); + unset($oDom); + + return $sResult; + } + + /** + * @param string $sHtml + * @param array $aFoundCids = array() + * @param array|null $mFoundDataURL = null + * @param array $aFoundedContentLocationUrls = array() + * + * @return string + */ + public static function BuildHtml($sHtml, &$aFoundCids = array(), &$mFoundDataURL = null, &$aFoundedContentLocationUrls = array()) + { + $oDom = \MailSo\Base\HtmlUtils::GetDomFromText($sHtml); + + \MailSo\Base\HtmlUtils::ClearTags($oDom); + unset($sHtml); + + $aNodes = $oDom->getElementsByTagName('*'); + foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement) + { + $sTagNameLower = \strtolower($oElement->tagName); + + if ($oElement->hasAttribute('data-x-src-cid')) + { + $sCid = $oElement->getAttribute('data-x-src-cid'); + $oElement->removeAttribute('data-x-src-cid'); + + if (!empty($sCid)) + { + $aFoundCids[] = $sCid; + + @$oElement->removeAttribute('src'); + $oElement->setAttribute('src', 'cid:'.$sCid); + } + } + + if ($oElement->hasAttribute('data-x-src-location')) + { + $sSrc = $oElement->getAttribute('data-x-src-location'); + $oElement->removeAttribute('data-x-src-location'); + + if (!empty($sSrc)) + { + $aFoundedContentLocationUrls[] = $sSrc; + + @$oElement->removeAttribute('src'); + $oElement->setAttribute('src', $sSrc); + } + } + + if ($oElement->hasAttribute('data-x-broken-src')) + { + $oElement->setAttribute('src', $oElement->getAttribute('data-x-broken-src')); + $oElement->removeAttribute('data-x-broken-src'); + } + + if ($oElement->hasAttribute('data-x-src')) + { + $oElement->setAttribute('src', $oElement->getAttribute('data-x-src')); + $oElement->removeAttribute('data-x-src'); + } + + if ($oElement->hasAttribute('data-x-href')) + { + $oElement->setAttribute('href', $oElement->getAttribute('data-x-href')); + $oElement->removeAttribute('data-x-href'); + } + + if ($oElement->hasAttribute('data-x-style-cid-name') && $oElement->hasAttribute('data-x-style-cid')) + { + $sCidName = $oElement->getAttribute('data-x-style-cid-name'); + $sCid = $oElement->getAttribute('data-x-style-cid'); + + $oElement->removeAttribute('data-x-style-cid-name'); + $oElement->removeAttribute('data-x-style-cid'); + if (!empty($sCidName) && !empty($sCid) && \in_array($sCidName, + array('background-image', 'background', 'list-style-image', 'content'))) + { + $sStyles = ''; + if ($oElement->hasAttribute('style')) + { + $sStyles = \trim(\trim($oElement->getAttribute('style')), ';'); + } + + $sBack = $sCidName.': url(cid:'.$sCid.')'; + $sStyles = \preg_replace('/'.\preg_quote($sCidName, '/').':\s?[^;]+/i', $sBack, $sStyles); + if (false === \strpos($sStyles, $sBack)) + { + $sStyles .= empty($sStyles) ? '': '; '; + $sStyles .= $sBack; + } + + $oElement->setAttribute('style', $sStyles); + $aFoundCids[] = $sCid; + } + } + + foreach (array( + 'data-x-additional-src', 'data-x-additional-style-url', 'data-removed-attrs', + 'data-original', 'data-x-div-type', 'data-wrp', 'data-bind' + ) as $sName) + { + if ($oElement->hasAttribute($sName)) + { + $oElement->removeAttribute($sName); + } + } + + if ($oElement->hasAttribute('data-x-style-url')) + { + $sAddStyles = $oElement->getAttribute('data-x-style-url'); + $oElement->removeAttribute('data-x-style-url'); + + if (!empty($sAddStyles)) + { + $sStyles = ''; + if ($oElement->hasAttribute('style')) + { + $sStyles = \trim(\trim($oElement->getAttribute('style')), ';'); + } + + $oElement->setAttribute('style', (empty($sStyles) ? '' : $sStyles.'; ').$sAddStyles); + } + } + + if ('img' === $sTagNameLower && \is_array($mFoundDataURL)) + { + $sSrc = $oElement->getAttribute('src'); + if ('data:image/' === \strtolower(\substr($sSrc, 0, 11))) + { + $sHash = \md5($sSrc); + $mFoundDataURL[$sHash] = $sSrc; + + $oElement->setAttribute('src', 'cid:'.$sHash); + } + } + } + + $sResult = \MailSo\Base\HtmlUtils::GetTextFromDom($oDom, false); + unset($oDom); + + return ''. + ''.$sResult.''; + } + + /** + * @param string $sText + * @param bool $bLinksWithTargetBlank = true + * + * @return string + */ + public static function ConvertPlainToHtml($sText, $bLinksWithTargetBlank = true) + { + $sText = \trim($sText); + if (0 === \strlen($sText)) + { + return ''; + } + + $sText = \MailSo\Base\LinkFinder::NewInstance() + ->Text($sText) + ->UseDefaultWrappers($bLinksWithTargetBlank) + ->CompileText() + ; + + $sText = \str_replace("\r", '', $sText); + + $aText = \explode("\n", $sText); + unset($sText); + + $bIn = false; + $bDo = true; + do + { + $bDo = false; + $aNextText = array(); + foreach ($aText as $sTextLine) + { + $bStart = 0 === \strpos(\ltrim($sTextLine), '>'); + if ($bStart && !$bIn) + { + $bDo = true; + $bIn = true; + $aNextText[] = '
'; + $aNextText[] = \substr(\ltrim($sTextLine), 4); + } + else if (!$bStart && $bIn) + { + $bIn = false; + $aNextText[] = '
'; + $aNextText[] = $sTextLine; + } + else if ($bStart && $bIn) + { + $aNextText[] = \substr(\ltrim($sTextLine), 4); + } + else + { + $aNextText[] = $sTextLine; + } + } + + if ($bIn) + { + $bIn = false; + $aNextText[] = '
'; + } + + $aText = $aNextText; + } + while ($bDo); + + $sText = \join("\n", $aText); + unset($aText); + + $sText = \preg_replace('/[\n][ ]+/', "\n", $sText); +// $sText = \preg_replace('/[\s]+([\s])/', '\\1', $sText); + + $sText = \preg_replace('/
[\s]+/i', '
', $sText); + $sText = \preg_replace('/[\s]+<\/blockquote>/i', '
', $sText); + + $sText = \preg_replace('/<\/blockquote>([\n]{0,2})
/i', '\\1', $sText); + $sText = \preg_replace('/[\n]{3,}/', "\n\n", $sText); + + $sText = \strtr($sText, array( + "\n" => "
", + "\t" => '   ', + ' ' => '  ' + )); + + return $sText; + } + + /** + * @param string $sText + * + * @return string + */ + public static function ConvertHtmlToPlain($sText) + { + $sText = \trim(\stripslashes($sText)); + $sText = \MailSo\Base\Utils::StripSpaces($sText); + + $sText = \preg_replace(array( + "/\r/", + "/[\n\t]+/", + '/]*>.*?<\/script>/i', + '/]*>.*?<\/style>/i', + '/]*>.*?<\/title>/i', + '/]*>(.+?)<\/h[123]>/i', + '/]*>(.+?)<\/h[456]>/i', + '/]*>/i', + '/]*>/i', + '/]*>(.+?)<\/b>/i', + '/]*>(.+?)<\/i>/i', + '/(]*>|<\/ul>)/i', + '/(]*>|<\/ol>)/i', + '/]*>/i', + '/]*href="([^"]+)"[^>]*>(.+?)<\/a>/i', + '/]*>/i', + '/(]*>|<\/table>)/i', + '/(]*>|<\/tr>)/i', + '/]*>(.+?)<\/td>/i', + '/]*>(.+?)<\/th>/i', + '/ /i', + '/"/i', + '/>/i', + '/</i', + '/&/i', + '/©/i', + '/™/i', + '/“/', + '/”/', + '/–/', + '/’/', + '/&/', + '/©/', + '/™/', + '/—/', + '/“/', + '/”/', + '/•/', + '/®/i', + '/•/i', + '/&[&;]+;/i', + '/'/', + '/ /' + ), array( + '', + ' ', + '', + '', + '', + "\n\n\\1\n\n", + "\n\n\\1\n\n", + "\n\n\t", + "\n", + '\\1', + '\\1', + "\n\n", + "\n\n", + "\n\t* ", + '\\2 (\\1)', + "\n------------------------------------\n", + "\n", + "\n", + "\t\\1\n", + "\t\\1\n", + ' ', + '"', + '>', + '<', + '&', + '(c)', + '(tm)', + '"', + '"', + '-', + "'", + '&', + '(c)', + '(tm)', + '--', + '"', + '"', + '*', + '(R)', + '*', + '', + '\'', + '' + ), $sText); + + $sText = \str_ireplace('
',"\n
", $sText); + $sText = \strip_tags($sText, ''); + $sText = \preg_replace("/\n\\s+\n/", "\n", $sText); + $sText = \preg_replace("/[\n]{3,}/", "\n\n", $sText); + + return \trim($sText); + } +} diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Imap/FetchResponse.php b/rainloop/v/0.0.0/app/libraries/MailSo/Imap/FetchResponse.php index 84e94a104..99501f692 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Imap/FetchResponse.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Imap/FetchResponse.php @@ -1,274 +1,273 @@ -oImapResponse = $oImapResponse; - $this->aEnvelopeCache = null; - } - - /** - * @param \MailSo\Imap\Response $oImapResponse - * @return \MailSo\Imap\FetchResponse - */ - public static function NewInstance($oImapResponse) - { - return new self($oImapResponse); - } - - /** - * @param bool $bForce = false - * - * @return array|null - */ - public function GetEnvelope($bForce = false) - { - if (null === $this->aEnvelopeCache || $bForce) - { - $this->aEnvelopeCache = $this->GetFetchValue(Enumerations\FetchType::ENVELOPE); - } - return $this->aEnvelopeCache; - } - - /** - * @param int $iIndex - * @param mixed $mNullResult = null - * - * @return mixed - */ - public function GetFetchEnvelopeValue($iIndex, $mNullResult) - { - return self::findEnvelopeIndex($this->GetEnvelope(), $iIndex, $mNullResult); - } - - /** - * @param int $iIndex - * @param string $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1 - * - * @return \MailSo\Mime\EmailCollection|null - */ - public function GetFetchEnvelopeEmailCollection($iIndex, $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1) - { - $oResult = null; - $aEmails = $this->GetFetchEnvelopeValue($iIndex, null); - if (is_array($aEmails) && 0 < count($aEmails)) - { - $oResult = \MailSo\Mime\EmailCollection::NewInstance(); - foreach ($aEmails as $aEmailItem) - { - if (is_array($aEmailItem) && 4 === count($aEmailItem)) - { - $sDisplayName = \MailSo\Base\Utils::DecodeHeaderValue( - self::findEnvelopeIndex($aEmailItem, 0, ''), $sParentCharset); - - $sRemark = \MailSo\Base\Utils::DecodeHeaderValue( - self::findEnvelopeIndex($aEmailItem, 1, ''), $sParentCharset); - - $sLocalPart = self::findEnvelopeIndex($aEmailItem, 2, ''); - $sDomainPart = self::findEnvelopeIndex($aEmailItem, 3, ''); - - if (0 < strlen($sLocalPart) && 0 < strlen($sDomainPart)) - { - $oResult->Add( - \MailSo\Mime\Email::NewInstance( - $sLocalPart.'@'.$sDomainPart, $sDisplayName, $sRemark) - ); - } - } - } - } - - return $oResult; - } - - /** - * @param string $sRfc822SubMimeIndex = '' - * - * @return \MailSo\Imap\BodyStructure|null - */ - public function GetFetchBodyStructure($sRfc822SubMimeIndex = '') - { - $oBodyStructure = null; - $aBodyStructureArray = $this->GetFetchValue(Enumerations\FetchType::BODYSTRUCTURE); - - if (is_array($aBodyStructureArray)) - { - if (0 < strlen($sRfc822SubMimeIndex)) - { - $oBodyStructure = BodyStructure::NewInstanceFromRfc822SubPart($aBodyStructureArray, $sRfc822SubMimeIndex); - } - else - { - $oBodyStructure = BodyStructure::NewInstance($aBodyStructureArray); - } - } - - return $oBodyStructure; - } - - /** - * @param string $sFetchItemName - * - * @return mixed - */ - public function GetFetchValue($sFetchItemName) - { - $mReturn = null; - $bNextIsValue = false; - - if (Enumerations\FetchType::INDEX === $sFetchItemName) - { - $mReturn = $this->oImapResponse->ResponseList[1]; - } - else if (isset($this->oImapResponse->ResponseList[3]) && \is_array($this->oImapResponse->ResponseList[3])) - { - foreach ($this->oImapResponse->ResponseList[3] as $mItem) - { - if ($bNextIsValue) - { - $mReturn = $mItem; - break; - } - - if ($sFetchItemName === $mItem) - { - $bNextIsValue = true; - } - } - } - - return $mReturn; - } - - /** - * @param string $sRfc822SubMimeIndex = '' - * - * @return string - */ - public function GetHeaderFieldsValue($sRfc822SubMimeIndex = '') - { - $sReturn = ''; - $bNextIsValue = false; - - $sRfc822SubMimeIndex = 0 < \strlen($sRfc822SubMimeIndex) ? ''.$sRfc822SubMimeIndex.'.' : ''; - - if (isset($this->oImapResponse->ResponseList[3]) && \is_array($this->oImapResponse->ResponseList[3])) - { - foreach ($this->oImapResponse->ResponseList[3] as $mItem) - { - if ($bNextIsValue) - { - $sReturn = (string) $mItem; - break; - } - - if (\is_string($mItem) && ( - $mItem === 'BODY['.$sRfc822SubMimeIndex.'HEADER]' || - 0 === \strpos($mItem, 'BODY['.$sRfc822SubMimeIndex.'HEADER.FIELDS') || - $mItem === 'BODY['.$sRfc822SubMimeIndex.'MIME]')) - { - $bNextIsValue = true; - } - } - } - - return $sReturn; - } - - private static function findFetchUidAndSize($aList) - { - $bUid = false; - $bSize = false; - if (is_array($aList)) - { - foreach ($aList as $mItem) - { - if (\MailSo\Imap\Enumerations\FetchType::UID === $mItem) - { - $bUid = true; - } - else if (\MailSo\Imap\Enumerations\FetchType::RFC822_SIZE === $mItem) - { - $bSize = true; - } - } - } - - return $bUid && $bSize; - } - - /** - * @param \MailSo\Imap\Response $oImapResponse - * - * @return bool - */ - public static function IsValidFetchImapResponse($oImapResponse) - { - return ( - $oImapResponse - && true !== $oImapResponse->IsStatusResponse - && \MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType - && 3 < count($oImapResponse->ResponseList) && 'FETCH' === $oImapResponse->ResponseList[2] - && is_array($oImapResponse->ResponseList[3]) - ); - } - - /** - * @param \MailSo\Imap\Response $oImapResponse - * - * @return bool - */ - public static function IsNotEmptyFetchImapResponse($oImapResponse) - { - return ( - $oImapResponse - && self::IsValidFetchImapResponse($oImapResponse) - && isset($oImapResponse->ResponseList[3]) - && self::findFetchUidAndSize($oImapResponse->ResponseList[3]) - ); - } - - /** - * @param array $aEnvelope - * @param int $iIndex - * @param mixed $mNullResult = null - * - * @return mixed - */ - private static function findEnvelopeIndex($aEnvelope, $iIndex, $mNullResult) - { - return (isset($aEnvelope[$iIndex]) && 'NIL' !== $aEnvelope[$iIndex] && '' !== $aEnvelope[$iIndex]) - ? $aEnvelope[$iIndex] : $mNullResult; - } -} +oImapResponse = $oImapResponse; + $this->aEnvelopeCache = null; + } + + /** + * @param \MailSo\Imap\Response $oImapResponse + * @return \MailSo\Imap\FetchResponse + */ + public static function NewInstance($oImapResponse) + { + return new self($oImapResponse); + } + + /** + * @param bool $bForce = false + * + * @return array|null + */ + public function GetEnvelope($bForce = false) + { + if (null === $this->aEnvelopeCache || $bForce) + { + $this->aEnvelopeCache = $this->GetFetchValue(Enumerations\FetchType::ENVELOPE); + } + return $this->aEnvelopeCache; + } + + /** + * @param int $iIndex + * @param mixed $mNullResult = null + * + * @return mixed + */ + public function GetFetchEnvelopeValue($iIndex, $mNullResult) + { + return self::findEnvelopeIndex($this->GetEnvelope(), $iIndex, $mNullResult); + } + + /** + * @param int $iIndex + * @param string $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1 + * + * @return \MailSo\Mime\EmailCollection|null + */ + public function GetFetchEnvelopeEmailCollection($iIndex, $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1) + { + $oResult = null; + $aEmails = $this->GetFetchEnvelopeValue($iIndex, null); + if (is_array($aEmails) && 0 < count($aEmails)) + { + $oResult = \MailSo\Mime\EmailCollection::NewInstance(); + foreach ($aEmails as $aEmailItem) + { + if (is_array($aEmailItem) && 4 === count($aEmailItem)) + { + $sDisplayName = \MailSo\Base\Utils::DecodeHeaderValue( + self::findEnvelopeIndex($aEmailItem, 0, ''), $sParentCharset); + +// $sRemark = \MailSo\Base\Utils::DecodeHeaderValue( +// self::findEnvelopeIndex($aEmailItem, 1, ''), $sParentCharset); + + $sLocalPart = self::findEnvelopeIndex($aEmailItem, 2, ''); + $sDomainPart = self::findEnvelopeIndex($aEmailItem, 3, ''); + + if (0 < strlen($sLocalPart) && 0 < strlen($sDomainPart)) + { + $oResult->Add( + \MailSo\Mime\Email::NewInstance($sLocalPart.'@'.$sDomainPart, $sDisplayName) + ); + } + } + } + } + + return $oResult; + } + + /** + * @param string $sRfc822SubMimeIndex = '' + * + * @return \MailSo\Imap\BodyStructure|null + */ + public function GetFetchBodyStructure($sRfc822SubMimeIndex = '') + { + $oBodyStructure = null; + $aBodyStructureArray = $this->GetFetchValue(Enumerations\FetchType::BODYSTRUCTURE); + + if (is_array($aBodyStructureArray)) + { + if (0 < strlen($sRfc822SubMimeIndex)) + { + $oBodyStructure = BodyStructure::NewInstanceFromRfc822SubPart($aBodyStructureArray, $sRfc822SubMimeIndex); + } + else + { + $oBodyStructure = BodyStructure::NewInstance($aBodyStructureArray); + } + } + + return $oBodyStructure; + } + + /** + * @param string $sFetchItemName + * + * @return mixed + */ + public function GetFetchValue($sFetchItemName) + { + $mReturn = null; + $bNextIsValue = false; + + if (Enumerations\FetchType::INDEX === $sFetchItemName) + { + $mReturn = $this->oImapResponse->ResponseList[1]; + } + else if (isset($this->oImapResponse->ResponseList[3]) && \is_array($this->oImapResponse->ResponseList[3])) + { + foreach ($this->oImapResponse->ResponseList[3] as $mItem) + { + if ($bNextIsValue) + { + $mReturn = $mItem; + break; + } + + if ($sFetchItemName === $mItem) + { + $bNextIsValue = true; + } + } + } + + return $mReturn; + } + + /** + * @param string $sRfc822SubMimeIndex = '' + * + * @return string + */ + public function GetHeaderFieldsValue($sRfc822SubMimeIndex = '') + { + $sReturn = ''; + $bNextIsValue = false; + + $sRfc822SubMimeIndex = 0 < \strlen($sRfc822SubMimeIndex) ? ''.$sRfc822SubMimeIndex.'.' : ''; + + if (isset($this->oImapResponse->ResponseList[3]) && \is_array($this->oImapResponse->ResponseList[3])) + { + foreach ($this->oImapResponse->ResponseList[3] as $mItem) + { + if ($bNextIsValue) + { + $sReturn = (string) $mItem; + break; + } + + if (\is_string($mItem) && ( + $mItem === 'BODY['.$sRfc822SubMimeIndex.'HEADER]' || + 0 === \strpos($mItem, 'BODY['.$sRfc822SubMimeIndex.'HEADER.FIELDS') || + $mItem === 'BODY['.$sRfc822SubMimeIndex.'MIME]')) + { + $bNextIsValue = true; + } + } + } + + return $sReturn; + } + + private static function findFetchUidAndSize($aList) + { + $bUid = false; + $bSize = false; + if (is_array($aList)) + { + foreach ($aList as $mItem) + { + if (\MailSo\Imap\Enumerations\FetchType::UID === $mItem) + { + $bUid = true; + } + else if (\MailSo\Imap\Enumerations\FetchType::RFC822_SIZE === $mItem) + { + $bSize = true; + } + } + } + + return $bUid && $bSize; + } + + /** + * @param \MailSo\Imap\Response $oImapResponse + * + * @return bool + */ + public static function IsValidFetchImapResponse($oImapResponse) + { + return ( + $oImapResponse + && true !== $oImapResponse->IsStatusResponse + && \MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType + && 3 < count($oImapResponse->ResponseList) && 'FETCH' === $oImapResponse->ResponseList[2] + && is_array($oImapResponse->ResponseList[3]) + ); + } + + /** + * @param \MailSo\Imap\Response $oImapResponse + * + * @return bool + */ + public static function IsNotEmptyFetchImapResponse($oImapResponse) + { + return ( + $oImapResponse + && self::IsValidFetchImapResponse($oImapResponse) + && isset($oImapResponse->ResponseList[3]) + && self::findFetchUidAndSize($oImapResponse->ResponseList[3]) + ); + } + + /** + * @param array $aEnvelope + * @param int $iIndex + * @param mixed $mNullResult = null + * + * @return mixed + */ + private static function findEnvelopeIndex($aEnvelope, $iIndex, $mNullResult) + { + return (isset($aEnvelope[$iIndex]) && 'NIL' !== $aEnvelope[$iIndex] && '' !== $aEnvelope[$iIndex]) + ? $aEnvelope[$iIndex] : $mNullResult; + } +} diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php b/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php index 22d39b28b..3d387515e 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php @@ -1,2665 +1,2665 @@ -oLogger = null; - - $this->oImapClient = \MailSo\Imap\ImapClient::NewInstance(); - $this->oImapClient->SetTimeOuts(10, \MailSo\Config::$ImapTimeout); - } - - /** - * @return \MailSo\Mail\MailClient - */ - public static function NewInstance() - { - return new self(); - } - - /** - * @return \MailSo\Imap\ImapClient - */ - public function ImapClient() - { - return $this->oImapClient; - } - - /** - * @param string $sServerName - * @param int $iPort = 143 - * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT - * @param bool $bVerifySsl = false - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function Connect($sServerName, $iPort = 143, - $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, $bVerifySsl = false) - { - $this->oImapClient->Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl); - return $this; - } - - /** - * @param string $sLogin - * @param string $sPassword - * @param string $sProxyAuthUser = '' - * @param bool $bUseAuthPlainIfSupported = true - * @param bool $bUseAuthCramMd5IfSupported = true - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\LoginException - */ - public function Login($sLogin, $sPassword, $sProxyAuthUser = '', - $bUseAuthPlainIfSupported = true, $bUseAuthCramMd5IfSupported = true) - { - $this->oImapClient->Login($sLogin, $sPassword, $sProxyAuthUser, $bUseAuthPlainIfSupported, $bUseAuthCramMd5IfSupported); - return $this; - } - - /** - * @param string $sXOAuth2Token - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\LoginException - */ - public function LoginWithXOauth2($sXOAuth2Token) - { - $this->oImapClient->LoginWithXOauth2($sXOAuth2Token); - return $this; - } - - /** - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Net\Exceptions\Exception - */ - public function Logout() - { - $this->oImapClient->Logout(); - return $this; - } - - /** - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Net\Exceptions\Exception - */ - public function Disconnect() - { - $this->oImapClient->Disconnect(); - return $this; - } - - /** - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Net\Exceptions\Exception - */ - public function LogoutAndDisconnect() - { - return $this->Logout()->Disconnect(); - } - - /** - * @return bool - */ - public function IsConnected() - { - return $this->oImapClient->IsConnected(); - } - - /** - * @return bool - */ - public function IsLoggined() - { - return $this->oImapClient->IsLoggined(); - } - - /** - * @return string - */ - private function getEnvelopeOrHeadersRequestStringForSimpleList() - { - return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( - \MailSo\Mime\Enumerations\Header::RETURN_PATH, - \MailSo\Mime\Enumerations\Header::RECEIVED, - \MailSo\Mime\Enumerations\Header::MIME_VERSION, - \MailSo\Mime\Enumerations\Header::FROM_, - \MailSo\Mime\Enumerations\Header::TO_, - \MailSo\Mime\Enumerations\Header::CC, - \MailSo\Mime\Enumerations\Header::SENDER, - \MailSo\Mime\Enumerations\Header::REPLY_TO, - \MailSo\Mime\Enumerations\Header::DATE, - \MailSo\Mime\Enumerations\Header::SUBJECT, - \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, - \MailSo\Mime\Enumerations\Header::LIST_UNSUBSCRIBE, - ), true); - } - - /** - * @return string - */ - private function getEnvelopeOrHeadersRequestString() - { - if (\MailSo\Config::$MessageAllHeaders) - { - return \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK; - } - - return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( - \MailSo\Mime\Enumerations\Header::RETURN_PATH, - \MailSo\Mime\Enumerations\Header::RECEIVED, - \MailSo\Mime\Enumerations\Header::MIME_VERSION, - \MailSo\Mime\Enumerations\Header::MESSAGE_ID, - \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, - \MailSo\Mime\Enumerations\Header::FROM_, - \MailSo\Mime\Enumerations\Header::TO_, - \MailSo\Mime\Enumerations\Header::CC, - \MailSo\Mime\Enumerations\Header::BCC, - \MailSo\Mime\Enumerations\Header::SENDER, - \MailSo\Mime\Enumerations\Header::REPLY_TO, - \MailSo\Mime\Enumerations\Header::DELIVERED_TO, - \MailSo\Mime\Enumerations\Header::IN_REPLY_TO, - \MailSo\Mime\Enumerations\Header::REFERENCES, - \MailSo\Mime\Enumerations\Header::DATE, - \MailSo\Mime\Enumerations\Header::SUBJECT, - \MailSo\Mime\Enumerations\Header::SENSITIVITY, - \MailSo\Mime\Enumerations\Header::X_MSMAIL_PRIORITY, - \MailSo\Mime\Enumerations\Header::IMPORTANCE, - \MailSo\Mime\Enumerations\Header::X_PRIORITY, - \MailSo\Mime\Enumerations\Header::X_DRAFT_INFO, - \MailSo\Mime\Enumerations\Header::RETURN_RECEIPT_TO, - \MailSo\Mime\Enumerations\Header::DISPOSITION_NOTIFICATION_TO, - \MailSo\Mime\Enumerations\Header::X_CONFIRM_READING_TO, - \MailSo\Mime\Enumerations\Header::AUTHENTICATION_RESULTS, - \MailSo\Mime\Enumerations\Header::X_DKIM_AUTHENTICATION_RESULTS, - \MailSo\Mime\Enumerations\Header::LIST_UNSUBSCRIBE, - ), true); -// -// return \MailSo\Imap\Enumerations\FetchType::ENVELOPE; - } - - /** - * @param string $sFolderName - * @param string $sMessageFlag - * @param bool $bSetAction = true - * @param bool $sSkipUnsupportedFlag = false - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - * @throws \MailSo\Mail\Exceptions\Exception - */ - public function MessageSetFlagToAll($sFolderName, $sMessageFlag, $bSetAction = true, $sSkipUnsupportedFlag = false) - { - $this->oImapClient->FolderSelect($sFolderName); - - $oFolderInfo = $this->oImapClient->FolderCurrentInformation(); - if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag)) - { - if (!$sSkipUnsupportedFlag) - { - throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag "'.$sMessageFlag.'" is not supported.'); - } - } - - if ($oFolderInfo && 0 < $oFolderInfo->Exists) - { - $sStoreAction = $bSetAction - ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT - : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT - ; - - $this->oImapClient->MessageStoreFlag('1:*', false, array($sMessageFlag), $sStoreAction); - } - } - - /** - * @param string $sFolderName - * @param array $aIndexRange - * @param bool $bIndexIsUid - * @param string $sMessageFlag - * @param bool $bSetAction = true - * @param bool $sSkipUnsupportedFlag = false - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - * @throws \MailSo\Mail\Exceptions\Exception - */ - public function MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, $sMessageFlag, $bSetAction = true, $sSkipUnsupportedFlag = false) - { - $this->oImapClient->FolderSelect($sFolderName); - - $oFolderInfo = $this->oImapClient->FolderCurrentInformation(); - if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag)) - { - if (!$sSkipUnsupportedFlag) - { - throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag "'.$sMessageFlag.'" is not supported.'); - } - } - else - { - $sStoreAction = $bSetAction - ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT - : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT - ; - - $this->oImapClient->MessageStoreFlag(\MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), - $bIndexIsUid, array($sMessageFlag), $sStoreAction); - } - } - - /** - * @param string $sFolderName - * @param array $aIndexRange - * @param bool $bIndexIsUid - * @param bool $bSetAction = true - * @param bool $sSkipUnsupportedFlag = false - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageSetFlagged($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true, $sSkipUnsupportedFlag = false) - { - $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, - \MailSo\Imap\Enumerations\MessageFlag::FLAGGED, $bSetAction, $sSkipUnsupportedFlag); - } - - /** - * @param string $sFolderName - * @param bool $bSetAction = true - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageSetSeenToAll($sFolderName, $bSetAction = true) - { - $this->MessageSetFlagToAll($sFolderName, \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction, true); - } - - /** - * @param string $sFolderName - * @param array $aIndexRange - * @param bool $bIndexIsUid - * @param bool $bSetAction = true - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageSetSeen($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true) - { - $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, - \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction, true); - } - - /** - * @param string $sFolderName - * @param int $iIndex - * @param bool $bIndexIsUid = true - * @param \MailSo\Cache\CacheClient $oCacher = null - * @param int $iBodyTextLimit = null - * - * @return \MailSo\Mail\Message|false - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function Message($sFolderName, $iIndex, $bIndexIsUid = true, $oCacher = null, $iBodyTextLimit = null) - { - if (!\MailSo\Base\Validator::RangeInt($iIndex, 1)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderSelect($sFolderName); - - $oBodyStructure = null; - $oMessage = false; - - $aBodyPeekMimeIndexes = array(); - $aSignatureMimeIndexes = array(); - - $aFetchResponse = $this->oImapClient->Fetch(array(\MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE), $iIndex, $bIndexIsUid); - if (0 < \count($aFetchResponse) && isset($aFetchResponse[0])) - { - $oBodyStructure = $aFetchResponse[0]->GetFetchBodyStructure(); - if ($oBodyStructure) - { - $aTextParts = $oBodyStructure->SearchHtmlOrPlainParts(); - if (is_array($aTextParts) && 0 < \count($aTextParts)) - { - foreach ($aTextParts as $oPart) - { - $aBodyPeekMimeIndexes[] = array($oPart->PartID(), $oPart->Size()); - } - } - - $aSignatureParts = $oBodyStructure->SearchByContentType('application/pgp-signature'); - if (is_array($aSignatureParts) && 0 < \count($aSignatureParts)) - { - foreach ($aSignatureParts as $oPart) - { - $aSignatureMimeIndexes[] = $oPart->PartID(); - } - } - } - } - - $aFetchItems = array( - \MailSo\Imap\Enumerations\FetchType::INDEX, - \MailSo\Imap\Enumerations\FetchType::UID, - \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE, - \MailSo\Imap\Enumerations\FetchType::INTERNALDATE, - \MailSo\Imap\Enumerations\FetchType::FLAGS, - $this->getEnvelopeOrHeadersRequestString() - ); - - if (0 < \count($aBodyPeekMimeIndexes)) - { - foreach ($aBodyPeekMimeIndexes as $aTextMimeData) - { - $sLine = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$aTextMimeData[0].']'; - if (\is_numeric($iBodyTextLimit) && 0 < $iBodyTextLimit && $iBodyTextLimit < $aTextMimeData[1]) - { - $sLine .= '<0.'.((int) $iBodyTextLimit).'>'; - } - - $aFetchItems[] = $sLine; - } - } - - if (0 < \count($aSignatureMimeIndexes)) - { - foreach ($aSignatureMimeIndexes as $sTextMimeIndex) - { - $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sTextMimeIndex.']'; - } - } - - if (!$oBodyStructure) - { - $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE; - } - - $aFetchResponse = $this->oImapClient->Fetch($aFetchItems, $iIndex, $bIndexIsUid); - if (0 < \count($aFetchResponse)) - { - $oMessage = \MailSo\Mail\Message::NewFetchResponseInstance( - $sFolderName, $aFetchResponse[0], $oBodyStructure); - } - - return $oMessage; - } - - /** - * @param mixed $mCallback - * @param string $sFolderName - * @param int $iIndex - * @param bool $bIndexIsUid = true, - * @param string $sMimeIndex = '' - * - * @return bool - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageMimeStream($mCallback, $sFolderName, $iIndex, $bIndexIsUid = true, $sMimeIndex = '') - { - if (!is_callable($mCallback)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderSelect($sFolderName); - - $sFileName = ''; - $sContentType = ''; - $sMailEncodingName = ''; - - $sMimeIndex = trim($sMimeIndex); - $aFetchResponse = $this->oImapClient->Fetch(array( - 0 === \strlen($sMimeIndex) - ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK - : \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.'.MIME]' - ), $iIndex, $bIndexIsUid); - - if (0 < \count($aFetchResponse)) - { - $sMime = $aFetchResponse[0]->GetFetchValue( - 0 === \strlen($sMimeIndex) - ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER - : \MailSo\Imap\Enumerations\FetchType::BODY.'['.$sMimeIndex.'.MIME]' - ); - - if (0 < \strlen($sMime)) - { - $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sMime); - - if (0 < \strlen($sMimeIndex)) - { - $sFileName = $oHeaders->ParameterValue( - \MailSo\Mime\Enumerations\Header::CONTENT_DISPOSITION, - \MailSo\Mime\Enumerations\Parameter::FILENAME); - - if (0 === \strlen($sFileName)) - { - $sFileName = $oHeaders->ParameterValue( - \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, - \MailSo\Mime\Enumerations\Parameter::NAME); - } - - $sMailEncodingName = $oHeaders->ValueByName( - \MailSo\Mime\Enumerations\Header::CONTENT_TRANSFER_ENCODING); - - $sContentType = $oHeaders->ValueByName( - \MailSo\Mime\Enumerations\Header::CONTENT_TYPE); - } - else - { - $sSubject = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT); - - $sFileName = 0 === \strlen($sSubject) ? (string) $iIndex : $sSubject; - $sFileName .= '.eml'; - - $sContentType = 'message/rfc822'; - } - } - } - - $aFetchResponse = $this->oImapClient->Fetch(array( - array(\MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.']', - function ($sParent, $sLiteralAtomUpperCase, $rImapLiteralStream) use ($mCallback, $sMimeIndex, $sMailEncodingName, $sContentType, $sFileName) - { - if (0 < \strlen($sLiteralAtomUpperCase)) - { - if (is_resource($rImapLiteralStream) && 'FETCH' === $sParent) - { - $rMessageMimeIndexStream = (0 === \strlen($sMailEncodingName)) - ? $rImapLiteralStream - : \MailSo\Base\StreamWrappers\Binary::CreateStream($rImapLiteralStream, - \MailSo\Base\StreamWrappers\Binary::GetInlineDecodeOrEncodeFunctionName( - $sMailEncodingName, true)); - - \call_user_func($mCallback, $rMessageMimeIndexStream, $sContentType, $sFileName, $sMimeIndex); - } - } - } - )), $iIndex, $bIndexIsUid); - - return ($aFetchResponse && 1 === \count($aFetchResponse)); - } - - /** - * @param string $sFolder - * @param array $aIndexRange - * @param bool $bIndexIsUid - * @param bool $bUseExpunge = true - * @param bool $bExpungeAll = false - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageDelete($sFolder, $aIndexRange, $bIndexIsUid, $bUseExpunge = true, $bExpungeAll = false) - { - if (0 === \strlen($sFolder) || !\is_array($aIndexRange) || 0 === \count($aIndexRange)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderSelect($sFolder); - - $sIndexRange = \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange); - - $this->oImapClient->MessageStoreFlag($sIndexRange, $bIndexIsUid, - array(\MailSo\Imap\Enumerations\MessageFlag::DELETED), - \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT - ); - - if ($bUseExpunge) - { - $this->oImapClient->MessageExpunge($bIndexIsUid ? $sIndexRange : '', $bIndexIsUid, $bExpungeAll); - } - - return $this; - } - - /** - * @param string $sFromFolder - * @param string $sToFolder - * @param array $aIndexRange - * @param bool $bIndexIsUid - * @param bool $bUseMoveSupported = false - * @param bool $bExpungeAll = false - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageMove($sFromFolder, $sToFolder, $aIndexRange, $bIndexIsUid, $bUseMoveSupported = false, $bExpungeAll = false) - { - if (0 === \strlen($sFromFolder) || 0 === \strlen($sToFolder) || - !\is_array($aIndexRange) || 0 === \count($aIndexRange)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderSelect($sFromFolder); - - if ($bUseMoveSupported && $this->oImapClient->IsSupported('MOVE')) - { - $this->oImapClient->MessageMove($sToFolder, - \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid); - } - else - { - $this->oImapClient->MessageCopy($sToFolder, - \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid); - - $this->MessageDelete($sFromFolder, $aIndexRange, $bIndexIsUid, true, $bExpungeAll); - } - - return $this; - } - - /** - * @param string $sFromFolder - * @param string $sToFolder - * @param array $aIndexRange - * @param bool $bIndexIsUid - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageCopy($sFromFolder, $sToFolder, $aIndexRange, $bIndexIsUid) - { - if (0 === \strlen($sFromFolder) || 0 === \strlen($sToFolder) || - !\is_array($aIndexRange) || 0 === \count($aIndexRange)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderSelect($sFromFolder); - $this->oImapClient->MessageCopy($sToFolder, - \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid); - - return $this; - } - - /** - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderUnSelect() - { - if ($this->oImapClient->IsSelected()) - { - $this->oImapClient->FolderUnSelect(); - } - - return $this; - } - - /** - * @param resource $rMessageStream - * @param int $iMessageStreamSize - * @param string $sFolderToSave - * @param array $aAppendFlags = null - * @param int $iUid = null - * - * @return \MailSo\Mail\MailClient - */ - public function MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags = null, &$iUid = null) - { - if (!\is_resource($rMessageStream) || 0 === \strlen($sFolderToSave)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->MessageAppendStream( - $sFolderToSave, $rMessageStream, $iMessageStreamSize, $aAppendFlags, $iUid); - - return $this; - } - - /** - * @param string $sMessageFileName - * @param string $sFolderToSave - * @param array $aAppendFlags = null - * @param int &$iUid = null - * - * @return \MailSo\Mail\MailClient - */ - public function MessageAppendFile($sMessageFileName, $sFolderToSave, $aAppendFlags = null, &$iUid = null) - { - if (!@\is_file($sMessageFileName) || !@\is_readable($sMessageFileName)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $iMessageStreamSize = \filesize($sMessageFileName); - $rMessageStream = \fopen($sMessageFileName, 'rb'); - - $this->MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags, $iUid); - - if (\is_resource($rMessageStream)) - { - @fclose($rMessageStream); - } - - return $this; - } - - /** - * @param string $sFolderName - * @param int $iCount - * @param int $iUnseenCount - * @param string $sUidNext - * @param string $sHighestModSeq - * - * @return void - */ - protected function initFolderValues($sFolderName, &$iCount, &$iUnseenCount, - &$sUidNext, &$sHighestModSeq = '') - { - $aTypes = array( - \MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES, - \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN, - \MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT - ); - - if ($this->oImapClient->IsSupported('CONDSTORE')) - { - $aTypes[] = \MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ; - } - - $aFolderStatus = $this->oImapClient->FolderStatus($sFolderName, $aTypes); - - $iCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES]) - ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES] : 0; - - $iUnseenCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN]) - ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0; - - $sUidNext = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT]) - ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT] : '0'; - - $sHighestModSeq = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ]) - ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ] : ''; - - if ($this->IsGmail() && - ('INBOX' === $sFolderName || '[gmail]' === \strtolower(\substr($sFolderName, 0, 7)))) - { - $oFolder = $this->oImapClient->FolderCurrentInformation(); - if ($oFolder && null !== $oFolder->Exists && $oFolder->FolderName === $sFolderName) - { - $iSubCount = (int) $oFolder->Exists; - if (0 < $iSubCount && $iSubCount < $iCount) - { - $iCount = $iSubCount; - } - } - } - } - - /** - * @return string - */ - public function GenerateImapClientHash() - { - return \md5('ImapClientHash/'. - $this->oImapClient->GetLogginedUser().'@'. - $this->oImapClient->GetConnectedHost().':'. - $this->oImapClient->GetConnectedPort() - ); - } - - /** - * @param string $sFolder - * @param int $iCount - * @param int $iUnseenCount - * @param string $sUidNext - * @param string $sHighestModSeq = '' - * - * @return string - */ - public function GenerateFolderHash($sFolder, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq = '') - { - $iUnseenCount = 0; // unneccessery - return \md5('FolderHash/'.$sFolder.'-'.$iCount.'-'.$iUnseenCount.'-'.$sUidNext.'-'. - $sHighestModSeq.'-'.$this->GenerateImapClientHash().'-'. - \MailSo\Config::$MessageListPermanentFilter - ); - } - - /** - * @param string $sFolderName - * @param string $sPrevUidNext - * @param string $sCurrentUidNext - * - * @return array - */ - private function getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sCurrentUidNext) - { - $aNewMessages = array(); - - if (0 < \strlen($sPrevUidNext) && (string) $sPrevUidNext !== (string) $sCurrentUidNext) - { - $this->oImapClient->FolderSelect($sFolderName); - - $aFetchResponse = $this->oImapClient->Fetch(array( - \MailSo\Imap\Enumerations\FetchType::INDEX, - \MailSo\Imap\Enumerations\FetchType::UID, - \MailSo\Imap\Enumerations\FetchType::FLAGS, - \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( - \MailSo\Mime\Enumerations\Header::FROM_, - \MailSo\Mime\Enumerations\Header::SUBJECT, - \MailSo\Mime\Enumerations\Header::CONTENT_TYPE - )) - ), $sPrevUidNext.':*', true); - - if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse)) - { - foreach ($aFetchResponse as /* @var $oFetchResponse \MailSo\Imap\FetchResponse */ $oFetchResponse) - { - $aFlags = \array_map('strtolower', $oFetchResponse->GetFetchValue( - \MailSo\Imap\Enumerations\FetchType::FLAGS)); - - if (!\in_array(\strtolower(\MailSo\Imap\Enumerations\MessageFlag::SEEN), $aFlags)) - { - $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID); - $sHeaders = $oFetchResponse->GetHeaderFieldsValue(); - - $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sHeaders); - - $sContentTypeCharset = $oHeaders->ParameterValue( - \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, - \MailSo\Mime\Enumerations\Parameter::CHARSET - ); - - $sCharset = ''; - if (0 < \strlen($sContentTypeCharset)) - { - $sCharset = $sContentTypeCharset; - } - - if (0 < \strlen($sCharset)) - { - $oHeaders->SetParentCharset($sCharset); - } - - $aNewMessages[] = array( - 'Folder' => $sFolderName, - 'Uid' => $sUid, - 'Subject' => $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT, 0 === \strlen($sCharset)), - 'From' => $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::FROM_, 0 === \strlen($sCharset)) - ); - } - } - } - } - - return $aNewMessages; - } - - /** - * @param string $sFolderName - * @param string $sPrevUidNext = '' - * @param array $aUids = '' - * - * @return string - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderInformation($sFolderName, $sPrevUidNext = '', $aUids = array()) - { - $aFlags = array(); - - $bSelect = false; - if ($this->IsGmail() && - ('INBOX' === $sFolderName || '[gmail]' === \strtolower(\substr($sFolderName, 0, 7)))) - { - $this->oImapClient->FolderSelect($sFolderName); - $bSelect = true; - } - - if (\is_array($aUids) && 0 < \count($aUids)) - { - if (!$bSelect) - { - $this->oImapClient->FolderSelect($sFolderName); - } - - $aFetchResponse = $this->oImapClient->Fetch(array( - \MailSo\Imap\Enumerations\FetchType::INDEX, - \MailSo\Imap\Enumerations\FetchType::UID, - \MailSo\Imap\Enumerations\FetchType::FLAGS - ), \MailSo\Base\Utils::PrepearFetchSequence($aUids), true); - - if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse)) - { - foreach ($aFetchResponse as $oFetchResponse) - { - $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID); - $aFlags[(\is_numeric($sUid) ? (int) $sUid : 0)] = - $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::FLAGS); - } - } - } - - $iCount = 0; - $iUnseenCount = 0; - $sUidNext = '0'; - $sHighestModSeq = ''; - - $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq); - - $aResult = array( - 'Folder' => $sFolderName, - 'Hash' => $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq), - 'MessageCount' => $iCount, - 'MessageUnseenCount' => $iUnseenCount, - 'UidNext' => $sUidNext, - 'Flags' => $aFlags, - 'HighestModSeq' => $sHighestModSeq, - 'NewMessages' => 'INBOX' === $sFolderName ? - $this->getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sUidNext) : array() - ); - - return $aResult; - } - - /** - * @param string $sFolderName - * - * @return string - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function FolderHash($sFolderName) - { - $iCount = 0; - $iUnseenCount = 0; - $sUidNext = '0'; - $sHighestModSeq = ''; - - $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq); - - return $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq); - } - - /** - * @return int - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function InboxUnreadCount() - { - $aFolderStatus = $this->oImapClient->FolderStatus('INBOX', array( - \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN - )); - - $iResult = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN]) ? - (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0; - - return 0 < $iResult ? $iResult : 0; - } - - /** - * @return bool - */ - public function IsGmail() - { - return 'ssl://imap.gmail.com' === \strtolower($this->oImapClient->GetConnectedHost()); - } - - /** - * @param string $sSearch - * @param bool $bDetectGmail = true - * - * @return string - */ - private function escapeSearchString($sSearch, $bDetectGmail = true) - { - return !\MailSo\Base\Utils::IsAscii($sSearch) - ? '{'.\strlen($sSearch).'}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch); -// return ($bDetectGmail && !\MailSo\Base\Utils::IsAscii($sSearch) && $this->IsGmail()) -// ? '{'.\strlen($sSearch).'+}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch); - } - - /** - * @param string $sDate - * @param int $iTimeZoneOffset - * - * @return int - */ - private function parseSearchDate($sDate, $iTimeZoneOffset) - { - $iResult = 0; - if (0 < \strlen($sDate)) - { - $oDateTime = \DateTime::createFromFormat('Y.m.d', $sDate, \MailSo\Base\DateTimeHelper::GetUtcTimeZoneObject()); - return $oDateTime ? $oDateTime->getTimestamp() - $iTimeZoneOffset : 0; - } - - return $iResult; - } - - /** - * @param string $sSize - * - * @return int - */ - private function parseFriendlySize($sSize) - { - $sSize = preg_replace('/[^0-9bBkKmM]/', '', $sSize); - - $iResult = 0; - $aMatch = array(); - - if (\preg_match('/([\d]+)(B|KB|M|MB|G|GB)$/i', $sSize, $aMatch) && isset($aMatch[1], $aMatch[2])) - { - $iResult = (int) $aMatch[1]; - switch (\strtoupper($aMatch[2])) - { - case 'K': - case 'KB': - $iResult *= 1024; - case 'M': - case 'MB': - $iResult *= 1024; - case 'G': - case 'GB': - $iResult *= 1024; - } - } - else - { - $iResult = (int) $sSize; - } - - return $iResult; - } - - /** - * @param string $sSearch - * - * @return array - */ - private function parseSearchString($sSearch) - { - $aResult = array( - 'OTHER' => '' - ); - - $aCache = array(); - - $sReg = 'e?mail|from|to|subject|has|is|date|text|body|size|larger|bigger|smaller|maxsize|minsize'; - - $sSearch = \MailSo\Base\Utils::StripSpaces($sSearch); - $sSearch = \trim(\preg_replace('/('.$sReg.'): /i', '\\1:', $sSearch)); - - $mMatch = array(); - \preg_match_all('/".*?(? $sName) - { - if (isset($mMatch[2][$iIndex]) && 0 < \strlen($mMatch[2][$iIndex])) - { - $sName = \strtoupper($sName); - $sValue = $mMatch[2][$iIndex]; - switch ($sName) - { - case 'TEXT': - case 'BODY': - case 'EMAIL': - case 'MAIL': - case 'FROM': - case 'TO': - case 'SUBJECT': - case 'IS': - case 'HAS': - case 'SIZE': - case 'SMALLER': - case 'LARGER': - case 'BIGGER': - case 'MAXSIZE': - case 'MINSIZE': - case 'DATE': - if ('MAIL' === $sName) - { - $sName = 'EMAIL'; - } - if ('BODY' === $sName) - { - $sName = 'TEXT'; - } - if ('SIZE' === $sName || 'BIGGER' === $sName || 'MINSIZE' === $sName) - { - $sName = 'LARGER'; - } - if ('MAXSIZE' === $sName) - { - $sName = 'SMALLER'; - } - $aResult[$sName] = $sValue; - break; - } - } - } - } - - $aResult['OTHER'] = $sSearch; - foreach ($aResult as $sName => $sValue) - { - if (isset($aCache[$sValue])) - { - $aResult[$sName] = \trim($aCache[$sValue], '"\' '); - } - } - - return $aResult; - } - - /** - * @param string $sSearch - * @param string $sFilter - * @param int $iTimeZoneOffset = 0 - * @param bool $bUseCache = true - * - * @return string - */ - private function getImapSearchCriterias($sSearch, $sFilter, $iTimeZoneOffset = 0, &$bUseCache = true) - { - $bUseCache = true; - $iTimeFilter = 0; - $aCriteriasResult = array(); - - if (0 < \MailSo\Config::$MessageListDateFilter) - { - $iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter; - $iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD)); - } - - if (0 < \strlen(\trim($sSearch))) - { - $sGmailRawSearch = ''; - $sResultBodyTextSearch = ''; - - $aLines = $this->parseSearchString($sSearch); - $bIsGmail = $this->oImapClient->IsSupported('X-GM-EXT-1'); - - if (1 === \count($aLines) && isset($aLines['OTHER'])) - { - $sValue = $this->escapeSearchString($aLines['OTHER']); - - if (\MailSo\Config::$MessageListFastSimpleSearch) - { - $aCriteriasResult[] = 'OR OR OR'; - $aCriteriasResult[] = 'FROM'; - $aCriteriasResult[] = $sValue; - $aCriteriasResult[] = 'TO'; - $aCriteriasResult[] = $sValue; - $aCriteriasResult[] = 'CC'; - $aCriteriasResult[] = $sValue; - $aCriteriasResult[] = 'SUBJECT'; - $aCriteriasResult[] = $sValue; - } - else - { - $aCriteriasResult[] = 'TEXT'; - $aCriteriasResult[] = $sValue; - } - } - else - { - if (isset($aLines['EMAIL'])) - { - $sValue = $this->escapeSearchString($aLines['EMAIL']); - - $aCriteriasResult[] = 'OR OR'; - $aCriteriasResult[] = 'FROM'; - $aCriteriasResult[] = $sValue; - $aCriteriasResult[] = 'TO'; - $aCriteriasResult[] = $sValue; - $aCriteriasResult[] = 'CC'; - $aCriteriasResult[] = $sValue; - - unset($aLines['EMAIL']); - } - - if (isset($aLines['TO'])) - { - $sValue = $this->escapeSearchString($aLines['TO']); - - $aCriteriasResult[] = 'OR'; - $aCriteriasResult[] = 'TO'; - $aCriteriasResult[] = $sValue; - $aCriteriasResult[] = 'CC'; - $aCriteriasResult[] = $sValue; - - unset($aLines['TO']); - } - - $sMainText = ''; - foreach ($aLines as $sName => $sRawValue) - { - if ('' === \trim($sRawValue)) - { - continue; - } - - $sValue = $this->escapeSearchString($sRawValue); - switch ($sName) - { - case 'FROM': - $aCriteriasResult[] = 'FROM'; - $aCriteriasResult[] = $sValue; - break; - case 'SUBJECT': - $aCriteriasResult[] = 'SUBJECT'; - $aCriteriasResult[] = $sValue; - break; - case 'OTHER': - case 'TEXT': - $sMainText .= ' '.$sRawValue; - break; - case 'HAS': - $aValue = \explode(',', \strtolower($sRawValue)); - $aValue = \array_map('trim', $aValue); - - $aCompareArray = array('file', 'files', 'attach', 'attachs', 'attachment', 'attachments'); - if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue))) - { - if ($bIsGmail) - { - $sGmailRawSearch .= ' has:attachment'; - } - else - { - // Simple, is not detailed search (Sometimes doesn't work) - $aCriteriasResult[] = 'OR OR OR'; - $aCriteriasResult[] = 'HEADER Content-Type application/'; - $aCriteriasResult[] = 'HEADER Content-Type multipart/m'; - $aCriteriasResult[] = 'HEADER Content-Type multipart/signed'; - $aCriteriasResult[] = 'HEADER Content-Type multipart/report'; - } - } - - case 'IS': - $aValue = \explode(',', \strtolower($sRawValue)); - $aValue = \array_map('trim', $aValue); - - $aCompareArray = array('flag', 'flagged', 'star', 'starred', 'pinned'); - $aCompareArray2 = array('unflag', 'unflagged', 'unstar', 'unstarred', 'unpinned'); - if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue))) - { - $aCriteriasResult[] = 'FLAGGED'; - $bUseCache = false; - } - else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue))) - { - $aCriteriasResult[] = 'UNFLAGGED'; - $bUseCache = false; - } - - $aCompareArray = array('unread', 'unseen'); - $aCompareArray2 = array('read', 'seen'); - if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue))) - { - $aCriteriasResult[] = 'UNSEEN'; - $bUseCache = false; - } - else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue))) - { - $aCriteriasResult[] = 'SEEN'; - $bUseCache = false; - } - break; - - case 'LARGER': - $aCriteriasResult[] = 'LARGER'; - $aCriteriasResult[] = $this->parseFriendlySize($sRawValue); - break; - case 'SMALLER': - $aCriteriasResult[] = 'SMALLER'; - $aCriteriasResult[] = $this->parseFriendlySize($sRawValue); - break; - case 'DATE': - $iDateStampFrom = $iDateStampTo = 0; - - $sDate = $sRawValue; - $aDate = \explode('/', $sDate); - - if (\is_array($aDate) && 2 === \count($aDate)) - { - if (0 < \strlen($aDate[0])) - { - $iDateStampFrom = $this->parseSearchDate($aDate[0], $iTimeZoneOffset); - } - - if (0 < \strlen($aDate[1])) - { - $iDateStampTo = $this->parseSearchDate($aDate[1], $iTimeZoneOffset); - $iDateStampTo += 60 * 60 * 24; - } - } - else - { - if (0 < \strlen($sDate)) - { - $iDateStampFrom = $this->parseSearchDate($sDate, $iTimeZoneOffset); - $iDateStampTo = $iDateStampFrom + 60 * 60 * 24; - } - } - - if (0 < $iDateStampFrom) - { - $aCriteriasResult[] = 'SINCE'; - $aCriteriasResult[] = \gmdate('j-M-Y', $iTimeFilter > $iDateStampFrom ? - $iTimeFilter : $iDateStampFrom); - - $iTimeFilter = 0; - } - - if (0 < $iDateStampTo) - { - $aCriteriasResult[] = 'BEFORE'; - $aCriteriasResult[] = \gmdate('j-M-Y', $iDateStampTo); - } - break; - } - } - - if ('' !== \trim($sMainText)) - { - $sMainText = \trim(\MailSo\Base\Utils::StripSpaces($sMainText), '"'); - if ($bIsGmail) - { - $sGmailRawSearch .= ' '.$sMainText; - } - else - { - $sResultBodyTextSearch .= ' '.$sMainText; - } - } - } - - $sGmailRawSearch = \trim($sGmailRawSearch); - if ($bIsGmail && 0 < \strlen($sGmailRawSearch)) - { - $aCriteriasResult[] = 'X-GM-RAW'; - $aCriteriasResult[] = $this->escapeSearchString($sGmailRawSearch, false); - } - - $sResultBodyTextSearch = \trim($sResultBodyTextSearch); - if (0 < \strlen($sResultBodyTextSearch)) - { - $aCriteriasResult[] = 'BODY'; - $aCriteriasResult[] = $this->escapeSearchString($sResultBodyTextSearch); - } - } - - $sCriteriasResult = \trim(\implode(' ', $aCriteriasResult)); - - if (0 < $iTimeFilter) - { - $sCriteriasResult .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter); - } - - $sCriteriasResult = \trim($sCriteriasResult); - if (\MailSo\Config::$MessageListUndeletedOnly) - { - $sCriteriasResult = \trim($sCriteriasResult.' UNDELETED'); - } - - $sFilter = \trim($sFilter); - if ('' !== $sFilter) - { - $sCriteriasResult .= ' '.$sFilter; - } - - $sCriteriasResult = \trim($sCriteriasResult); - if ('' !== \MailSo\Config::$MessageListPermanentFilter) - { - $sCriteriasResult = \trim($sCriteriasResult.' '.\MailSo\Config::$MessageListPermanentFilter); - } - - $sCriteriasResult = \trim($sCriteriasResult); - if ('' === $sCriteriasResult) - { - $sCriteriasResult = 'ALL'; - } - - return $sCriteriasResult; - } - - /** - * @param array $aThreads - * @return array - */ - private function threadArrayMap($aThreads) - { - $aNew = array(); - foreach ($aThreads as $mItem) - { - if (!\is_array($mItem)) - { - $aNew[] = $mItem; - } - else - { - $mMap = $this->threadArrayMap($mItem); - if (\is_array($mMap) && 0 < \count($mMap)) - { - $aNew = \array_merge($aNew, $mMap); - } - } - } - - return $aNew; - } - - /** - * @param array $aThreads - * - * @return array - */ - private function compileThreadArray($aThreads) - { - $aResult = array(); - foreach ($aThreads as $mItem) - { - if (\is_array($mItem)) - { - $aMap = $this->threadArrayMap($mItem); - if (\is_array($aMap)) - { - if (1 < \count($aMap)) - { - $aResult[] = $aMap; - } - else if (0 < \count($aMap)) - { - $aResult[] = $aMap[0]; - } - } - } - else - { - $aResult[] = $mItem; - } - } - - return $aResult; - } - - /** - * @param string $sFolderName - * @param string $sFolderHash - * @param array $aIndexOrUids - * @param \MailSo\Cache\CacheClient $oCacher - * @param bool $bCacheOnly = false - * - * @return array - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageListThreadsMap($sFolderName, $sFolderHash, $aIndexOrUids, $oCacher, $bCacheOnly = false) - { - $iThreadLimit = \MailSo\Config::$LargeThreadLimit; - - $sSearchHash = ''; - if (0 < \MailSo\Config::$MessageListDateFilter) - { - $iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter; - $iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD)); - - $sSearchHash .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter); - } - - if ('' === \trim($sSearchHash)) - { - $sSearchHash = 'ALL'; - } - - if ($oCacher && $oCacher->IsInited()) - { - $sSerializedHashKey = - 'ThreadsMapSorted/'.$sSearchHash.'/'. - 'Limit='.$iThreadLimit.'/'.$sFolderName.'/'.$sFolderHash; - - if ($this->oLogger) - { - $this->oLogger->Write($sSerializedHashKey); - } - - $sSerializedUids = $oCacher->Get($sSerializedHashKey); - if (!empty($sSerializedUids)) - { - $aSerializedUids = @\json_decode($sSerializedUids, true); - if (isset($aSerializedUids['ThreadsUids']) && \is_array($aSerializedUids['ThreadsUids'])) - { - if ($this->oLogger) - { - $this->oLogger->Write('Get Serialized Thread UIDS from cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aSerializedUids['ThreadsUids']).']'); - } - - return $aSerializedUids['ThreadsUids']; - } - } - } - - if ($bCacheOnly) - { - return null; - } - - $this->oImapClient->FolderExamine($sFolderName); - - $aThreadUids = array(); - try - { - $aThreadUids = $this->oImapClient->MessageSimpleThread($sSearchHash); - } - catch (\MailSo\Imap\Exceptions\RuntimeException $oException) - { - unset($oException); - $aThreadUids = array(); - } - - $aResult = array(); - $aCompiledThreads = $this->compileThreadArray($aThreadUids); - - foreach ($aCompiledThreads as $mData) - { - if (\is_array($mData)) - { - foreach ($mData as $mSubData) - { - $aResult[(int) $mSubData] = - \array_diff($mData, array((int) $mSubData)); - } - } - else if (\is_int($mData) || \is_string($mData)) - { - $aResult[(int) $mData] = (int) $mData; - } - } - - $aParentsMap = array(); - foreach ($aIndexOrUids as $iUid) - { - if (isset($aResult[$iUid]) && \is_array($aResult[$iUid])) - { - foreach ($aResult[$iUid] as $iTempUid) - { - $aParentsMap[$iTempUid] = $iUid; - if (isset($aResult[$iTempUid])) - { - unset($aResult[$iTempUid]); - } - } - } - } - - $aSortedThreads = array(); - foreach ($aIndexOrUids as $iUid) - { - if (isset($aResult[$iUid])) - { - $aSortedThreads[$iUid] = $iUid; - } - } - - foreach ($aIndexOrUids as $iUid) - { - if (!isset($aSortedThreads[$iUid]) && - isset($aParentsMap[$iUid]) && - isset($aSortedThreads[$aParentsMap[$iUid]])) - { - if (!\is_array($aSortedThreads[$aParentsMap[$iUid]])) - { - $aSortedThreads[$aParentsMap[$iUid]] = array(); - } - - $aSortedThreads[$aParentsMap[$iUid]][] = $iUid; - } - } - - $aResult = $aSortedThreads; - unset($aParentsMap, $aSortedThreads); - - $aTemp = array(); - foreach ($aResult as $iUid => $mValue) - { - if (0 < $iThreadLimit && \is_array($mValue) && $iThreadLimit < \count($mValue)) - { - $aParts = \array_chunk($mValue, $iThreadLimit); - if (0 < count($aParts)) - { - foreach ($aParts as $iIndex => $aItem) - { - if (0 === $iIndex) - { - $aResult[$iUid] = $aItem; - } - else if (0 < $iIndex && \is_array($aItem)) - { - $mFirst = \array_shift($aItem); - if (!empty($mFirst)) - { - $aTemp[$mFirst] = 0 < \count($aItem) ? $aItem : $mFirst; - } - } - } - } - } - } - - foreach ($aTemp as $iUid => $mValue) - { - $aResult[$iUid] = $mValue; - } - - unset($aTemp); - - $aLastResult = array(); - foreach ($aIndexOrUids as $iUid) - { - if (isset($aResult[$iUid])) - { - $aLastResult[$iUid] = $aResult[$iUid]; - } - } - - $aResult = $aLastResult; - unset($aLastResult); - - if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHashKey)) - { - $oCacher->Set($sSerializedHashKey, @\json_encode(array( - 'ThreadsUids' => $aResult - ))); - - if ($this->oLogger) - { - $this->oLogger->Write('Save Serialized Thread UIDS to cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aResult).']'); - } - } - - return $aResult; - } - - /** - * @param \MailSo\Mail\MessageCollection &$oMessageCollection - * @param array $aRequestIndexOrUids - * @param bool $bIndexAsUid - * @param bool $bSimple = false - * - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageListByRequestIndexOrUids(&$oMessageCollection, $aRequestIndexOrUids, $bIndexAsUid, $bSimple = false) - { - if (\is_array($aRequestIndexOrUids) && 0 < \count($aRequestIndexOrUids)) - { - $aFetchResponse = $this->oImapClient->Fetch(array( - \MailSo\Imap\Enumerations\FetchType::INDEX, - \MailSo\Imap\Enumerations\FetchType::UID, - \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE, - \MailSo\Imap\Enumerations\FetchType::INTERNALDATE, - \MailSo\Imap\Enumerations\FetchType::FLAGS, - \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE, - $bSimple ? - $this->getEnvelopeOrHeadersRequestStringForSimpleList() : - $this->getEnvelopeOrHeadersRequestString() - ), \MailSo\Base\Utils::PrepearFetchSequence($aRequestIndexOrUids), $bIndexAsUid); - - if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse)) - { - $aFetchIndexArray = array(); - $oFetchResponseItem = null; - foreach ($aFetchResponse as /* @var $oFetchResponseItem \MailSo\Imap\FetchResponse */ &$oFetchResponseItem) - { - $aFetchIndexArray[($bIndexAsUid) - ? $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID) - : $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::INDEX)] =& $oFetchResponseItem; - - unset($oFetchResponseItem); - } - - foreach ($aRequestIndexOrUids as $iFUid) - { - if (isset($aFetchIndexArray[$iFUid])) - { - $oMessageCollection->Add( - Message::NewFetchResponseInstance( - $oMessageCollection->FolderName, $aFetchIndexArray[$iFUid])); - } - } - } - } - } - - /** - * @return bool - * - * @throws \MailSo\Net\Exceptions\Exception - */ - public function IsThreadsSupported() - { - return $this->oImapClient->IsSupported('THREAD=REFS') || - $this->oImapClient->IsSupported('THREAD=REFERENCES') || - $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT'); - } - - /** - * @param string $sFolderName - * @param array $aUids - * - * @return \MailSo\Mail\MessageCollection - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageListSimple($sFolderName, $aUids) - { - if (0 === \strlen($sFolderName) || !\MailSo\Base\Validator::NotEmptyArray($aUids)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderExamine($sFolderName); - - $oMessageCollection = \MailSo\Mail\MessageCollection::NewInstance(); - $oMessageCollection->FolderName = $sFolderName; - - $this->MessageListByRequestIndexOrUids($oMessageCollection, $aUids, true, true); - - return $oMessageCollection->GetAsArray(); - } - - /** - * @param \MailSo\Cache\CacheClient|null $oCacher - * @param string $sSearch - * @param string $sFilter - * @param string $sFolderName - * @param string $sFolderHash - * @param bool $bUseSortIfSupported = false - * - * @return array - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function GetUids($oCacher, $sSearch, $sFilter, $sFolderName, $sFolderHash, $bUseSortIfSupported = false) - { - $aResultUids = false; - $bUidsFromCacher = false; - $bUseCacheAfterSearch = true; - - $sSerializedHash = ''; - $sSerializedLog = ''; - - $bUseSortIfSupported = $bUseSortIfSupported ? !!$this->oImapClient->IsSupported('SORT') : false; - - if (0 < \strlen($sSearch)) - { - $bUseSortIfSupported = false; - } - - $sSearchCriterias = $this->getImapSearchCriterias($sSearch, $sFilter, 0, $bUseCacheAfterSearch); - if ($bUseCacheAfterSearch && $oCacher && $oCacher->IsInited()) - { - $sSerializedHash = 'GetUids/'. - ($bUseSortIfSupported ? 'S': 'N').'/'. - $this->GenerateImapClientHash().'/'. - $sFolderName.'/'.$sSearchCriterias; - - $sSerializedLog = '"'.$sFolderName.'" / '.$sSearchCriterias.''; - - $sSerialized = $oCacher->Get($sSerializedHash); - if (!empty($sSerialized)) - { - $aSerialized = @\json_decode($sSerialized, true); - if (\is_array($aSerialized) && isset($aSerialized['FolderHash'], $aSerialized['Uids']) && - $sFolderHash === $aSerialized['FolderHash'] && - \is_array($aSerialized['Uids']) - ) - { - if ($this->oLogger) - { - $this->oLogger->Write('Get Serialized UIDS from cache ('.$sSerializedLog.') [count:'.\count($aSerialized['Uids']).']'); - } - - $aResultUids = $aSerialized['Uids']; - $bUidsFromCacher = true; - } - } - } - - if (!\is_array($aResultUids)) - { - $aResultUids = $bUseSortIfSupported ? - $this->oImapClient->MessageSimpleSort(array('REVERSE ARRIVAL'), $sSearchCriterias, true) : - $this->oImapClient->MessageSimpleSearch($sSearchCriterias, true, \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? '' : 'UTF-8') - ; - - if (!$bUidsFromCacher && $bUseCacheAfterSearch && \is_array($aResultUids) && $oCacher && $oCacher->IsInited() && 0 < \strlen($sSerializedHash)) - { - $oCacher->Set($sSerializedHash, @\json_encode(array( - 'FolderHash' => $sFolderHash, - 'Uids' => $aResultUids - ))); - - if ($this->oLogger) - { - $this->oLogger->Write('Save Serialized UIDS to cache ('.$sSerializedLog.') [count:'.\count($aResultUids).']'); - } - } - } - - return \is_array($aResultUids) ? $aResultUids : array(); - } - - /** - * @param string $sFolderName - * @param int $iOffset = 0 - * @param int $iLimit = 10 - * @param string $sSearch = '' - * @param string $sPrevUidNext = '' - * @param \MailSo\Cache\CacheClient|null $oCacher = null - * @param bool $bUseSortIfSupported = false - * @param bool $bUseThreadSortIfSupported = false - * @param bool $bUseESearchOrESortRequest = false - * @param string $sThreadUid = '' - * @param string $sFilter = '' - * - * @return \MailSo\Mail\MessageCollection - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Net\Exceptions\Exception - * @throws \MailSo\Imap\Exceptions\Exception - */ - public function MessageList($sFolderName, $iOffset = 0, $iLimit = 10, $sSearch = '', $sPrevUidNext = '', $oCacher = null, - $bUseSortIfSupported = false, $bUseThreadSortIfSupported = false, $sThreadUid = '', $sFilter = '') - { - $sFilter = \trim($sFilter); - $sSearch = \trim($sSearch); - if (!\MailSo\Base\Validator::RangeInt($iOffset, 0) || - !\MailSo\Base\Validator::RangeInt($iLimit, 0, 999)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $bUseFilter = '' !== $sFilter; - - $this->oImapClient->FolderSelect($sFolderName); - - $oMessageCollection = MessageCollection::NewInstance(); - $oMessageCollection->FolderName = $sFolderName; - $oMessageCollection->Offset = $iOffset; - $oMessageCollection->Limit = $iLimit; - $oMessageCollection->Search = $sSearch; - $oMessageCollection->ThreadUid = $sThreadUid; - $oMessageCollection->Filtered = '' !== \MailSo\Config::$MessageListPermanentFilter; - - $aUids = array(); - $mAllSortedUids = null; - $mAllThreads = null; - - $iThreadUid = empty($sThreadUid) ? 0 : (int) $sThreadUid; - - $iMessageRealCount = 0; - $iMessageUnseenCount = 0; - $sUidNext = '0'; - $sHighestModSeq = ''; - - $bUseSortIfSupported = $bUseSortIfSupported ? $this->oImapClient->IsSupported('SORT') : false; - - $bUseThreadSortIfSupported = $bUseThreadSortIfSupported ? - ($this->oImapClient->IsSupported('THREAD=REFS') || $this->oImapClient->IsSupported('THREAD=REFERENCES') || $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT')) : false; - - if (!empty($sThreadUid) && !$bUseThreadSortIfSupported) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - if (!$oCacher || !($oCacher instanceof \MailSo\Cache\CacheClient)) - { - $oCacher = null; - } - - $this->initFolderValues($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext, $sHighestModSeq); - - if ($bUseFilter) - { - $iMessageUnseenCount = 0; - } - - $oMessageCollection->FolderHash = $this->GenerateFolderHash( - $sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext, $sHighestModSeq); - - $oMessageCollection->UidNext = $sUidNext; - - if (empty($sThreadUid) && 0 < \strlen($sPrevUidNext) && 'INBOX' === $sFolderName) - { - $oMessageCollection->NewMessages = $this->getFolderNextMessageInformation( - $sFolderName, $sPrevUidNext, $sUidNext); - } - - $bSearch = false; - $bMessageListOptimization = 0 < \MailSo\Config::$MessageListCountLimitTrigger && - \MailSo\Config::$MessageListCountLimitTrigger < $iMessageRealCount; - - if ($bMessageListOptimization) - { - $bUseSortIfSupported = false; - $bUseThreadSortIfSupported = false; - } - - if (0 < $iMessageRealCount && !$bMessageListOptimization) - { - $mAllSortedUids = $this->GetUids($oCacher, '', $sFilter, - $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $bUseSortIfSupported); - - $mAllThreads = $bUseThreadSortIfSupported ? $this->MessageListThreadsMap( - $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $mAllSortedUids, $oCacher) : null; - - if ($bUseThreadSortIfSupported && 0 < $iThreadUid && \is_array($mAllThreads)) - { - $aUids = array(); - $iResultRootUid = 0; - - if (isset($mAllThreads[$iThreadUid])) - { - $iResultRootUid = $iThreadUid; - if (\is_array($mAllThreads[$iThreadUid])) - { - $aUids = $mAllThreads[$iThreadUid]; - } - } - else - { - foreach ($mAllThreads as $iRootUid => $mSubUids) - { - if (\is_array($mSubUids) && \in_array($iThreadUid, $mSubUids)) - { - $iResultRootUid = $iRootUid; - $aUids = $mSubUids; - continue; - } - } - } - - if (0 < $iResultRootUid && \in_array($iResultRootUid, $mAllSortedUids)) - { - \array_unshift($aUids, $iResultRootUid); - } - } - else if ($bUseThreadSortIfSupported && \is_array($mAllThreads)) - { - $aUids = \array_keys($mAllThreads); - } - else - { - $bUseThreadSortIfSupported = false; - $aUids = $mAllSortedUids; - } - - if (0 < \strlen($sSearch) && \is_array($aUids)) - { - $aSearchedUids = $this->GetUids($oCacher, $sSearch, $sFilter, - $oMessageCollection->FolderName, $oMessageCollection->FolderHash); - - if (\is_array($aSearchedUids) && 0 < \count($aSearchedUids)) - { - $aFlippedSearchedUids = \array_flip($aSearchedUids); - - $bSearch = true; - $aNewUids = array(); - - foreach ($aUids as $iUid) - { - if (isset($aFlippedSearchedUids[$iUid])) - { - $aNewUids[] = $iUid; - } - else if ($bUseThreadSortIfSupported && 0 === $iThreadUid && isset($mAllThreads[$iUid]) && \is_array($mAllThreads[$iUid])) - { - foreach ($mAllThreads[$iUid] as $iSubUid) - { - if (isset($aFlippedSearchedUids[$iSubUid])) - { - $aNewUids[] = $iUid; - continue; - } - } - } - } - - $aUids = \array_unique($aNewUids); - unset($aNewUids); - } - else - { - $aUids = array(); - } - } - - if (\is_array($aUids)) - { - $oMessageCollection->MessageCount = $iMessageRealCount; - $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount; - $oMessageCollection->MessageResultCount = \count($aUids); - - if (0 < \count($aUids)) - { - $aRequestUids = \array_slice($aUids, $iOffset, $iLimit); - $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestUids, true); - } - } - } - else if (0 < $iMessageRealCount) - { - if ($this->oLogger) - { - $this->oLogger->Write('List optimization (count: '.$iMessageRealCount. - ', limit:'.\MailSo\Config::$MessageListCountLimitTrigger.')'); - } - - $oMessageCollection->MessageCount = $iMessageRealCount; - $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount; - - if (0 < \strlen($sSearch) || $bUseFilter) - { - $aUids = $this->GetUids($oCacher, $sSearch, $sFilter, - $oMessageCollection->FolderName, $oMessageCollection->FolderHash); - - if (0 < \count($aUids)) - { - $oMessageCollection->MessageResultCount = \count($aUids); - - $aRequestUids = \array_slice($aUids, $iOffset, $iLimit); - $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestUids, true); - } - else - { - $oMessageCollection->MessageResultCount = 0; - } - } - else - { - $oMessageCollection->MessageResultCount = $iMessageRealCount; - - if (1 < $iMessageRealCount) - { - $aRequestIndexes = \array_slice(array_reverse(range(1, $iMessageRealCount)), $iOffset, $iLimit); - } - else - { - $aRequestIndexes = \array_slice(array(1), $iOffset, $iLimit); - } - - $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestIndexes, false); - } - } - - if ($bUseThreadSortIfSupported && 0 === $iThreadUid && \is_array($mAllThreads) && 0 < \count($mAllThreads)) - { - $oMessageCollection->ForeachList(function (/* @var $oMessage \MailSo\Mail\Message */ $oMessage) use ($mAllThreads) { - - $iUid = $oMessage->Uid(); - if (isset($mAllThreads[$iUid]) && \is_array($mAllThreads[$iUid]) && 0 < \count($mAllThreads[$iUid])) - { - $aSubThreads = $mAllThreads[$iUid]; - \array_unshift($aSubThreads, $iUid); - - $oMessage->SetThreads(\array_map('trim', $aSubThreads)); - unset($aSubThreads); - } - }); - } - - return $oMessageCollection; - } - - /** - * @return array|false - */ - public function Quota() - { - return $this->oImapClient->Quota(); - } - - /** - * @param string $sFolderName - * @param string $sMessageId - * - * @return int|null - */ - public function FindMessageUidByMessageId($sFolderName, $sMessageId) - { - if (0 === \strlen($sMessageId)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderExamine($sFolderName); - - $aUids = $this->oImapClient->MessageSimpleSearch( - 'HEADER Message-ID '.$sMessageId, true); - - return \is_array($aUids) && 1 === \count($aUids) && \is_numeric($aUids[0]) ? (int) $aUids[0] : null; - } - - /** - * @param array $aMailFoldersHelper - * @param int $iOptimizationLimit = 0 - * - * @return array - */ - public function folderListOptimization($aMailFoldersHelper, $iOptimizationLimit = 0) - { - // optimization - if (10 < $iOptimizationLimit && \is_array($aMailFoldersHelper) && $iOptimizationLimit < \count($aMailFoldersHelper)) - { - if ($this->oLogger) - { - $this->oLogger->Write('Start optimization (limit:'.$iOptimizationLimit.') for '.\count($aMailFoldersHelper).' folders'); - } - - $iForeachLimit = 1; - - $aFilteredNames = array( - 'inbox', - 'sent', 'outbox', 'sentmail', - 'drafts', - 'junk', 'spam', - 'trash', 'bin', - 'archives', 'archive', 'allmail', 'all', - 'starred', 'flagged', 'important', - 'contacts', 'chats' - ); - - $aNewMailFoldersHelper = array(); - - $iCountLimit = $iForeachLimit; - - foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) - { - // mandatory folders - if ($oFolder && \in_array(\strtolower($oFolder->NameRaw()), $aFilteredNames)) - { - $aNewMailFoldersHelper[] = $oFolder; - $aMailFoldersHelper[$iIndex] = null; - } - } - - foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) - { - // subscribed folders - if ($oFolder && $oFolder->IsSubscribed()) - { - $aNewMailFoldersHelper[] = $oFolder; - - $aMailFoldersHelper[$iIndex] = null; - $iCountLimit--; - } - - if (0 > $iCountLimit) - { - if ($iOptimizationLimit < \count($aNewMailFoldersHelper)) - { - break; - } - else - { - $iCountLimit = $iForeachLimit; - } - } - } - - $iCountLimit = $iForeachLimit; - if ($iOptimizationLimit >= \count($aNewMailFoldersHelper)) - { - // name filter - foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) - { - if ($oFolder && !\preg_match('/[{}\[\]]/', $oFolder->NameRaw())) - { - $aNewMailFoldersHelper[] = $oFolder; - - $aMailFoldersHelper[$iIndex] = null; - $iCountLimit--; - } - - if (0 > $iCountLimit) - { - if ($iOptimizationLimit < \count($aNewMailFoldersHelper)) - { - break; - } - else - { - $iCountLimit = $iForeachLimit; - } - } - } - } - - $iCountLimit = $iForeachLimit; - if ($iOptimizationLimit >= \count($aNewMailFoldersHelper)) - { - // other - foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) - { - if ($oFolder) - { - $aNewMailFoldersHelper[] = $oFolder; - - $aMailFoldersHelper[$iIndex] = null; - $iCountLimit--; - } - - if (0 > $iCountLimit) - { - if ($iOptimizationLimit < \count($aNewMailFoldersHelper)) - { - break; - } - else - { - $iCountLimit = $iForeachLimit; - } - } - } - } - - $aMailFoldersHelper = $aNewMailFoldersHelper; - - if ($this->oLogger) - { - $this->oLogger->Write('Result optimization: '.\count($aMailFoldersHelper).' folders'); - } - } - - return $aMailFoldersHelper; - } - - /** - * @param string $sParent = '' - * @param string $sListPattern = '*' - * @param bool $bUseListSubscribeStatus = false - * @param int $iOptimizationLimit = 0 - * - * @return \MailSo\Mail\FolderCollection|false - */ - public function Folders($sParent = '', $sListPattern = '*', $bUseListSubscribeStatus = true, $iOptimizationLimit = 0) - { - $oFolderCollection = false; - - $aSubscribedFolders = null; - if ($bUseListSubscribeStatus) - { - try - { - $aSubscribedFolders = $this->oImapClient->FolderSubscribeList($sParent, $sListPattern); - } - catch (\Exception $oException) - { - unset($oException); - } - } - - $aImapSubscribedFoldersHelper = null; - if (\is_array($aSubscribedFolders)) - { - $aImapSubscribedFoldersHelper = array(); - foreach ($aSubscribedFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) - { - $aImapSubscribedFoldersHelper[] = $oImapFolder->FullNameRaw(); - } - } - - $aFolders = $this->oImapClient->FolderList($sParent, $sListPattern); - - $bOptimized = false; - $aMailFoldersHelper = null; - - if (\is_array($aFolders)) - { - $aMailFoldersHelper = array(); - - foreach ($aFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) - { - $aMailFoldersHelper[] = Folder::NewInstance($oImapFolder, - (null === $aImapSubscribedFoldersHelper || \in_array($oImapFolder->FullNameRaw(), $aImapSubscribedFoldersHelper)) || - $oImapFolder->IsInbox() - ); - } - - $iCount = \count($aMailFoldersHelper); - $aMailFoldersHelper = $this->folderListOptimization($aMailFoldersHelper, $iOptimizationLimit); - - $bOptimized = $iCount !== \count($aMailFoldersHelper); - } - - if (\is_array($aMailFoldersHelper)) - { - $oFolderCollection = FolderCollection::NewInstance(); - $oFolderCollection->InitByUnsortedMailFolderArray($aMailFoldersHelper); - - $oFolderCollection->Optimized = $bOptimized; - } - - if ($oFolderCollection) - { - $oFolderCollection->SortByCallback(function ($oFolderA, $oFolderB) { - $sA = \strtoupper($oFolderA->FullNameRaw()); - $sB = \strtoupper($oFolderB->FullNameRaw()); - switch (true) - { - case 'INBOX' === $sA: - return -1; - case 'INBOX' === $sB: - return 1; - case '[GMAIL]' === $sA: - return -1; - case '[GMAIL]' === $sB: - return 1; - } - - return \strnatcasecmp($oFolderA->FullName(), $oFolderB->FullName()); - }); - - $oNamespace = $this->oImapClient->GetNamespace(); - if ($oNamespace) - { - $oFolderCollection->SetNamespace($oNamespace->GetPersonalNamespace()); - } - - $oFolderCollection->IsThreadsSupported = $this->IsThreadsSupported(); - } - - return $oFolderCollection; - } - - /** - * @param string $sFolderNameInUtf8 - * @param string $sFolderParentFullNameRaw = '' - * @param bool $bSubscribeOnCreation = true - * @param string $sDelimiter = '' - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function FolderCreate($sFolderNameInUtf8, $sFolderParentFullNameRaw = '', $bSubscribeOnCreation = true, $sDelimiter = '') - { - if (!\MailSo\Base\Validator::NotEmptyString($sFolderNameInUtf8, true) || - !\is_string($sFolderParentFullNameRaw)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $sFolderNameInUtf8 = \trim($sFolderNameInUtf8); - - if (0 === \strlen($sDelimiter) || 0 < \strlen(\trim($sFolderParentFullNameRaw))) - { - $aFolders = $this->oImapClient->FolderList('', 0 === \strlen(\trim($sFolderParentFullNameRaw)) ? 'INBOX' : $sFolderParentFullNameRaw); - if (!\is_array($aFolders) || !isset($aFolders[0])) - { - // TODO - throw new \MailSo\Mail\Exceptions\RuntimeException( - 0 === \strlen(trim($sFolderParentFullNameRaw)) - ? 'Cannot get folder delimiter' - : 'Cannot create folder in non-existen parent folder'); - } - - $sDelimiter = $aFolders[0]->Delimiter(); - if (0 < \strlen($sDelimiter) && 0 < \strlen(\trim($sFolderParentFullNameRaw))) - { - $sFolderParentFullNameRaw .= $sDelimiter; - } - } - - $sFullNameRawToCreate = \MailSo\Base\Utils::ConvertEncoding($sFolderNameInUtf8, - \MailSo\Base\Enumerations\Charset::UTF_8, - \MailSo\Base\Enumerations\Charset::UTF_7_IMAP); - - if (0 < \strlen($sDelimiter) && false !== \strpos($sFullNameRawToCreate, $sDelimiter)) - { - // TODO - throw new \MailSo\Mail\Exceptions\RuntimeException( - 'New folder name contains delimiter'); - } - - $sFullNameRawToCreate = $sFolderParentFullNameRaw.$sFullNameRawToCreate; - - $this->oImapClient->FolderCreate($sFullNameRawToCreate); - - if ($bSubscribeOnCreation) - { - $this->oImapClient->FolderSubscribe($sFullNameRawToCreate); - } - - return $this; - } - - /** - * @param string $sPrevFolderFullNameRaw - * @param string $sNextFolderFullNameInUtf - * @param bool $bSubscribeOnMove = true - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function FolderMove($sPrevFolderFullNameRaw, $sNextFolderFullNameInUtf, $bSubscribeOnMove = true) - { - return $this->folderModify($sPrevFolderFullNameRaw, $sNextFolderFullNameInUtf, false, $bSubscribeOnMove); - } - - /** - * @param string $sPrevFolderFullNameRaw - * @param string $sNewTopFolderNameInUtf - * @param bool $bSubscribeOnRename = true - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function FolderRename($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf, $bSubscribeOnRename = true) - { - return $this->folderModify($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf, true, $bSubscribeOnRename); - } - - /** - * @param string $sPrevFolderFullNameRaw - * @param string $sNextFolderNameInUtf - * @param bool $bRenameOrMove - * @param bool $bSubscribeOnModify - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function folderModify($sPrevFolderFullNameRaw, $sNextFolderNameInUtf, $bRenameOrMove, $bSubscribeOnModify) - { - if (0 === \strlen($sPrevFolderFullNameRaw) || 0 === \strlen($sNextFolderNameInUtf)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $aFolders = $this->oImapClient->FolderList('', $sPrevFolderFullNameRaw); - if (!\is_array($aFolders) || !isset($aFolders[0])) - { - // TODO - throw new \MailSo\Mail\Exceptions\RuntimeException('Cannot rename non-existen folder'); - } - - $sDelimiter = $aFolders[0]->Delimiter(); - $iLast = \strrpos($sPrevFolderFullNameRaw, $sDelimiter); - - $mSubscribeFolders = null; - if ($bSubscribeOnModify) - { - $mSubscribeFolders = $this->oImapClient->FolderSubscribeList($sPrevFolderFullNameRaw, '*'); - if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders)) - { - foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) - { - $this->oImapClient->FolderUnSubscribe($oFolder->FullNameRaw()); - } - } - } - - $sNewFolderFullNameRaw = \MailSo\Base\Utils::ConvertEncoding($sNextFolderNameInUtf, - \MailSo\Base\Enumerations\Charset::UTF_8, - \MailSo\Base\Enumerations\Charset::UTF_7_IMAP); - - if($bRenameOrMove) - { - if (0 < \strlen($sDelimiter) && false !== \strpos($sNewFolderFullNameRaw, $sDelimiter)) - { - // TODO - throw new \MailSo\Mail\Exceptions\RuntimeException('New folder name contains delimiter'); - } - - $sFolderParentFullNameRaw = false === $iLast ? '' : \substr($sPrevFolderFullNameRaw, 0, $iLast + 1); - $sNewFolderFullNameRaw = $sFolderParentFullNameRaw.$sNewFolderFullNameRaw; - } - - $this->oImapClient->FolderRename($sPrevFolderFullNameRaw, $sNewFolderFullNameRaw); - - if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders)) - { - foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) - { - $sFolderFullNameRawForResubscrine = $oFolder->FullNameRaw(); - if (0 === \strpos($sFolderFullNameRawForResubscrine, $sPrevFolderFullNameRaw)) - { - $sNewFolderFullNameRawForResubscrine = $sNewFolderFullNameRaw. - \substr($sFolderFullNameRawForResubscrine, \strlen($sPrevFolderFullNameRaw)); - - $this->oImapClient->FolderSubscribe($sNewFolderFullNameRawForResubscrine); - } - } - } - - return $this; - } - - /** - * @param string $sFolderFullNameRaw - * @param bool $bUnsubscribeOnDeletion = true - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - * @throws \MailSo\Mail\Exceptions\RuntimeException - */ - public function FolderDelete($sFolderFullNameRaw, $bUnsubscribeOnDeletion = true) - { - if (0 === \strlen($sFolderFullNameRaw) || 'INBOX' === $sFolderFullNameRaw) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->FolderExamine($sFolderFullNameRaw); - - $aIndexOrUids = $this->oImapClient->MessageSimpleSearch('ALL'); - if (0 < \count($aIndexOrUids)) - { - throw new \MailSo\Mail\Exceptions\NonEmptyFolder(); - } - - $this->oImapClient->FolderExamine('INBOX'); - - if ($bUnsubscribeOnDeletion) - { - $this->oImapClient->FolderUnSubscribe($sFolderFullNameRaw); - } - - $this->oImapClient->FolderDelete($sFolderFullNameRaw); - - return $this; - } - - /** - * @param string $sFolderFullNameRaw - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function FolderClear($sFolderFullNameRaw) - { - $this->oImapClient->FolderSelect($sFolderFullNameRaw); - - $oFolderInformation = $this->oImapClient->FolderCurrentInformation(); - if ($oFolderInformation && $oFolderInformation->Exists && 0 < $oFolderInformation->Exists) // STATUS? - { - $this->oImapClient->MessageStoreFlag('1:*', false, - array(\MailSo\Imap\Enumerations\MessageFlag::DELETED), - \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT - ); - - $this->oImapClient->MessageExpunge(); - } - - return $this; - } - - /** - * @param string $sFolderFullNameRaw - * @param bool $bSubscribe - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function FolderSubscribe($sFolderFullNameRaw, $bSubscribe) - { - if (0 === \strlen($sFolderFullNameRaw)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oImapClient->{($bSubscribe) ? 'FolderSubscribe' : 'FolderUnSubscribe'}($sFolderFullNameRaw); - - return $this; - } - - /** - * @param \MailSo\Log\Logger $oLogger - * - * @return \MailSo\Mail\MailClient - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public function SetLogger($oLogger) - { - if (!($oLogger instanceof \MailSo\Log\Logger)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $this->oLogger = $oLogger; - $this->oImapClient->SetLogger($this->oLogger); - - return $this; - } -} +oLogger = null; + + $this->oImapClient = \MailSo\Imap\ImapClient::NewInstance(); + $this->oImapClient->SetTimeOuts(10, \MailSo\Config::$ImapTimeout); + } + + /** + * @return \MailSo\Mail\MailClient + */ + public static function NewInstance() + { + return new self(); + } + + /** + * @return \MailSo\Imap\ImapClient + */ + public function ImapClient() + { + return $this->oImapClient; + } + + /** + * @param string $sServerName + * @param int $iPort = 143 + * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT + * @param bool $bVerifySsl = false + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function Connect($sServerName, $iPort = 143, + $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, $bVerifySsl = false) + { + $this->oImapClient->Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl); + return $this; + } + + /** + * @param string $sLogin + * @param string $sPassword + * @param string $sProxyAuthUser = '' + * @param bool $bUseAuthPlainIfSupported = true + * @param bool $bUseAuthCramMd5IfSupported = true + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\LoginException + */ + public function Login($sLogin, $sPassword, $sProxyAuthUser = '', + $bUseAuthPlainIfSupported = true, $bUseAuthCramMd5IfSupported = true) + { + $this->oImapClient->Login($sLogin, $sPassword, $sProxyAuthUser, $bUseAuthPlainIfSupported, $bUseAuthCramMd5IfSupported); + return $this; + } + + /** + * @param string $sXOAuth2Token + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\LoginException + */ + public function LoginWithXOauth2($sXOAuth2Token) + { + $this->oImapClient->LoginWithXOauth2($sXOAuth2Token); + return $this; + } + + /** + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Net\Exceptions\Exception + */ + public function Logout() + { + $this->oImapClient->Logout(); + return $this; + } + + /** + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Net\Exceptions\Exception + */ + public function Disconnect() + { + $this->oImapClient->Disconnect(); + return $this; + } + + /** + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Net\Exceptions\Exception + */ + public function LogoutAndDisconnect() + { + return $this->Logout()->Disconnect(); + } + + /** + * @return bool + */ + public function IsConnected() + { + return $this->oImapClient->IsConnected(); + } + + /** + * @return bool + */ + public function IsLoggined() + { + return $this->oImapClient->IsLoggined(); + } + + /** + * @return string + */ + private function getEnvelopeOrHeadersRequestStringForSimpleList() + { + return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( + \MailSo\Mime\Enumerations\Header::RETURN_PATH, + \MailSo\Mime\Enumerations\Header::RECEIVED, + \MailSo\Mime\Enumerations\Header::MIME_VERSION, + \MailSo\Mime\Enumerations\Header::FROM_, + \MailSo\Mime\Enumerations\Header::TO_, + \MailSo\Mime\Enumerations\Header::CC, + \MailSo\Mime\Enumerations\Header::SENDER, + \MailSo\Mime\Enumerations\Header::REPLY_TO, + \MailSo\Mime\Enumerations\Header::DATE, + \MailSo\Mime\Enumerations\Header::SUBJECT, + \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, + \MailSo\Mime\Enumerations\Header::LIST_UNSUBSCRIBE, + ), true); + } + + /** + * @return string + */ + private function getEnvelopeOrHeadersRequestString() + { + if (\MailSo\Config::$MessageAllHeaders) + { + return \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK; + } + + return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( + \MailSo\Mime\Enumerations\Header::RETURN_PATH, + \MailSo\Mime\Enumerations\Header::RECEIVED, + \MailSo\Mime\Enumerations\Header::MIME_VERSION, + \MailSo\Mime\Enumerations\Header::MESSAGE_ID, + \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, + \MailSo\Mime\Enumerations\Header::FROM_, + \MailSo\Mime\Enumerations\Header::TO_, + \MailSo\Mime\Enumerations\Header::CC, + \MailSo\Mime\Enumerations\Header::BCC, + \MailSo\Mime\Enumerations\Header::SENDER, + \MailSo\Mime\Enumerations\Header::REPLY_TO, + \MailSo\Mime\Enumerations\Header::DELIVERED_TO, + \MailSo\Mime\Enumerations\Header::IN_REPLY_TO, + \MailSo\Mime\Enumerations\Header::REFERENCES, + \MailSo\Mime\Enumerations\Header::DATE, + \MailSo\Mime\Enumerations\Header::SUBJECT, + \MailSo\Mime\Enumerations\Header::SENSITIVITY, + \MailSo\Mime\Enumerations\Header::X_MSMAIL_PRIORITY, + \MailSo\Mime\Enumerations\Header::IMPORTANCE, + \MailSo\Mime\Enumerations\Header::X_PRIORITY, + \MailSo\Mime\Enumerations\Header::X_DRAFT_INFO, + \MailSo\Mime\Enumerations\Header::RETURN_RECEIPT_TO, + \MailSo\Mime\Enumerations\Header::DISPOSITION_NOTIFICATION_TO, + \MailSo\Mime\Enumerations\Header::X_CONFIRM_READING_TO, + \MailSo\Mime\Enumerations\Header::AUTHENTICATION_RESULTS, + \MailSo\Mime\Enumerations\Header::X_DKIM_AUTHENTICATION_RESULTS, + \MailSo\Mime\Enumerations\Header::LIST_UNSUBSCRIBE, + ), true); +// +// return \MailSo\Imap\Enumerations\FetchType::ENVELOPE; + } + + /** + * @param string $sFolderName + * @param string $sMessageFlag + * @param bool $bSetAction = true + * @param bool $sSkipUnsupportedFlag = false + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + * @throws \MailSo\Mail\Exceptions\Exception + */ + public function MessageSetFlagToAll($sFolderName, $sMessageFlag, $bSetAction = true, $sSkipUnsupportedFlag = false) + { + $this->oImapClient->FolderSelect($sFolderName); + + $oFolderInfo = $this->oImapClient->FolderCurrentInformation(); + if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag)) + { + if (!$sSkipUnsupportedFlag) + { + throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag "'.$sMessageFlag.'" is not supported.'); + } + } + + if ($oFolderInfo && 0 < $oFolderInfo->Exists) + { + $sStoreAction = $bSetAction + ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT + : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT + ; + + $this->oImapClient->MessageStoreFlag('1:*', false, array($sMessageFlag), $sStoreAction); + } + } + + /** + * @param string $sFolderName + * @param array $aIndexRange + * @param bool $bIndexIsUid + * @param string $sMessageFlag + * @param bool $bSetAction = true + * @param bool $sSkipUnsupportedFlag = false + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + * @throws \MailSo\Mail\Exceptions\Exception + */ + public function MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, $sMessageFlag, $bSetAction = true, $sSkipUnsupportedFlag = false) + { + $this->oImapClient->FolderSelect($sFolderName); + + $oFolderInfo = $this->oImapClient->FolderCurrentInformation(); + if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag)) + { + if (!$sSkipUnsupportedFlag) + { + throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag "'.$sMessageFlag.'" is not supported.'); + } + } + else + { + $sStoreAction = $bSetAction + ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT + : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT + ; + + $this->oImapClient->MessageStoreFlag(\MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), + $bIndexIsUid, array($sMessageFlag), $sStoreAction); + } + } + + /** + * @param string $sFolderName + * @param array $aIndexRange + * @param bool $bIndexIsUid + * @param bool $bSetAction = true + * @param bool $sSkipUnsupportedFlag = false + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageSetFlagged($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true, $sSkipUnsupportedFlag = false) + { + $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, + \MailSo\Imap\Enumerations\MessageFlag::FLAGGED, $bSetAction, $sSkipUnsupportedFlag); + } + + /** + * @param string $sFolderName + * @param bool $bSetAction = true + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageSetSeenToAll($sFolderName, $bSetAction = true) + { + $this->MessageSetFlagToAll($sFolderName, \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction, true); + } + + /** + * @param string $sFolderName + * @param array $aIndexRange + * @param bool $bIndexIsUid + * @param bool $bSetAction = true + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageSetSeen($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true) + { + $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, + \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction, true); + } + + /** + * @param string $sFolderName + * @param int $iIndex + * @param bool $bIndexIsUid = true + * @param \MailSo\Cache\CacheClient $oCacher = null + * @param int $iBodyTextLimit = null + * + * @return \MailSo\Mail\Message|false + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function Message($sFolderName, $iIndex, $bIndexIsUid = true, $oCacher = null, $iBodyTextLimit = null) + { + if (!\MailSo\Base\Validator::RangeInt($iIndex, 1)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderSelect($sFolderName); + + $oBodyStructure = null; + $oMessage = false; + + $aBodyPeekMimeIndexes = array(); + $aSignatureMimeIndexes = array(); + + $aFetchResponse = $this->oImapClient->Fetch(array(\MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE), $iIndex, $bIndexIsUid); + if (0 < \count($aFetchResponse) && isset($aFetchResponse[0])) + { + $oBodyStructure = $aFetchResponse[0]->GetFetchBodyStructure(); + if ($oBodyStructure) + { + $aTextParts = $oBodyStructure->SearchHtmlOrPlainParts(); + if (is_array($aTextParts) && 0 < \count($aTextParts)) + { + foreach ($aTextParts as $oPart) + { + $aBodyPeekMimeIndexes[] = array($oPart->PartID(), $oPart->Size()); + } + } + + $aSignatureParts = $oBodyStructure->SearchByContentType('application/pgp-signature'); + if (is_array($aSignatureParts) && 0 < \count($aSignatureParts)) + { + foreach ($aSignatureParts as $oPart) + { + $aSignatureMimeIndexes[] = $oPart->PartID(); + } + } + } + } + + $aFetchItems = array( + \MailSo\Imap\Enumerations\FetchType::INDEX, + \MailSo\Imap\Enumerations\FetchType::UID, + \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE, + \MailSo\Imap\Enumerations\FetchType::INTERNALDATE, + \MailSo\Imap\Enumerations\FetchType::FLAGS, + $this->getEnvelopeOrHeadersRequestString() + ); + + if (0 < \count($aBodyPeekMimeIndexes)) + { + foreach ($aBodyPeekMimeIndexes as $aTextMimeData) + { + $sLine = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$aTextMimeData[0].']'; + if (\is_numeric($iBodyTextLimit) && 0 < $iBodyTextLimit && $iBodyTextLimit < $aTextMimeData[1]) + { + $sLine .= '<0.'.((int) $iBodyTextLimit).'>'; + } + + $aFetchItems[] = $sLine; + } + } + + if (0 < \count($aSignatureMimeIndexes)) + { + foreach ($aSignatureMimeIndexes as $sTextMimeIndex) + { + $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sTextMimeIndex.']'; + } + } + + if (!$oBodyStructure) + { + $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE; + } + + $aFetchResponse = $this->oImapClient->Fetch($aFetchItems, $iIndex, $bIndexIsUid); + if (0 < \count($aFetchResponse)) + { + $oMessage = \MailSo\Mail\Message::NewFetchResponseInstance( + $sFolderName, $aFetchResponse[0], $oBodyStructure); + } + + return $oMessage; + } + + /** + * @param mixed $mCallback + * @param string $sFolderName + * @param int $iIndex + * @param bool $bIndexIsUid = true, + * @param string $sMimeIndex = '' + * + * @return bool + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageMimeStream($mCallback, $sFolderName, $iIndex, $bIndexIsUid = true, $sMimeIndex = '') + { + if (!is_callable($mCallback)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderSelect($sFolderName); + + $sFileName = ''; + $sContentType = ''; + $sMailEncodingName = ''; + + $sMimeIndex = trim($sMimeIndex); + $aFetchResponse = $this->oImapClient->Fetch(array( + 0 === \strlen($sMimeIndex) + ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK + : \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.'.MIME]' + ), $iIndex, $bIndexIsUid); + + if (0 < \count($aFetchResponse)) + { + $sMime = $aFetchResponse[0]->GetFetchValue( + 0 === \strlen($sMimeIndex) + ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER + : \MailSo\Imap\Enumerations\FetchType::BODY.'['.$sMimeIndex.'.MIME]' + ); + + if (0 < \strlen($sMime)) + { + $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sMime); + + if (0 < \strlen($sMimeIndex)) + { + $sFileName = $oHeaders->ParameterValue( + \MailSo\Mime\Enumerations\Header::CONTENT_DISPOSITION, + \MailSo\Mime\Enumerations\Parameter::FILENAME); + + if (0 === \strlen($sFileName)) + { + $sFileName = $oHeaders->ParameterValue( + \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, + \MailSo\Mime\Enumerations\Parameter::NAME); + } + + $sMailEncodingName = $oHeaders->ValueByName( + \MailSo\Mime\Enumerations\Header::CONTENT_TRANSFER_ENCODING); + + $sContentType = $oHeaders->ValueByName( + \MailSo\Mime\Enumerations\Header::CONTENT_TYPE); + } + else + { + $sSubject = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT); + + $sFileName = 0 === \strlen($sSubject) ? (string) $iIndex : $sSubject; + $sFileName .= '.eml'; + + $sContentType = 'message/rfc822'; + } + } + } + + $aFetchResponse = $this->oImapClient->Fetch(array( + array(\MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.']', + function ($sParent, $sLiteralAtomUpperCase, $rImapLiteralStream) use ($mCallback, $sMimeIndex, $sMailEncodingName, $sContentType, $sFileName) + { + if (0 < \strlen($sLiteralAtomUpperCase)) + { + if (is_resource($rImapLiteralStream) && 'FETCH' === $sParent) + { + $rMessageMimeIndexStream = (0 === \strlen($sMailEncodingName)) + ? $rImapLiteralStream + : \MailSo\Base\StreamWrappers\Binary::CreateStream($rImapLiteralStream, + \MailSo\Base\StreamWrappers\Binary::GetInlineDecodeOrEncodeFunctionName( + $sMailEncodingName, true)); + + \call_user_func($mCallback, $rMessageMimeIndexStream, $sContentType, $sFileName, $sMimeIndex); + } + } + } + )), $iIndex, $bIndexIsUid); + + return ($aFetchResponse && 1 === \count($aFetchResponse)); + } + + /** + * @param string $sFolder + * @param array $aIndexRange + * @param bool $bIndexIsUid + * @param bool $bUseExpunge = true + * @param bool $bExpungeAll = false + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageDelete($sFolder, $aIndexRange, $bIndexIsUid, $bUseExpunge = true, $bExpungeAll = false) + { + if (0 === \strlen($sFolder) || !\is_array($aIndexRange) || 0 === \count($aIndexRange)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderSelect($sFolder); + + $sIndexRange = \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange); + + $this->oImapClient->MessageStoreFlag($sIndexRange, $bIndexIsUid, + array(\MailSo\Imap\Enumerations\MessageFlag::DELETED), + \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT + ); + + if ($bUseExpunge) + { + $this->oImapClient->MessageExpunge($bIndexIsUid ? $sIndexRange : '', $bIndexIsUid, $bExpungeAll); + } + + return $this; + } + + /** + * @param string $sFromFolder + * @param string $sToFolder + * @param array $aIndexRange + * @param bool $bIndexIsUid + * @param bool $bUseMoveSupported = false + * @param bool $bExpungeAll = false + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageMove($sFromFolder, $sToFolder, $aIndexRange, $bIndexIsUid, $bUseMoveSupported = false, $bExpungeAll = false) + { + if (0 === \strlen($sFromFolder) || 0 === \strlen($sToFolder) || + !\is_array($aIndexRange) || 0 === \count($aIndexRange)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderSelect($sFromFolder); + + if ($bUseMoveSupported && $this->oImapClient->IsSupported('MOVE')) + { + $this->oImapClient->MessageMove($sToFolder, + \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid); + } + else + { + $this->oImapClient->MessageCopy($sToFolder, + \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid); + + $this->MessageDelete($sFromFolder, $aIndexRange, $bIndexIsUid, true, $bExpungeAll); + } + + return $this; + } + + /** + * @param string $sFromFolder + * @param string $sToFolder + * @param array $aIndexRange + * @param bool $bIndexIsUid + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageCopy($sFromFolder, $sToFolder, $aIndexRange, $bIndexIsUid) + { + if (0 === \strlen($sFromFolder) || 0 === \strlen($sToFolder) || + !\is_array($aIndexRange) || 0 === \count($aIndexRange)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderSelect($sFromFolder); + $this->oImapClient->MessageCopy($sToFolder, + \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid); + + return $this; + } + + /** + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderUnSelect() + { + if ($this->oImapClient->IsSelected()) + { + $this->oImapClient->FolderUnSelect(); + } + + return $this; + } + + /** + * @param resource $rMessageStream + * @param int $iMessageStreamSize + * @param string $sFolderToSave + * @param array $aAppendFlags = null + * @param int $iUid = null + * + * @return \MailSo\Mail\MailClient + */ + public function MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags = null, &$iUid = null) + { + if (!\is_resource($rMessageStream) || 0 === \strlen($sFolderToSave)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->MessageAppendStream( + $sFolderToSave, $rMessageStream, $iMessageStreamSize, $aAppendFlags, $iUid); + + return $this; + } + + /** + * @param string $sMessageFileName + * @param string $sFolderToSave + * @param array $aAppendFlags = null + * @param int &$iUid = null + * + * @return \MailSo\Mail\MailClient + */ + public function MessageAppendFile($sMessageFileName, $sFolderToSave, $aAppendFlags = null, &$iUid = null) + { + if (!@\is_file($sMessageFileName) || !@\is_readable($sMessageFileName)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $iMessageStreamSize = \filesize($sMessageFileName); + $rMessageStream = \fopen($sMessageFileName, 'rb'); + + $this->MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags, $iUid); + + if (\is_resource($rMessageStream)) + { + @fclose($rMessageStream); + } + + return $this; + } + + /** + * @param string $sFolderName + * @param int $iCount + * @param int $iUnseenCount + * @param string $sUidNext + * @param string $sHighestModSeq + * + * @return void + */ + protected function initFolderValues($sFolderName, &$iCount, &$iUnseenCount, + &$sUidNext, &$sHighestModSeq = '') + { + $aTypes = array( + \MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES, + \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN, + \MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT + ); + + if ($this->oImapClient->IsSupported('CONDSTORE')) + { + $aTypes[] = \MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ; + } + + $aFolderStatus = $this->oImapClient->FolderStatus($sFolderName, $aTypes); + + $iCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES]) + ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES] : 0; + + $iUnseenCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN]) + ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0; + + $sUidNext = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT]) + ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT] : '0'; + + $sHighestModSeq = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ]) + ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ] : ''; + + if ($this->IsGmail() && + ('INBOX' === $sFolderName || '[gmail]' === \strtolower(\substr($sFolderName, 0, 7)))) + { + $oFolder = $this->oImapClient->FolderCurrentInformation(); + if ($oFolder && null !== $oFolder->Exists && $oFolder->FolderName === $sFolderName) + { + $iSubCount = (int) $oFolder->Exists; + if (0 < $iSubCount && $iSubCount < $iCount) + { + $iCount = $iSubCount; + } + } + } + } + + /** + * @return string + */ + public function GenerateImapClientHash() + { + return \md5('ImapClientHash/'. + $this->oImapClient->GetLogginedUser().'@'. + $this->oImapClient->GetConnectedHost().':'. + $this->oImapClient->GetConnectedPort() + ); + } + + /** + * @param string $sFolder + * @param int $iCount + * @param int $iUnseenCount + * @param string $sUidNext + * @param string $sHighestModSeq = '' + * + * @return string + */ + public function GenerateFolderHash($sFolder, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq = '') + { + $iUnseenCount = 0; // unneccessery + return \md5('FolderHash/'.$sFolder.'-'.$iCount.'-'.$iUnseenCount.'-'.$sUidNext.'-'. + $sHighestModSeq.'-'.$this->GenerateImapClientHash().'-'. + \MailSo\Config::$MessageListPermanentFilter + ); + } + + /** + * @param string $sFolderName + * @param string $sPrevUidNext + * @param string $sCurrentUidNext + * + * @return array + */ + private function getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sCurrentUidNext) + { + $aNewMessages = array(); + + if (0 < \strlen($sPrevUidNext) && (string) $sPrevUidNext !== (string) $sCurrentUidNext) + { + $this->oImapClient->FolderSelect($sFolderName); + + $aFetchResponse = $this->oImapClient->Fetch(array( + \MailSo\Imap\Enumerations\FetchType::INDEX, + \MailSo\Imap\Enumerations\FetchType::UID, + \MailSo\Imap\Enumerations\FetchType::FLAGS, + \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( + \MailSo\Mime\Enumerations\Header::FROM_, + \MailSo\Mime\Enumerations\Header::SUBJECT, + \MailSo\Mime\Enumerations\Header::CONTENT_TYPE + )) + ), $sPrevUidNext.':*', true); + + if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse)) + { + foreach ($aFetchResponse as /* @var $oFetchResponse \MailSo\Imap\FetchResponse */ $oFetchResponse) + { + $aFlags = \array_map('strtolower', $oFetchResponse->GetFetchValue( + \MailSo\Imap\Enumerations\FetchType::FLAGS)); + + if (!\in_array(\strtolower(\MailSo\Imap\Enumerations\MessageFlag::SEEN), $aFlags)) + { + $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID); + $sHeaders = $oFetchResponse->GetHeaderFieldsValue(); + + $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sHeaders); + + $sContentTypeCharset = $oHeaders->ParameterValue( + \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, + \MailSo\Mime\Enumerations\Parameter::CHARSET + ); + + $sCharset = ''; + if (0 < \strlen($sContentTypeCharset)) + { + $sCharset = $sContentTypeCharset; + } + + if (0 < \strlen($sCharset)) + { + $oHeaders->SetParentCharset($sCharset); + } + + $aNewMessages[] = array( + 'Folder' => $sFolderName, + 'Uid' => $sUid, + 'Subject' => $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT, 0 === \strlen($sCharset)), + 'From' => $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::FROM_, 0 === \strlen($sCharset)) + ); + } + } + } + } + + return $aNewMessages; + } + + /** + * @param string $sFolderName + * @param string $sPrevUidNext = '' + * @param array $aUids = '' + * + * @return string + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderInformation($sFolderName, $sPrevUidNext = '', $aUids = array()) + { + $aFlags = array(); + + $bSelect = false; + if ($this->IsGmail() && + ('INBOX' === $sFolderName || '[gmail]' === \strtolower(\substr($sFolderName, 0, 7)))) + { + $this->oImapClient->FolderSelect($sFolderName); + $bSelect = true; + } + + if (\is_array($aUids) && 0 < \count($aUids)) + { + if (!$bSelect) + { + $this->oImapClient->FolderSelect($sFolderName); + } + + $aFetchResponse = $this->oImapClient->Fetch(array( + \MailSo\Imap\Enumerations\FetchType::INDEX, + \MailSo\Imap\Enumerations\FetchType::UID, + \MailSo\Imap\Enumerations\FetchType::FLAGS + ), \MailSo\Base\Utils::PrepearFetchSequence($aUids), true); + + if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse)) + { + foreach ($aFetchResponse as $oFetchResponse) + { + $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID); + $aFlags[(\is_numeric($sUid) ? (int) $sUid : 0)] = + $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::FLAGS); + } + } + } + + $iCount = 0; + $iUnseenCount = 0; + $sUidNext = '0'; + $sHighestModSeq = ''; + + $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq); + + $aResult = array( + 'Folder' => $sFolderName, + 'Hash' => $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq), + 'MessageCount' => $iCount, + 'MessageUnseenCount' => $iUnseenCount, + 'UidNext' => $sUidNext, + 'Flags' => $aFlags, + 'HighestModSeq' => $sHighestModSeq, + 'NewMessages' => 'INBOX' === $sFolderName ? + $this->getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sUidNext) : array() + ); + + return $aResult; + } + + /** + * @param string $sFolderName + * + * @return string + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function FolderHash($sFolderName) + { + $iCount = 0; + $iUnseenCount = 0; + $sUidNext = '0'; + $sHighestModSeq = ''; + + $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq); + + return $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq); + } + + /** + * @return int + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function InboxUnreadCount() + { + $aFolderStatus = $this->oImapClient->FolderStatus('INBOX', array( + \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN + )); + + $iResult = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN]) ? + (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0; + + return 0 < $iResult ? $iResult : 0; + } + + /** + * @return bool + */ + public function IsGmail() + { + return 'ssl://imap.gmail.com' === \strtolower($this->oImapClient->GetConnectedHost()); + } + + /** + * @param string $sSearch + * @param bool $bDetectGmail = true + * + * @return string + */ + private function escapeSearchString($sSearch, $bDetectGmail = true) + { + return !\MailSo\Base\Utils::IsAscii($sSearch) + ? '{'.\strlen($sSearch).'}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch); +// return ($bDetectGmail && !\MailSo\Base\Utils::IsAscii($sSearch) && $this->IsGmail()) +// ? '{'.\strlen($sSearch).'+}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch); + } + + /** + * @param string $sDate + * @param int $iTimeZoneOffset + * + * @return int + */ + private function parseSearchDate($sDate, $iTimeZoneOffset) + { + $iResult = 0; + if (0 < \strlen($sDate)) + { + $oDateTime = \DateTime::createFromFormat('Y.m.d', $sDate, \MailSo\Base\DateTimeHelper::GetUtcTimeZoneObject()); + return $oDateTime ? $oDateTime->getTimestamp() - $iTimeZoneOffset : 0; + } + + return $iResult; + } + + /** + * @param string $sSize + * + * @return int + */ + private function parseFriendlySize($sSize) + { + $sSize = preg_replace('/[^0-9bBkKmM]/', '', $sSize); + + $iResult = 0; + $aMatch = array(); + + if (\preg_match('/([\d]+)(B|KB|M|MB|G|GB)$/i', $sSize, $aMatch) && isset($aMatch[1], $aMatch[2])) + { + $iResult = (int) $aMatch[1]; + switch (\strtoupper($aMatch[2])) + { + case 'K': + case 'KB': + $iResult *= 1024; + case 'M': + case 'MB': + $iResult *= 1024; + case 'G': + case 'GB': + $iResult *= 1024; + } + } + else + { + $iResult = (int) $sSize; + } + + return $iResult; + } + + /** + * @param string $sSearch + * + * @return array + */ + private function parseSearchString($sSearch) + { + $aResult = array( + 'OTHER' => '' + ); + + $aCache = array(); + + $sReg = 'e?mail|from|to|subject|has|is|date|text|body|size|larger|bigger|smaller|maxsize|minsize'; + + $sSearch = \MailSo\Base\Utils::StripSpaces($sSearch); + $sSearch = \trim(\preg_replace('/('.$sReg.'): /i', '\\1:', $sSearch)); + + $mMatch = array(); + \preg_match_all('/".*?(? $sName) + { + if (isset($mMatch[2][$iIndex]) && 0 < \strlen($mMatch[2][$iIndex])) + { + $sName = \strtoupper($sName); + $sValue = $mMatch[2][$iIndex]; + switch ($sName) + { + case 'TEXT': + case 'BODY': + case 'EMAIL': + case 'MAIL': + case 'FROM': + case 'TO': + case 'SUBJECT': + case 'IS': + case 'HAS': + case 'SIZE': + case 'SMALLER': + case 'LARGER': + case 'BIGGER': + case 'MAXSIZE': + case 'MINSIZE': + case 'DATE': + if ('MAIL' === $sName) + { + $sName = 'EMAIL'; + } + if ('BODY' === $sName) + { + $sName = 'TEXT'; + } + if ('SIZE' === $sName || 'BIGGER' === $sName || 'MINSIZE' === $sName) + { + $sName = 'LARGER'; + } + if ('MAXSIZE' === $sName) + { + $sName = 'SMALLER'; + } + $aResult[$sName] = $sValue; + break; + } + } + } + } + + $aResult['OTHER'] = $sSearch; + foreach ($aResult as $sName => $sValue) + { + if (isset($aCache[$sValue])) + { + $aResult[$sName] = \trim($aCache[$sValue], '"\' '); + } + } + + return $aResult; + } + + /** + * @param string $sSearch + * @param string $sFilter + * @param int $iTimeZoneOffset = 0 + * @param bool $bUseCache = true + * + * @return string + */ + private function getImapSearchCriterias($sSearch, $sFilter, $iTimeZoneOffset = 0, &$bUseCache = true) + { + $bUseCache = true; + $iTimeFilter = 0; + $aCriteriasResult = array(); + + if (0 < \MailSo\Config::$MessageListDateFilter) + { + $iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter; + $iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD)); + } + + if (0 < \strlen(\trim($sSearch))) + { + $sGmailRawSearch = ''; + $sResultBodyTextSearch = ''; + + $aLines = $this->parseSearchString($sSearch); + $bIsGmail = $this->oImapClient->IsSupported('X-GM-EXT-1'); + + if (1 === \count($aLines) && isset($aLines['OTHER'])) + { + $sValue = $this->escapeSearchString($aLines['OTHER']); + + if (\MailSo\Config::$MessageListFastSimpleSearch) + { + $aCriteriasResult[] = 'OR OR OR'; + $aCriteriasResult[] = 'FROM'; + $aCriteriasResult[] = $sValue; + $aCriteriasResult[] = 'TO'; + $aCriteriasResult[] = $sValue; + $aCriteriasResult[] = 'CC'; + $aCriteriasResult[] = $sValue; + $aCriteriasResult[] = 'SUBJECT'; + $aCriteriasResult[] = $sValue; + } + else + { + $aCriteriasResult[] = 'TEXT'; + $aCriteriasResult[] = $sValue; + } + } + else + { + if (isset($aLines['EMAIL'])) + { + $sValue = $this->escapeSearchString($aLines['EMAIL']); + + $aCriteriasResult[] = 'OR OR'; + $aCriteriasResult[] = 'FROM'; + $aCriteriasResult[] = $sValue; + $aCriteriasResult[] = 'TO'; + $aCriteriasResult[] = $sValue; + $aCriteriasResult[] = 'CC'; + $aCriteriasResult[] = $sValue; + + unset($aLines['EMAIL']); + } + + if (isset($aLines['TO'])) + { + $sValue = $this->escapeSearchString($aLines['TO']); + + $aCriteriasResult[] = 'OR'; + $aCriteriasResult[] = 'TO'; + $aCriteriasResult[] = $sValue; + $aCriteriasResult[] = 'CC'; + $aCriteriasResult[] = $sValue; + + unset($aLines['TO']); + } + + $sMainText = ''; + foreach ($aLines as $sName => $sRawValue) + { + if ('' === \trim($sRawValue)) + { + continue; + } + + $sValue = $this->escapeSearchString($sRawValue); + switch ($sName) + { + case 'FROM': + $aCriteriasResult[] = 'FROM'; + $aCriteriasResult[] = $sValue; + break; + case 'SUBJECT': + $aCriteriasResult[] = 'SUBJECT'; + $aCriteriasResult[] = $sValue; + break; + case 'OTHER': + case 'TEXT': + $sMainText .= ' '.$sRawValue; + break; + case 'HAS': + $aValue = \explode(',', \strtolower($sRawValue)); + $aValue = \array_map('trim', $aValue); + + $aCompareArray = array('file', 'files', 'attach', 'attachs', 'attachment', 'attachments'); + if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue))) + { + if ($bIsGmail) + { + $sGmailRawSearch .= ' has:attachment'; + } + else + { + // Simple, is not detailed search (Sometimes doesn't work) + $aCriteriasResult[] = 'OR OR OR'; + $aCriteriasResult[] = 'HEADER Content-Type application/'; + $aCriteriasResult[] = 'HEADER Content-Type multipart/m'; + $aCriteriasResult[] = 'HEADER Content-Type multipart/signed'; + $aCriteriasResult[] = 'HEADER Content-Type multipart/report'; + } + } + + case 'IS': + $aValue = \explode(',', \strtolower($sRawValue)); + $aValue = \array_map('trim', $aValue); + + $aCompareArray = array('flag', 'flagged', 'star', 'starred', 'pinned'); + $aCompareArray2 = array('unflag', 'unflagged', 'unstar', 'unstarred', 'unpinned'); + if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue))) + { + $aCriteriasResult[] = 'FLAGGED'; + $bUseCache = false; + } + else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue))) + { + $aCriteriasResult[] = 'UNFLAGGED'; + $bUseCache = false; + } + + $aCompareArray = array('unread', 'unseen'); + $aCompareArray2 = array('read', 'seen'); + if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue))) + { + $aCriteriasResult[] = 'UNSEEN'; + $bUseCache = false; + } + else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue))) + { + $aCriteriasResult[] = 'SEEN'; + $bUseCache = false; + } + break; + + case 'LARGER': + $aCriteriasResult[] = 'LARGER'; + $aCriteriasResult[] = $this->parseFriendlySize($sRawValue); + break; + case 'SMALLER': + $aCriteriasResult[] = 'SMALLER'; + $aCriteriasResult[] = $this->parseFriendlySize($sRawValue); + break; + case 'DATE': + $iDateStampFrom = $iDateStampTo = 0; + + $sDate = $sRawValue; + $aDate = \explode('/', $sDate); + + if (\is_array($aDate) && 2 === \count($aDate)) + { + if (0 < \strlen($aDate[0])) + { + $iDateStampFrom = $this->parseSearchDate($aDate[0], $iTimeZoneOffset); + } + + if (0 < \strlen($aDate[1])) + { + $iDateStampTo = $this->parseSearchDate($aDate[1], $iTimeZoneOffset); + $iDateStampTo += 60 * 60 * 24; + } + } + else + { + if (0 < \strlen($sDate)) + { + $iDateStampFrom = $this->parseSearchDate($sDate, $iTimeZoneOffset); + $iDateStampTo = $iDateStampFrom + 60 * 60 * 24; + } + } + + if (0 < $iDateStampFrom) + { + $aCriteriasResult[] = 'SINCE'; + $aCriteriasResult[] = \gmdate('j-M-Y', $iTimeFilter > $iDateStampFrom ? + $iTimeFilter : $iDateStampFrom); + + $iTimeFilter = 0; + } + + if (0 < $iDateStampTo) + { + $aCriteriasResult[] = 'BEFORE'; + $aCriteriasResult[] = \gmdate('j-M-Y', $iDateStampTo); + } + break; + } + } + + if ('' !== \trim($sMainText)) + { + $sMainText = \trim(\MailSo\Base\Utils::StripSpaces($sMainText), '"'); + if ($bIsGmail) + { + $sGmailRawSearch .= ' '.$sMainText; + } + else + { + $sResultBodyTextSearch .= ' '.$sMainText; + } + } + } + + $sGmailRawSearch = \trim($sGmailRawSearch); + if ($bIsGmail && 0 < \strlen($sGmailRawSearch)) + { + $aCriteriasResult[] = 'X-GM-RAW'; + $aCriteriasResult[] = $this->escapeSearchString($sGmailRawSearch, false); + } + + $sResultBodyTextSearch = \trim($sResultBodyTextSearch); + if (0 < \strlen($sResultBodyTextSearch)) + { + $aCriteriasResult[] = 'BODY'; + $aCriteriasResult[] = $this->escapeSearchString($sResultBodyTextSearch); + } + } + + $sCriteriasResult = \trim(\implode(' ', $aCriteriasResult)); + + if (0 < $iTimeFilter) + { + $sCriteriasResult .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter); + } + + $sCriteriasResult = \trim($sCriteriasResult); + if (\MailSo\Config::$MessageListUndeletedOnly) + { + $sCriteriasResult = \trim($sCriteriasResult.' UNDELETED'); + } + + $sFilter = \trim($sFilter); + if ('' !== $sFilter) + { + $sCriteriasResult .= ' '.$sFilter; + } + + $sCriteriasResult = \trim($sCriteriasResult); + if ('' !== \MailSo\Config::$MessageListPermanentFilter) + { + $sCriteriasResult = \trim($sCriteriasResult.' '.\MailSo\Config::$MessageListPermanentFilter); + } + + $sCriteriasResult = \trim($sCriteriasResult); + if ('' === $sCriteriasResult) + { + $sCriteriasResult = 'ALL'; + } + + return $sCriteriasResult; + } + + /** + * @param array $aThreads + * @return array + */ + private function threadArrayMap($aThreads) + { + $aNew = array(); + foreach ($aThreads as $mItem) + { + if (!\is_array($mItem)) + { + $aNew[] = $mItem; + } + else + { + $mMap = $this->threadArrayMap($mItem); + if (\is_array($mMap) && 0 < \count($mMap)) + { + $aNew = \array_merge($aNew, $mMap); + } + } + } + + return $aNew; + } + + /** + * @param array $aThreads + * + * @return array + */ + private function compileThreadArray($aThreads) + { + $aResult = array(); + foreach ($aThreads as $mItem) + { + if (\is_array($mItem)) + { + $aMap = $this->threadArrayMap($mItem); + if (\is_array($aMap)) + { + if (1 < \count($aMap)) + { + $aResult[] = $aMap; + } + else if (0 < \count($aMap)) + { + $aResult[] = $aMap[0]; + } + } + } + else + { + $aResult[] = $mItem; + } + } + + return $aResult; + } + + /** + * @param string $sFolderName + * @param string $sFolderHash + * @param array $aIndexOrUids + * @param \MailSo\Cache\CacheClient $oCacher + * @param bool $bCacheOnly = false + * + * @return array + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageListThreadsMap($sFolderName, $sFolderHash, $aIndexOrUids, $oCacher, $bCacheOnly = false) + { + $iThreadLimit = \MailSo\Config::$LargeThreadLimit; + + $sSearchHash = ''; + if (0 < \MailSo\Config::$MessageListDateFilter) + { + $iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter; + $iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD)); + + $sSearchHash .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter); + } + + if ('' === \trim($sSearchHash)) + { + $sSearchHash = 'ALL'; + } + + if ($oCacher && $oCacher->IsInited()) + { + $sSerializedHashKey = + 'ThreadsMapSorted/'.$sSearchHash.'/'. + 'Limit='.$iThreadLimit.'/'.$sFolderName.'/'.$sFolderHash; + + if ($this->oLogger) + { + $this->oLogger->Write($sSerializedHashKey); + } + + $sSerializedUids = $oCacher->Get($sSerializedHashKey); + if (!empty($sSerializedUids)) + { + $aSerializedUids = @\json_decode($sSerializedUids, true); + if (isset($aSerializedUids['ThreadsUids']) && \is_array($aSerializedUids['ThreadsUids'])) + { + if ($this->oLogger) + { + $this->oLogger->Write('Get Serialized Thread UIDS from cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aSerializedUids['ThreadsUids']).']'); + } + + return $aSerializedUids['ThreadsUids']; + } + } + } + + if ($bCacheOnly) + { + return null; + } + + $this->oImapClient->FolderExamine($sFolderName); + + $aThreadUids = array(); + try + { + $aThreadUids = $this->oImapClient->MessageSimpleThread($sSearchHash); + } + catch (\MailSo\Imap\Exceptions\RuntimeException $oException) + { + unset($oException); + $aThreadUids = array(); + } + + $aResult = array(); + $aCompiledThreads = $this->compileThreadArray($aThreadUids); + + foreach ($aCompiledThreads as $mData) + { + if (\is_array($mData)) + { + foreach ($mData as $mSubData) + { + $aResult[(int) $mSubData] = + \array_diff($mData, array((int) $mSubData)); + } + } + else if (\is_int($mData) || \is_string($mData)) + { + $aResult[(int) $mData] = (int) $mData; + } + } + + $aParentsMap = array(); + foreach ($aIndexOrUids as $iUid) + { + if (isset($aResult[$iUid]) && \is_array($aResult[$iUid])) + { + foreach ($aResult[$iUid] as $iTempUid) + { + $aParentsMap[$iTempUid] = $iUid; + if (isset($aResult[$iTempUid])) + { + unset($aResult[$iTempUid]); + } + } + } + } + + $aSortedThreads = array(); + foreach ($aIndexOrUids as $iUid) + { + if (isset($aResult[$iUid])) + { + $aSortedThreads[$iUid] = $iUid; + } + } + + foreach ($aIndexOrUids as $iUid) + { + if (!isset($aSortedThreads[$iUid]) && + isset($aParentsMap[$iUid]) && + isset($aSortedThreads[$aParentsMap[$iUid]])) + { + if (!\is_array($aSortedThreads[$aParentsMap[$iUid]])) + { + $aSortedThreads[$aParentsMap[$iUid]] = array(); + } + + $aSortedThreads[$aParentsMap[$iUid]][] = $iUid; + } + } + + $aResult = $aSortedThreads; + unset($aParentsMap, $aSortedThreads); + + $aTemp = array(); + foreach ($aResult as $iUid => $mValue) + { + if (0 < $iThreadLimit && \is_array($mValue) && $iThreadLimit < \count($mValue)) + { + $aParts = \array_chunk($mValue, $iThreadLimit); + if (0 < count($aParts)) + { + foreach ($aParts as $iIndex => $aItem) + { + if (0 === $iIndex) + { + $aResult[$iUid] = $aItem; + } + else if (0 < $iIndex && \is_array($aItem)) + { + $mFirst = \array_shift($aItem); + if (!empty($mFirst)) + { + $aTemp[$mFirst] = 0 < \count($aItem) ? $aItem : $mFirst; + } + } + } + } + } + } + + foreach ($aTemp as $iUid => $mValue) + { + $aResult[$iUid] = $mValue; + } + + unset($aTemp); + + $aLastResult = array(); + foreach ($aIndexOrUids as $iUid) + { + if (isset($aResult[$iUid])) + { + $aLastResult[$iUid] = $aResult[$iUid]; + } + } + + $aResult = $aLastResult; + unset($aLastResult); + + if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHashKey)) + { + $oCacher->Set($sSerializedHashKey, @\json_encode(array( + 'ThreadsUids' => $aResult + ))); + + if ($this->oLogger) + { + $this->oLogger->Write('Save Serialized Thread UIDS to cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aResult).']'); + } + } + + return $aResult; + } + + /** + * @param \MailSo\Mail\MessageCollection &$oMessageCollection + * @param array $aRequestIndexOrUids + * @param bool $bIndexAsUid + * @param bool $bSimple = false + * + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageListByRequestIndexOrUids(&$oMessageCollection, $aRequestIndexOrUids, $bIndexAsUid, $bSimple = false) + { + if (\is_array($aRequestIndexOrUids) && 0 < \count($aRequestIndexOrUids)) + { + $aFetchResponse = $this->oImapClient->Fetch(array( + \MailSo\Imap\Enumerations\FetchType::INDEX, + \MailSo\Imap\Enumerations\FetchType::UID, + \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE, + \MailSo\Imap\Enumerations\FetchType::INTERNALDATE, + \MailSo\Imap\Enumerations\FetchType::FLAGS, + \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE, + $bSimple ? + $this->getEnvelopeOrHeadersRequestStringForSimpleList() : + $this->getEnvelopeOrHeadersRequestString() + ), \MailSo\Base\Utils::PrepearFetchSequence($aRequestIndexOrUids), $bIndexAsUid); + + if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse)) + { + $aFetchIndexArray = array(); + $oFetchResponseItem = null; + foreach ($aFetchResponse as /* @var $oFetchResponseItem \MailSo\Imap\FetchResponse */ &$oFetchResponseItem) + { + $aFetchIndexArray[($bIndexAsUid) + ? $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID) + : $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::INDEX)] =& $oFetchResponseItem; + + unset($oFetchResponseItem); + } + + foreach ($aRequestIndexOrUids as $iFUid) + { + if (isset($aFetchIndexArray[$iFUid])) + { + $oMessageCollection->Add( + Message::NewFetchResponseInstance( + $oMessageCollection->FolderName, $aFetchIndexArray[$iFUid])); + } + } + } + } + } + + /** + * @return bool + * + * @throws \MailSo\Net\Exceptions\Exception + */ + public function IsThreadsSupported() + { + return $this->oImapClient->IsSupported('THREAD=REFS') || + $this->oImapClient->IsSupported('THREAD=REFERENCES') || + $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT'); + } + + /** + * @param string $sFolderName + * @param array $aUids + * + * @return \MailSo\Mail\MessageCollection + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageListSimple($sFolderName, $aUids) + { + if (0 === \strlen($sFolderName) || !\MailSo\Base\Validator::NotEmptyArray($aUids)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderExamine($sFolderName); + + $oMessageCollection = \MailSo\Mail\MessageCollection::NewInstance(); + $oMessageCollection->FolderName = $sFolderName; + + $this->MessageListByRequestIndexOrUids($oMessageCollection, $aUids, true, true); + + return $oMessageCollection->GetAsArray(); + } + + /** + * @param \MailSo\Cache\CacheClient|null $oCacher + * @param string $sSearch + * @param string $sFilter + * @param string $sFolderName + * @param string $sFolderHash + * @param bool $bUseSortIfSupported = false + * + * @return array + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function GetUids($oCacher, $sSearch, $sFilter, $sFolderName, $sFolderHash, $bUseSortIfSupported = false) + { + $aResultUids = false; + $bUidsFromCacher = false; + $bUseCacheAfterSearch = true; + + $sSerializedHash = ''; + $sSerializedLog = ''; + + $bUseSortIfSupported = $bUseSortIfSupported ? !!$this->oImapClient->IsSupported('SORT') : false; + + if (0 < \strlen($sSearch)) + { + $bUseSortIfSupported = false; + } + + $sSearchCriterias = $this->getImapSearchCriterias($sSearch, $sFilter, 0, $bUseCacheAfterSearch); + if ($bUseCacheAfterSearch && $oCacher && $oCacher->IsInited()) + { + $sSerializedHash = 'GetUids/'. + ($bUseSortIfSupported ? 'S': 'N').'/'. + $this->GenerateImapClientHash().'/'. + $sFolderName.'/'.$sSearchCriterias; + + $sSerializedLog = '"'.$sFolderName.'" / '.$sSearchCriterias.''; + + $sSerialized = $oCacher->Get($sSerializedHash); + if (!empty($sSerialized)) + { + $aSerialized = @\json_decode($sSerialized, true); + if (\is_array($aSerialized) && isset($aSerialized['FolderHash'], $aSerialized['Uids']) && + $sFolderHash === $aSerialized['FolderHash'] && + \is_array($aSerialized['Uids']) + ) + { + if ($this->oLogger) + { + $this->oLogger->Write('Get Serialized UIDS from cache ('.$sSerializedLog.') [count:'.\count($aSerialized['Uids']).']'); + } + + $aResultUids = $aSerialized['Uids']; + $bUidsFromCacher = true; + } + } + } + + if (!\is_array($aResultUids)) + { + $aResultUids = $bUseSortIfSupported ? + $this->oImapClient->MessageSimpleSort(array('REVERSE ARRIVAL'), $sSearchCriterias, true) : + $this->oImapClient->MessageSimpleSearch($sSearchCriterias, true, \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? '' : 'UTF-8') + ; + + if (!$bUidsFromCacher && $bUseCacheAfterSearch && \is_array($aResultUids) && $oCacher && $oCacher->IsInited() && 0 < \strlen($sSerializedHash)) + { + $oCacher->Set($sSerializedHash, @\json_encode(array( + 'FolderHash' => $sFolderHash, + 'Uids' => $aResultUids + ))); + + if ($this->oLogger) + { + $this->oLogger->Write('Save Serialized UIDS to cache ('.$sSerializedLog.') [count:'.\count($aResultUids).']'); + } + } + } + + return \is_array($aResultUids) ? $aResultUids : array(); + } + + /** + * @param string $sFolderName + * @param int $iOffset = 0 + * @param int $iLimit = 10 + * @param string $sSearch = '' + * @param string $sPrevUidNext = '' + * @param \MailSo\Cache\CacheClient|null $oCacher = null + * @param bool $bUseSortIfSupported = false + * @param bool $bUseThreadSortIfSupported = false + * @param bool $bUseESearchOrESortRequest = false + * @param string $sThreadUid = '' + * @param string $sFilter = '' + * + * @return \MailSo\Mail\MessageCollection + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Net\Exceptions\Exception + * @throws \MailSo\Imap\Exceptions\Exception + */ + public function MessageList($sFolderName, $iOffset = 0, $iLimit = 10, $sSearch = '', $sPrevUidNext = '', $oCacher = null, + $bUseSortIfSupported = false, $bUseThreadSortIfSupported = false, $sThreadUid = '', $sFilter = '') + { + $sFilter = \trim($sFilter); + $sSearch = \trim($sSearch); + if (!\MailSo\Base\Validator::RangeInt($iOffset, 0) || + !\MailSo\Base\Validator::RangeInt($iLimit, 0, 999)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $bUseFilter = '' !== $sFilter; + + $this->oImapClient->FolderSelect($sFolderName); + + $oMessageCollection = MessageCollection::NewInstance(); + $oMessageCollection->FolderName = $sFolderName; + $oMessageCollection->Offset = $iOffset; + $oMessageCollection->Limit = $iLimit; + $oMessageCollection->Search = $sSearch; + $oMessageCollection->ThreadUid = $sThreadUid; + $oMessageCollection->Filtered = '' !== \MailSo\Config::$MessageListPermanentFilter; + + $aUids = array(); + $mAllSortedUids = null; + $mAllThreads = null; + + $iThreadUid = empty($sThreadUid) ? 0 : (int) $sThreadUid; + + $iMessageRealCount = 0; + $iMessageUnseenCount = 0; + $sUidNext = '0'; + $sHighestModSeq = ''; + + $bUseSortIfSupported = $bUseSortIfSupported ? $this->oImapClient->IsSupported('SORT') : false; + + $bUseThreadSortIfSupported = $bUseThreadSortIfSupported ? + ($this->oImapClient->IsSupported('THREAD=REFS') || $this->oImapClient->IsSupported('THREAD=REFERENCES') || $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT')) : false; + + if (!empty($sThreadUid) && !$bUseThreadSortIfSupported) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + if (!$oCacher || !($oCacher instanceof \MailSo\Cache\CacheClient)) + { + $oCacher = null; + } + + $this->initFolderValues($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext, $sHighestModSeq); + + if ($bUseFilter) + { + $iMessageUnseenCount = 0; + } + + $oMessageCollection->FolderHash = $this->GenerateFolderHash( + $sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext, $sHighestModSeq); + + $oMessageCollection->UidNext = $sUidNext; + + if (empty($sThreadUid) && 0 < \strlen($sPrevUidNext) && 'INBOX' === $sFolderName) + { + $oMessageCollection->NewMessages = $this->getFolderNextMessageInformation( + $sFolderName, $sPrevUidNext, $sUidNext); + } + + $bSearch = false; + $bMessageListOptimization = 0 < \MailSo\Config::$MessageListCountLimitTrigger && + \MailSo\Config::$MessageListCountLimitTrigger < $iMessageRealCount; + + if ($bMessageListOptimization) + { + $bUseSortIfSupported = false; + $bUseThreadSortIfSupported = false; + } + + if (0 < $iMessageRealCount && !$bMessageListOptimization) + { + $mAllSortedUids = $this->GetUids($oCacher, '', $sFilter, + $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $bUseSortIfSupported); + + $mAllThreads = $bUseThreadSortIfSupported ? $this->MessageListThreadsMap( + $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $mAllSortedUids, $oCacher) : null; + + if ($bUseThreadSortIfSupported && 0 < $iThreadUid && \is_array($mAllThreads)) + { + $aUids = array(); + $iResultRootUid = 0; + + if (isset($mAllThreads[$iThreadUid])) + { + $iResultRootUid = $iThreadUid; + if (\is_array($mAllThreads[$iThreadUid])) + { + $aUids = $mAllThreads[$iThreadUid]; + } + } + else + { + foreach ($mAllThreads as $iRootUid => $mSubUids) + { + if (\is_array($mSubUids) && \in_array($iThreadUid, $mSubUids)) + { + $iResultRootUid = $iRootUid; + $aUids = $mSubUids; + continue; + } + } + } + + if (0 < $iResultRootUid && \in_array($iResultRootUid, $mAllSortedUids)) + { + \array_unshift($aUids, $iResultRootUid); + } + } + else if ($bUseThreadSortIfSupported && \is_array($mAllThreads)) + { + $aUids = \array_keys($mAllThreads); + } + else + { + $bUseThreadSortIfSupported = false; + $aUids = $mAllSortedUids; + } + + if (0 < \strlen($sSearch) && \is_array($aUids)) + { + $aSearchedUids = $this->GetUids($oCacher, $sSearch, $sFilter, + $oMessageCollection->FolderName, $oMessageCollection->FolderHash); + + if (\is_array($aSearchedUids) && 0 < \count($aSearchedUids)) + { + $aFlippedSearchedUids = \array_flip($aSearchedUids); + + $bSearch = true; + $aNewUids = array(); + + foreach ($aUids as $iUid) + { + if (isset($aFlippedSearchedUids[$iUid])) + { + $aNewUids[] = $iUid; + } + else if ($bUseThreadSortIfSupported && 0 === $iThreadUid && isset($mAllThreads[$iUid]) && \is_array($mAllThreads[$iUid])) + { + foreach ($mAllThreads[$iUid] as $iSubUid) + { + if (isset($aFlippedSearchedUids[$iSubUid])) + { + $aNewUids[] = $iUid; + continue; + } + } + } + } + + $aUids = \array_unique($aNewUids); + unset($aNewUids); + } + else + { + $aUids = array(); + } + } + + if (\is_array($aUids)) + { + $oMessageCollection->MessageCount = $iMessageRealCount; + $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount; + $oMessageCollection->MessageResultCount = \count($aUids); + + if (0 < \count($aUids)) + { + $aRequestUids = \array_slice($aUids, $iOffset, $iLimit); + $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestUids, true); + } + } + } + else if (0 < $iMessageRealCount) + { + if ($this->oLogger) + { + $this->oLogger->Write('List optimization (count: '.$iMessageRealCount. + ', limit:'.\MailSo\Config::$MessageListCountLimitTrigger.')'); + } + + $oMessageCollection->MessageCount = $iMessageRealCount; + $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount; + + if (0 < \strlen($sSearch) || $bUseFilter) + { + $aUids = $this->GetUids($oCacher, $sSearch, $sFilter, + $oMessageCollection->FolderName, $oMessageCollection->FolderHash); + + if (0 < \count($aUids)) + { + $oMessageCollection->MessageResultCount = \count($aUids); + + $aRequestUids = \array_slice($aUids, $iOffset, $iLimit); + $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestUids, true); + } + else + { + $oMessageCollection->MessageResultCount = 0; + } + } + else + { + $oMessageCollection->MessageResultCount = $iMessageRealCount; + + if (1 < $iMessageRealCount) + { + $aRequestIndexes = \array_slice(array_reverse(range(1, $iMessageRealCount)), $iOffset, $iLimit); + } + else + { + $aRequestIndexes = \array_slice(array(1), $iOffset, $iLimit); + } + + $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestIndexes, false); + } + } + + if ($bUseThreadSortIfSupported && 0 === $iThreadUid && \is_array($mAllThreads) && 0 < \count($mAllThreads)) + { + $oMessageCollection->ForeachList(function (/* @var $oMessage \MailSo\Mail\Message */ $oMessage) use ($mAllThreads) { + + $iUid = $oMessage->Uid(); + if (isset($mAllThreads[$iUid]) && \is_array($mAllThreads[$iUid]) && 0 < \count($mAllThreads[$iUid])) + { + $aSubThreads = $mAllThreads[$iUid]; + \array_unshift($aSubThreads, $iUid); + + $oMessage->SetThreads(\array_map('trim', $aSubThreads)); + unset($aSubThreads); + } + }); + } + + return $oMessageCollection; + } + + /** + * @return array|false + */ + public function Quota() + { + return $this->oImapClient->Quota(); + } + + /** + * @param string $sFolderName + * @param string $sMessageId + * + * @return int|null + */ + public function FindMessageUidByMessageId($sFolderName, $sMessageId) + { + if (0 === \strlen($sMessageId)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderExamine($sFolderName); + + $aUids = $this->oImapClient->MessageSimpleSearch( + 'HEADER Message-ID '.$sMessageId, true); + + return \is_array($aUids) && 1 === \count($aUids) && \is_numeric($aUids[0]) ? (int) $aUids[0] : null; + } + + /** + * @param array $aMailFoldersHelper + * @param int $iOptimizationLimit = 0 + * + * @return array + */ + public function folderListOptimization($aMailFoldersHelper, $iOptimizationLimit = 0) + { + // optimization + if (10 < $iOptimizationLimit && \is_array($aMailFoldersHelper) && $iOptimizationLimit < \count($aMailFoldersHelper)) + { + if ($this->oLogger) + { + $this->oLogger->Write('Start optimization (limit:'.$iOptimizationLimit.') for '.\count($aMailFoldersHelper).' folders'); + } + + $iForeachLimit = 1; + + $aFilteredNames = array( + 'inbox', + 'sent', 'send', 'outbox', 'sentmail', 'sendmail', + 'drafts', 'draft', + 'junk', 'spam', 'spambucket', + 'trash', 'bin', 'deleted', + 'archives', 'archive', 'allmail', 'all', + 'starred', 'flagged', 'important', + 'contacts', 'chats' + ); + + $aNewMailFoldersHelper = array(); + + $iCountLimit = $iForeachLimit; + + foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) + { + // mandatory folders + if ($oFolder && \in_array(\str_replace(' ', '', \strtolower($oFolder->NameRaw())), $aFilteredNames)) + { + $aNewMailFoldersHelper[] = $oFolder; + $aMailFoldersHelper[$iIndex] = null; + } + } + + foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) + { + // subscribed folders + if ($oFolder && $oFolder->IsSubscribed()) + { + $aNewMailFoldersHelper[] = $oFolder; + + $aMailFoldersHelper[$iIndex] = null; + $iCountLimit--; + } + + if (0 > $iCountLimit) + { + if ($iOptimizationLimit < \count($aNewMailFoldersHelper)) + { + break; + } + else + { + $iCountLimit = $iForeachLimit; + } + } + } + + $iCountLimit = $iForeachLimit; + if ($iOptimizationLimit >= \count($aNewMailFoldersHelper)) + { + // name filter + foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) + { + if ($oFolder && !\preg_match('/[{}\[\]]/', $oFolder->NameRaw())) + { + $aNewMailFoldersHelper[] = $oFolder; + + $aMailFoldersHelper[$iIndex] = null; + $iCountLimit--; + } + + if (0 > $iCountLimit) + { + if ($iOptimizationLimit < \count($aNewMailFoldersHelper)) + { + break; + } + else + { + $iCountLimit = $iForeachLimit; + } + } + } + } + + $iCountLimit = $iForeachLimit; + if ($iOptimizationLimit >= \count($aNewMailFoldersHelper)) + { + // other + foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder) + { + if ($oFolder) + { + $aNewMailFoldersHelper[] = $oFolder; + + $aMailFoldersHelper[$iIndex] = null; + $iCountLimit--; + } + + if (0 > $iCountLimit) + { + if ($iOptimizationLimit < \count($aNewMailFoldersHelper)) + { + break; + } + else + { + $iCountLimit = $iForeachLimit; + } + } + } + } + + $aMailFoldersHelper = $aNewMailFoldersHelper; + + if ($this->oLogger) + { + $this->oLogger->Write('Result optimization: '.\count($aMailFoldersHelper).' folders'); + } + } + + return $aMailFoldersHelper; + } + + /** + * @param string $sParent = '' + * @param string $sListPattern = '*' + * @param bool $bUseListSubscribeStatus = false + * @param int $iOptimizationLimit = 0 + * + * @return \MailSo\Mail\FolderCollection|false + */ + public function Folders($sParent = '', $sListPattern = '*', $bUseListSubscribeStatus = true, $iOptimizationLimit = 0) + { + $oFolderCollection = false; + + $aSubscribedFolders = null; + if ($bUseListSubscribeStatus) + { + try + { + $aSubscribedFolders = $this->oImapClient->FolderSubscribeList($sParent, $sListPattern); + } + catch (\Exception $oException) + { + unset($oException); + } + } + + $aImapSubscribedFoldersHelper = null; + if (\is_array($aSubscribedFolders)) + { + $aImapSubscribedFoldersHelper = array(); + foreach ($aSubscribedFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) + { + $aImapSubscribedFoldersHelper[] = $oImapFolder->FullNameRaw(); + } + } + + $aFolders = $this->oImapClient->FolderList($sParent, $sListPattern); + + $bOptimized = false; + $aMailFoldersHelper = null; + + if (\is_array($aFolders)) + { + $aMailFoldersHelper = array(); + + foreach ($aFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) + { + $aMailFoldersHelper[] = Folder::NewInstance($oImapFolder, + (null === $aImapSubscribedFoldersHelper || \in_array($oImapFolder->FullNameRaw(), $aImapSubscribedFoldersHelper)) || + $oImapFolder->IsInbox() + ); + } + + $iCount = \count($aMailFoldersHelper); + $aMailFoldersHelper = $this->folderListOptimization($aMailFoldersHelper, $iOptimizationLimit); + + $bOptimized = $iCount !== \count($aMailFoldersHelper); + } + + if (\is_array($aMailFoldersHelper)) + { + $oFolderCollection = FolderCollection::NewInstance(); + $oFolderCollection->InitByUnsortedMailFolderArray($aMailFoldersHelper); + + $oFolderCollection->Optimized = $bOptimized; + } + + if ($oFolderCollection) + { + $oFolderCollection->SortByCallback(function ($oFolderA, $oFolderB) { + $sA = \strtoupper($oFolderA->FullNameRaw()); + $sB = \strtoupper($oFolderB->FullNameRaw()); + switch (true) + { + case 'INBOX' === $sA: + return -1; + case 'INBOX' === $sB: + return 1; + case '[GMAIL]' === $sA: + return -1; + case '[GMAIL]' === $sB: + return 1; + } + + return \strnatcasecmp($oFolderA->FullName(), $oFolderB->FullName()); + }); + + $oNamespace = $this->oImapClient->GetNamespace(); + if ($oNamespace) + { + $oFolderCollection->SetNamespace($oNamespace->GetPersonalNamespace()); + } + + $oFolderCollection->IsThreadsSupported = $this->IsThreadsSupported(); + } + + return $oFolderCollection; + } + + /** + * @param string $sFolderNameInUtf8 + * @param string $sFolderParentFullNameRaw = '' + * @param bool $bSubscribeOnCreation = true + * @param string $sDelimiter = '' + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function FolderCreate($sFolderNameInUtf8, $sFolderParentFullNameRaw = '', $bSubscribeOnCreation = true, $sDelimiter = '') + { + if (!\MailSo\Base\Validator::NotEmptyString($sFolderNameInUtf8, true) || + !\is_string($sFolderParentFullNameRaw)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $sFolderNameInUtf8 = \trim($sFolderNameInUtf8); + + if (0 === \strlen($sDelimiter) || 0 < \strlen(\trim($sFolderParentFullNameRaw))) + { + $aFolders = $this->oImapClient->FolderList('', 0 === \strlen(\trim($sFolderParentFullNameRaw)) ? 'INBOX' : $sFolderParentFullNameRaw); + if (!\is_array($aFolders) || !isset($aFolders[0])) + { + // TODO + throw new \MailSo\Mail\Exceptions\RuntimeException( + 0 === \strlen(trim($sFolderParentFullNameRaw)) + ? 'Cannot get folder delimiter' + : 'Cannot create folder in non-existen parent folder'); + } + + $sDelimiter = $aFolders[0]->Delimiter(); + if (0 < \strlen($sDelimiter) && 0 < \strlen(\trim($sFolderParentFullNameRaw))) + { + $sFolderParentFullNameRaw .= $sDelimiter; + } + } + + $sFullNameRawToCreate = \MailSo\Base\Utils::ConvertEncoding($sFolderNameInUtf8, + \MailSo\Base\Enumerations\Charset::UTF_8, + \MailSo\Base\Enumerations\Charset::UTF_7_IMAP); + + if (0 < \strlen($sDelimiter) && false !== \strpos($sFullNameRawToCreate, $sDelimiter)) + { + // TODO + throw new \MailSo\Mail\Exceptions\RuntimeException( + 'New folder name contains delimiter'); + } + + $sFullNameRawToCreate = $sFolderParentFullNameRaw.$sFullNameRawToCreate; + + $this->oImapClient->FolderCreate($sFullNameRawToCreate); + + if ($bSubscribeOnCreation) + { + $this->oImapClient->FolderSubscribe($sFullNameRawToCreate); + } + + return $this; + } + + /** + * @param string $sPrevFolderFullNameRaw + * @param string $sNextFolderFullNameInUtf + * @param bool $bSubscribeOnMove = true + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function FolderMove($sPrevFolderFullNameRaw, $sNextFolderFullNameInUtf, $bSubscribeOnMove = true) + { + return $this->folderModify($sPrevFolderFullNameRaw, $sNextFolderFullNameInUtf, false, $bSubscribeOnMove); + } + + /** + * @param string $sPrevFolderFullNameRaw + * @param string $sNewTopFolderNameInUtf + * @param bool $bSubscribeOnRename = true + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function FolderRename($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf, $bSubscribeOnRename = true) + { + return $this->folderModify($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf, true, $bSubscribeOnRename); + } + + /** + * @param string $sPrevFolderFullNameRaw + * @param string $sNextFolderNameInUtf + * @param bool $bRenameOrMove + * @param bool $bSubscribeOnModify + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function folderModify($sPrevFolderFullNameRaw, $sNextFolderNameInUtf, $bRenameOrMove, $bSubscribeOnModify) + { + if (0 === \strlen($sPrevFolderFullNameRaw) || 0 === \strlen($sNextFolderNameInUtf)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $aFolders = $this->oImapClient->FolderList('', $sPrevFolderFullNameRaw); + if (!\is_array($aFolders) || !isset($aFolders[0])) + { + // TODO + throw new \MailSo\Mail\Exceptions\RuntimeException('Cannot rename non-existen folder'); + } + + $sDelimiter = $aFolders[0]->Delimiter(); + $iLast = \strrpos($sPrevFolderFullNameRaw, $sDelimiter); + + $mSubscribeFolders = null; + if ($bSubscribeOnModify) + { + $mSubscribeFolders = $this->oImapClient->FolderSubscribeList($sPrevFolderFullNameRaw, '*'); + if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders)) + { + foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) + { + $this->oImapClient->FolderUnSubscribe($oFolder->FullNameRaw()); + } + } + } + + $sNewFolderFullNameRaw = \MailSo\Base\Utils::ConvertEncoding($sNextFolderNameInUtf, + \MailSo\Base\Enumerations\Charset::UTF_8, + \MailSo\Base\Enumerations\Charset::UTF_7_IMAP); + + if($bRenameOrMove) + { + if (0 < \strlen($sDelimiter) && false !== \strpos($sNewFolderFullNameRaw, $sDelimiter)) + { + // TODO + throw new \MailSo\Mail\Exceptions\RuntimeException('New folder name contains delimiter'); + } + + $sFolderParentFullNameRaw = false === $iLast ? '' : \substr($sPrevFolderFullNameRaw, 0, $iLast + 1); + $sNewFolderFullNameRaw = $sFolderParentFullNameRaw.$sNewFolderFullNameRaw; + } + + $this->oImapClient->FolderRename($sPrevFolderFullNameRaw, $sNewFolderFullNameRaw); + + if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders)) + { + foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) + { + $sFolderFullNameRawForResubscrine = $oFolder->FullNameRaw(); + if (0 === \strpos($sFolderFullNameRawForResubscrine, $sPrevFolderFullNameRaw)) + { + $sNewFolderFullNameRawForResubscrine = $sNewFolderFullNameRaw. + \substr($sFolderFullNameRawForResubscrine, \strlen($sPrevFolderFullNameRaw)); + + $this->oImapClient->FolderSubscribe($sNewFolderFullNameRawForResubscrine); + } + } + } + + return $this; + } + + /** + * @param string $sFolderFullNameRaw + * @param bool $bUnsubscribeOnDeletion = true + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + * @throws \MailSo\Mail\Exceptions\RuntimeException + */ + public function FolderDelete($sFolderFullNameRaw, $bUnsubscribeOnDeletion = true) + { + if (0 === \strlen($sFolderFullNameRaw) || 'INBOX' === $sFolderFullNameRaw) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->FolderExamine($sFolderFullNameRaw); + + $aIndexOrUids = $this->oImapClient->MessageSimpleSearch('ALL'); + if (0 < \count($aIndexOrUids)) + { + throw new \MailSo\Mail\Exceptions\NonEmptyFolder(); + } + + $this->oImapClient->FolderExamine('INBOX'); + + if ($bUnsubscribeOnDeletion) + { + $this->oImapClient->FolderUnSubscribe($sFolderFullNameRaw); + } + + $this->oImapClient->FolderDelete($sFolderFullNameRaw); + + return $this; + } + + /** + * @param string $sFolderFullNameRaw + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function FolderClear($sFolderFullNameRaw) + { + $this->oImapClient->FolderSelect($sFolderFullNameRaw); + + $oFolderInformation = $this->oImapClient->FolderCurrentInformation(); + if ($oFolderInformation && $oFolderInformation->Exists && 0 < $oFolderInformation->Exists) // STATUS? + { + $this->oImapClient->MessageStoreFlag('1:*', false, + array(\MailSo\Imap\Enumerations\MessageFlag::DELETED), + \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT + ); + + $this->oImapClient->MessageExpunge(); + } + + return $this; + } + + /** + * @param string $sFolderFullNameRaw + * @param bool $bSubscribe + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function FolderSubscribe($sFolderFullNameRaw, $bSubscribe) + { + if (0 === \strlen($sFolderFullNameRaw)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oImapClient->{($bSubscribe) ? 'FolderSubscribe' : 'FolderUnSubscribe'}($sFolderFullNameRaw); + + return $this; + } + + /** + * @param \MailSo\Log\Logger $oLogger + * + * @return \MailSo\Mail\MailClient + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public function SetLogger($oLogger) + { + if (!($oLogger instanceof \MailSo\Log\Logger)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $this->oLogger = $oLogger; + $this->oImapClient->SetLogger($this->oLogger); + + return $this; + } +} diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Mime/Email.php b/rainloop/v/0.0.0/app/libraries/MailSo/Mime/Email.php index 1da3d320f..9dd393f5d 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Mime/Email.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Mime/Email.php @@ -1,338 +1,315 @@ -sEmail = \MailSo\Base\Utils::IdnToAscii( - \MailSo\Base\Utils::Trim($sEmail), true); - - $this->sDisplayName = \MailSo\Base\Utils::Trim($sDisplayName); - $this->sRemark = \MailSo\Base\Utils::Trim($sRemark); - - $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::NONE; - $this->sDkimValue = ''; - } - - /** - * @param string $sEmail - * @param string $sDisplayName = '' - * @param string $sRemark = '' - * - * @return \MailSo\Mime\Email - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public static function NewInstance($sEmail, $sDisplayName = '', $sRemark = '') - { - return new self($sEmail, $sDisplayName, $sRemark); - } - - /** - * @param string $sEmailAddress - * @return \MailSo\Mime\Email - * - * @throws \MailSo\Base\Exceptions\InvalidArgumentException - */ - public static function Parse($sEmailAddress) - { - $sEmailAddress = \MailSo\Base\Utils::Trim($sEmailAddress); - if (!\MailSo\Base\Validator::NotEmptyString($sEmailAddress, true)) - { - throw new \MailSo\Base\Exceptions\InvalidArgumentException(); - } - - $sName = ''; - $sEmail = ''; - $sComment = ''; - - $bInName = false; - $bInAddress = false; - $bInComment = false; - - $iStartIndex = 0; - $iEndIndex = 0; - $iCurrentIndex = 0; - - while ($iCurrentIndex < \strlen($sEmailAddress)) - { - switch ($sEmailAddress{$iCurrentIndex}) - { -// case '\'': - case '"': -// $sQuoteChar = $sEmailAddress{$iCurrentIndex}; - if ((!$bInName) && (!$bInAddress) && (!$bInComment)) - { - $bInName = true; - $iStartIndex = $iCurrentIndex; - } - else if ((!$bInAddress) && (!$bInComment)) - { - $iEndIndex = $iCurrentIndex; - $sName = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); - $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); - $iEndIndex = 0; - $iCurrentIndex = 0; - $iStartIndex = 0; - $bInName = false; - } - break; - case '<': - if ((!$bInName) && (!$bInAddress) && (!$bInComment)) - { - if ($iCurrentIndex > 0 && \strlen($sName) === 0) - { - $sName = \substr($sEmailAddress, 0, $iCurrentIndex); - } - - $bInAddress = true; - $iStartIndex = $iCurrentIndex; - } - break; - case '>': - if ($bInAddress) - { - $iEndIndex = $iCurrentIndex; - $sEmail = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); - $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); - $iEndIndex = 0; - $iCurrentIndex = 0; - $iStartIndex = 0; - $bInAddress = false; - } - break; - case '(': - if ((!$bInName) && (!$bInAddress) && (!$bInComment)) - { - $bInComment = true; - $iStartIndex = $iCurrentIndex; - } - break; - case ')': - if ($bInComment) - { - $iEndIndex = $iCurrentIndex; - $sComment = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); - $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); - $iEndIndex = 0; - $iCurrentIndex = 0; - $iStartIndex = 0; - $bInComment = false; - } - break; - case '\\': - $iCurrentIndex++; - break; - } - - $iCurrentIndex++; - } - - if (\strlen($sEmail) === 0) - { - $aRegs = array(''); - if (\preg_match('/[^@\s]+@\S+/i', $sEmailAddress, $aRegs) && isset($aRegs[0])) - { - $sEmail = $aRegs[0]; - } - else - { - $sName = $sEmailAddress; - } - } - - if ((\strlen($sEmail) > 0) && (\strlen($sName) == 0) && (\strlen($sComment) == 0)) - { - $sName = \str_replace($sEmail, '', $sEmailAddress); - } - - $sEmail = \trim(\trim($sEmail), '<>'); - $sEmail = \rtrim(\trim($sEmail), '.'); - $sEmail = \trim($sEmail); - - $sName = \trim(\trim($sName), '"'); - $sName = \trim($sName, '\''); - $sComment = \trim(\trim($sComment), '()'); - - // Remove backslash - $sName = \preg_replace('/\\\\(.)/s', '$1', $sName); - $sComment = \preg_replace('/\\\\(.)/s', '$1', $sComment); - - return Email::NewInstance($sEmail, $sName, $sComment); - } - - /** - * @param bool $bIdn = false - * - * @return string - */ - public function GetEmail($bIdn = false) - { - return $bIdn ? \MailSo\Base\Utils::IdnToUtf8($this->sEmail) : $this->sEmail; - } - - /** - * @return string - */ - public function GetDisplayName() - { - return $this->sDisplayName; - } - - /** - * @return string - */ - public function GetRemark() - { - return $this->sRemark; - } - - /** - * @return string - */ - public function GetDkimStatus() - { - return $this->sDkimStatus; - } - - /** - * @return string - */ - public function GetDkimValue() - { - return $this->sDkimValue; - } - - /** - * @return string - */ - public function GetAccountName() - { - return \MailSo\Base\Utils::GetAccountNameFromEmail($this->GetEmail(false)); - } - - /** - * @param bool $bIdn = false - * - * @return string - */ - public function GetDomain($bIdn = false) - { - return \MailSo\Base\Utils::GetDomainFromEmail($this->GetEmail($bIdn)); - } - - /** - * @param string $sDkimStatus - * @param string $sDkimValue = '' - */ - public function SetDkimStatusAndValue($sDkimStatus, $sDkimValue = '') - { - $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::normalizeValue($sDkimStatus); - $this->sDkimValue = $sDkimValue; - } - - /** - * @param bool $bIdn = false - * @param bool $bDkim = true - * - * @return array - */ - public function ToArray($bIdn = false, $bDkim = true) - { - return $bDkim ? array($this->sDisplayName, $this->GetEmail($bIdn), $this->sRemark, $this->sDkimStatus, $this->sDkimValue) : - array($this->sDisplayName, $this->GetEmail($bIdn), $this->sRemark); - } - - /** - * @param bool $bConvertSpecialsName = false - * @param bool $bIdn = false - * - * @return string - */ - public function ToString($bConvertSpecialsName = false, $bIdn = false) - { - $sReturn = ''; - - $sRemark = \str_replace(')', '\)', $this->sRemark); - $sDisplayName = \str_replace('"', '\"', $this->sDisplayName); - - if ($bConvertSpecialsName) - { - $sDisplayName = 0 === \strlen($sDisplayName) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue( - \MailSo\Base\Enumerations\Encoding::BASE64_SHORT, - $sDisplayName); - - $sRemark = 0 === \strlen($sRemark) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue( - \MailSo\Base\Enumerations\Encoding::BASE64_SHORT, - $sRemark); - } - - $sDisplayName = 0 === \strlen($sDisplayName) ? '' : '"'.$sDisplayName.'"'; - $sRemark = 0 === \strlen($sRemark) ? '' : '('.$sRemark.')'; - - if (0 < \strlen($this->sEmail)) - { - $sReturn = $this->GetEmail($bIdn); - if (0 < \strlen($sDisplayName.$sRemark)) - { - $sReturn = $sDisplayName.' <'.$sReturn.'> '.$sRemark; - } - } - - return \trim($sReturn); - } -} +sEmail = \MailSo\Base\Utils::IdnToAscii( + \MailSo\Base\Utils::Trim($sEmail), true); + + $this->sDisplayName = \MailSo\Base\Utils::Trim($sDisplayName); + + $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::NONE; + $this->sDkimValue = ''; + } + + /** + * @param string $sEmail + * @param string $sDisplayName = '' + * + * @return \MailSo\Mime\Email + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public static function NewInstance($sEmail, $sDisplayName = '') + { + return new self($sEmail, $sDisplayName); + } + + /** + * @param string $sEmailAddress + * @return \MailSo\Mime\Email + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public static function Parse($sEmailAddress) + { + $sEmailAddress = \MailSo\Base\Utils::Trim($sEmailAddress); + if (!\MailSo\Base\Validator::NotEmptyString($sEmailAddress, true)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $sName = ''; + $sEmail = ''; + $sComment = ''; + + $bInName = false; + $bInAddress = false; + $bInComment = false; + + $iStartIndex = 0; + $iEndIndex = 0; + $iCurrentIndex = 0; + + while ($iCurrentIndex < \strlen($sEmailAddress)) + { + switch ($sEmailAddress{$iCurrentIndex}) + { +// case '\'': + case '"': +// $sQuoteChar = $sEmailAddress{$iCurrentIndex}; + if ((!$bInName) && (!$bInAddress) && (!$bInComment)) + { + $bInName = true; + $iStartIndex = $iCurrentIndex; + } + else if ((!$bInAddress) && (!$bInComment)) + { + $iEndIndex = $iCurrentIndex; + $sName = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); + $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); + $iEndIndex = 0; + $iCurrentIndex = 0; + $iStartIndex = 0; + $bInName = false; + } + break; + case '<': + if ((!$bInName) && (!$bInAddress) && (!$bInComment)) + { + if ($iCurrentIndex > 0 && \strlen($sName) === 0) + { + $sName = \substr($sEmailAddress, 0, $iCurrentIndex); + } + + $bInAddress = true; + $iStartIndex = $iCurrentIndex; + } + break; + case '>': + if ($bInAddress) + { + $iEndIndex = $iCurrentIndex; + $sEmail = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); + $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); + $iEndIndex = 0; + $iCurrentIndex = 0; + $iStartIndex = 0; + $bInAddress = false; + } + break; + case '(': + if ((!$bInName) && (!$bInAddress) && (!$bInComment)) + { + $bInComment = true; + $iStartIndex = $iCurrentIndex; + } + break; + case ')': + if ($bInComment) + { + $iEndIndex = $iCurrentIndex; + $sComment = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); + $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); + $iEndIndex = 0; + $iCurrentIndex = 0; + $iStartIndex = 0; + $bInComment = false; + } + break; + case '\\': + $iCurrentIndex++; + break; + } + + $iCurrentIndex++; + } + + if (\strlen($sEmail) === 0) + { + $aRegs = array(''); + if (\preg_match('/[^@\s]+@\S+/i', $sEmailAddress, $aRegs) && isset($aRegs[0])) + { + $sEmail = $aRegs[0]; + } + else + { + $sName = $sEmailAddress; + } + } + + if ((\strlen($sEmail) > 0) && (\strlen($sName) == 0) && (\strlen($sComment) == 0)) + { + $sName = \str_replace($sEmail, '', $sEmailAddress); + } + + $sEmail = \trim(\trim($sEmail), '<>'); + $sEmail = \rtrim(\trim($sEmail), '.'); + $sEmail = \trim($sEmail); + + $sName = \trim(\trim($sName), '"'); + $sName = \trim($sName, '\''); + $sComment = \trim(\trim($sComment), '()'); + + // Remove backslash + $sName = \preg_replace('/\\\\(.)/s', '$1', $sName); + $sComment = \preg_replace('/\\\\(.)/s', '$1', $sComment); + + return Email::NewInstance($sEmail, $sName); + } + + /** + * @param bool $bIdn = false + * + * @return string + */ + public function GetEmail($bIdn = false) + { + return $bIdn ? \MailSo\Base\Utils::IdnToUtf8($this->sEmail) : $this->sEmail; + } + + /** + * @return string + */ + public function GetDisplayName() + { + return $this->sDisplayName; + } + + /** + * @return string + */ + public function GetDkimStatus() + { + return $this->sDkimStatus; + } + + /** + * @return string + */ + public function GetDkimValue() + { + return $this->sDkimValue; + } + + /** + * @return string + */ + public function GetAccountName() + { + return \MailSo\Base\Utils::GetAccountNameFromEmail($this->GetEmail(false)); + } + + /** + * @param bool $bIdn = false + * + * @return string + */ + public function GetDomain($bIdn = false) + { + return \MailSo\Base\Utils::GetDomainFromEmail($this->GetEmail($bIdn)); + } + + /** + * @param string $sDkimStatus + * @param string $sDkimValue = '' + */ + public function SetDkimStatusAndValue($sDkimStatus, $sDkimValue = '') + { + $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::normalizeValue($sDkimStatus); + $this->sDkimValue = $sDkimValue; + } + + /** + * @param bool $bIdn = false + * @param bool $bDkim = true + * + * @return array + */ + public function ToArray($bIdn = false, $bDkim = true) + { + return $bDkim ? + array($this->sDisplayName, $this->GetEmail($bIdn), $this->sDkimStatus, $this->sDkimValue) : + array($this->sDisplayName, $this->GetEmail($bIdn)); + } + + /** + * @param bool $bConvertSpecialsName = false + * @param bool $bIdn = false + * + * @return string + */ + public function ToString($bConvertSpecialsName = false, $bIdn = false) + { + $sReturn = ''; + + $sDisplayName = \str_replace('"', '\"', $this->sDisplayName); + if ($bConvertSpecialsName) + { + $sDisplayName = 0 === \strlen($sDisplayName) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue( + \MailSo\Base\Enumerations\Encoding::BASE64_SHORT, + $sDisplayName); + } + + $sDisplayName = 0 === \strlen($sDisplayName) ? '' : '"'.$sDisplayName.'"'; + if (0 < \strlen($this->sEmail)) + { + $sReturn = $this->GetEmail($bIdn); + if (0 < \strlen($sDisplayName)) + { + $sReturn = $sDisplayName.' <'.$sReturn.'>'; + } + } + + return \trim($sReturn); + } +} diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Mime/EmailDep.php b/rainloop/v/0.0.0/app/libraries/MailSo/Mime/EmailDep.php new file mode 100644 index 000000000..64173bed3 --- /dev/null +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Mime/EmailDep.php @@ -0,0 +1,339 @@ +sEmail = \MailSo\Base\Utils::IdnToAscii( + \MailSo\Base\Utils::Trim($sEmail), true); + + $this->sDisplayName = \MailSo\Base\Utils::Trim($sDisplayName); + $this->sRemark = \MailSo\Base\Utils::Trim($sRemark); + + $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::NONE; + $this->sDkimValue = ''; + } + + /** + * @param string $sEmail + * @param string $sDisplayName = '' + * @param string $sRemark = '' + * + * @return \MailSo\Mime\Email + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public static function NewInstance($sEmail, $sDisplayName = '', $sRemark = '') + { + return new self($sEmail, $sDisplayName, $sRemark); + } + + /** + * @param string $sEmailAddress + * @return \MailSo\Mime\Email + * + * @throws \MailSo\Base\Exceptions\InvalidArgumentException + */ + public static function Parse($sEmailAddress) + { + $sEmailAddress = \MailSo\Base\Utils::Trim($sEmailAddress); + if (!\MailSo\Base\Validator::NotEmptyString($sEmailAddress, true)) + { + throw new \MailSo\Base\Exceptions\InvalidArgumentException(); + } + + $sName = ''; + $sEmail = ''; + $sComment = ''; + + $bInName = false; + $bInAddress = false; + $bInComment = false; + + $iStartIndex = 0; + $iEndIndex = 0; + $iCurrentIndex = 0; + + while ($iCurrentIndex < \strlen($sEmailAddress)) + { + switch ($sEmailAddress{$iCurrentIndex}) + { +// case '\'': + case '"': +// $sQuoteChar = $sEmailAddress{$iCurrentIndex}; + if ((!$bInName) && (!$bInAddress) && (!$bInComment)) + { + $bInName = true; + $iStartIndex = $iCurrentIndex; + } + else if ((!$bInAddress) && (!$bInComment)) + { + $iEndIndex = $iCurrentIndex; + $sName = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); + $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); + $iEndIndex = 0; + $iCurrentIndex = 0; + $iStartIndex = 0; + $bInName = false; + } + break; + case '<': + if ((!$bInName) && (!$bInAddress) && (!$bInComment)) + { + if ($iCurrentIndex > 0 && \strlen($sName) === 0) + { + $sName = \substr($sEmailAddress, 0, $iCurrentIndex); + } + + $bInAddress = true; + $iStartIndex = $iCurrentIndex; + } + break; + case '>': + if ($bInAddress) + { + $iEndIndex = $iCurrentIndex; + $sEmail = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); + $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); + $iEndIndex = 0; + $iCurrentIndex = 0; + $iStartIndex = 0; + $bInAddress = false; + } + break; + case '(': + if ((!$bInName) && (!$bInAddress) && (!$bInComment)) + { + $bInComment = true; + $iStartIndex = $iCurrentIndex; + } + break; + case ')': + if ($bInComment) + { + $iEndIndex = $iCurrentIndex; + $sComment = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); + $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); + $iEndIndex = 0; + $iCurrentIndex = 0; + $iStartIndex = 0; + $bInComment = false; + } + break; + case '\\': + $iCurrentIndex++; + break; + } + + $iCurrentIndex++; + } + + if (\strlen($sEmail) === 0) + { + $aRegs = array(''); + if (\preg_match('/[^@\s]+@\S+/i', $sEmailAddress, $aRegs) && isset($aRegs[0])) + { + $sEmail = $aRegs[0]; + } + else + { + $sName = $sEmailAddress; + } + } + + if ((\strlen($sEmail) > 0) && (\strlen($sName) == 0) && (\strlen($sComment) == 0)) + { + $sName = \str_replace($sEmail, '', $sEmailAddress); + } + + $sEmail = \trim(\trim($sEmail), '<>'); + $sEmail = \rtrim(\trim($sEmail), '.'); + $sEmail = \trim($sEmail); + + $sName = \trim(\trim($sName), '"'); + $sName = \trim($sName, '\''); + $sComment = \trim(\trim($sComment), '()'); + + // Remove backslash + $sName = \preg_replace('/\\\\(.)/s', '$1', $sName); + $sComment = \preg_replace('/\\\\(.)/s', '$1', $sComment); + + return Email::NewInstance($sEmail, $sName, $sComment); + } + + /** + * @param bool $bIdn = false + * + * @return string + */ + public function GetEmail($bIdn = false) + { + return $bIdn ? \MailSo\Base\Utils::IdnToUtf8($this->sEmail) : $this->sEmail; + } + + /** + * @return string + */ + public function GetDisplayName() + { + return $this->sDisplayName; + } + + /** + * @return string + */ + public function GetRemark() + { + return $this->sRemark; + } + + /** + * @return string + */ + public function GetDkimStatus() + { + return $this->sDkimStatus; + } + + /** + * @return string + */ + public function GetDkimValue() + { + return $this->sDkimValue; + } + + /** + * @return string + */ + public function GetAccountName() + { + return \MailSo\Base\Utils::GetAccountNameFromEmail($this->GetEmail(false)); + } + + /** + * @param bool $bIdn = false + * + * @return string + */ + public function GetDomain($bIdn = false) + { + return \MailSo\Base\Utils::GetDomainFromEmail($this->GetEmail($bIdn)); + } + + /** + * @param string $sDkimStatus + * @param string $sDkimValue = '' + */ + public function SetDkimStatusAndValue($sDkimStatus, $sDkimValue = '') + { + $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::normalizeValue($sDkimStatus); + $this->sDkimValue = $sDkimValue; + } + + /** + * @param bool $bIdn = false + * @param bool $bDkim = true + * + * @return array + */ + public function ToArray($bIdn = false, $bDkim = true) + { + return $bDkim ? array($this->sDisplayName, $this->GetEmail($bIdn), $this->sRemark, $this->sDkimStatus, $this->sDkimValue) : + array($this->sDisplayName, $this->GetEmail($bIdn), $this->sRemark); + } + + /** + * @param bool $bConvertSpecialsName = false + * @param bool $bIdn = false + * + * @return string + */ + public function ToString($bConvertSpecialsName = false, $bIdn = false) + { + $sReturn = ''; + + $sRemark = \str_replace(')', '\)', $this->sRemark); + $sDisplayName = \str_replace('"', '\"', $this->sDisplayName); + + if ($bConvertSpecialsName) + { + $sDisplayName = 0 === \strlen($sDisplayName) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue( + \MailSo\Base\Enumerations\Encoding::BASE64_SHORT, + $sDisplayName); + + $sRemark = 0 === \strlen($sRemark) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue( + \MailSo\Base\Enumerations\Encoding::BASE64_SHORT, + $sRemark); + } + + $sDisplayName = 0 === \strlen($sDisplayName) ? '' : '"'.$sDisplayName.'"'; + $sRemark = 0 === \strlen($sRemark) ? '' : '('.$sRemark.')'; + + if (0 < \strlen($this->sEmail)) + { + $sReturn = $this->GetEmail($bIdn); + if (0 < \strlen($sDisplayName.$sRemark)) + { + $sReturn = $sDisplayName.' <'.$sReturn.'> '.$sRemark; + } + } + + return \trim($sReturn); + } +} diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/.gitignore b/rainloop/v/0.0.0/app/libraries/RainLoop/.gitignore deleted file mode 100644 index 416618dd3..000000000 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/Prem/** -/_Prem/** \ No newline at end of file diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php index 2863945ae..33f463bfd 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -820,9 +820,9 @@ class Actions { if (null === $this->oPremProvider) { - if (\file_exists(APP_VERSION_ROOT_PATH.'app/libraries/RainLoop/Prem/Provider.php')) + if (\file_exists(APP_VERSION_ROOT_PATH.'app/libraries/RainLoop/Providers/Prem.php')) { - $this->oPremProvider = new \RainLoop\Prem\Provider( + $this->oPremProvider = new \RainLoop\Providers\Prem( $this->Config(), $this->Logger(), $this->Cacher(null, true) ); } @@ -1466,8 +1466,7 @@ class Actions 'themes' => $this->GetThemes($bMobile, false), 'languages' => $this->GetLanguages(false), 'languagesAdmin' => $this->GetLanguages(true), - 'attachmentsActions' => $aAttachmentsActions, - 'openpgpPublicKeyServer' => $oConfig->Get('security', 'openpgp_public_key_server', '') + 'attachmentsActions' => $aAttachmentsActions ), $bAdmin ? array( 'adminHostUse' => '' !== $oConfig->Get('security', 'admin_panel_host', ''), 'adminPath' => \strtolower($oConfig->Get('security', 'admin_panel_key', 'admin')), @@ -2357,7 +2356,8 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack $this->Logger()->AddSecret($sPassword); if ('sleep@sleep.dev' === $sEmail && 0 < \strlen($sPassword) && - \is_numeric($sPassword) && $this->Config()->Get('debug', 'enable', false) + \is_numeric($sPassword) && $this->Config()->Get('debug', 'enable', false) && + 0 < (int) $sPassword && 30 > (int) $sPassword ) { \sleep((int) $sPassword); @@ -5179,8 +5179,11 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack $aCache = array( 'Sent' => \MailSo\Imap\Enumerations\FolderType::SENT, - 'Send' => \MailSo\Imap\Enumerations\FolderType::SENT, + + 'Outbox' => \MailSo\Imap\Enumerations\FolderType::SENT, + 'Out box' => \MailSo\Imap\Enumerations\FolderType::SENT, + 'Sent Item' => \MailSo\Imap\Enumerations\FolderType::SENT, 'Sent Items' => \MailSo\Imap\Enumerations\FolderType::SENT, 'Send Item' => \MailSo\Imap\Enumerations\FolderType::SENT, @@ -5199,6 +5202,7 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack 'Drafts Mails' => \MailSo\Imap\Enumerations\FolderType::DRAFTS, 'Spam' => \MailSo\Imap\Enumerations\FolderType::JUNK, + 'Spams' => \MailSo\Imap\Enumerations\FolderType::JUNK, 'Junk' => \MailSo\Imap\Enumerations\FolderType::JUNK, 'Bulk Mail' => \MailSo\Imap\Enumerations\FolderType::JUNK, @@ -5209,14 +5213,22 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack 'Bin' => \MailSo\Imap\Enumerations\FolderType::TRASH, 'Archive' => \MailSo\Imap\Enumerations\FolderType::ALL, + 'Archives' => \MailSo\Imap\Enumerations\FolderType::ALL, 'All' => \MailSo\Imap\Enumerations\FolderType::ALL, 'All Mail' => \MailSo\Imap\Enumerations\FolderType::ALL, 'All Mails' => \MailSo\Imap\Enumerations\FolderType::ALL, - 'AllMail' => \MailSo\Imap\Enumerations\FolderType::ALL, - 'AllMails' => \MailSo\Imap\Enumerations\FolderType::ALL, ); + $aNewCache = array(); + foreach ($aCache as $sKey => $iType) + { + $aNewCache[$sKey] = $iType; + $aNewCache[\str_replace(' ', '', $sKey)] = $iType; + } + + $aCache = $aNewCache; + $this->Plugins()->RunHook('filter.system-folders-names', array($oAccount, &$aCache)); } @@ -8416,35 +8428,35 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack case 1: break; - case 2: // horizontal flip + case 2: // flip horizontal $oImage->flipHorizontally(); break; - case 3: // 180 rotate left + case 3: // rotate 180 $oImage->rotate(180); break; - case 4: // vertical flip + case 4: // flip vertical $oImage->flipVertically(); break; - case 5: // vertical flip + 90 rotate right + case 5: // vertical flip + 90 rotate $oImage->flipVertically(); - $oImage->rotate(-90); - break; - - case 6: // 90 rotate right - $oImage->rotate(-90); - break; - - case 7: // horizontal flip + 90 rotate right - $oImage->flipHorizontally(); - $oImage->rotate(-90); - break; - - case 8: // 90 rotate left $oImage->rotate(90); break; + + case 6: // rotate 90 + $oImage->rotate(90); + break; + + case 7: // horizontal flip + 90 rotate + $oImage->flipHorizontally(); + $oImage->rotate(90); + break; + + case 8: // rotate 270 + $oImage->rotate(270); + break; } } } @@ -8586,8 +8598,6 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack $self->cacheByKey($sRawKey); $sLoadedData = null; - $bDetectImageOrientation = false; - if (!$bDownload) { if ($bThumbnail) @@ -9606,7 +9616,7 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack private function hashFolderFullName($sFolderFullName) { return \in_array(\strtolower($sFolderFullName), array('inbox', 'sent', 'send', 'drafts', - 'spam', 'junk', 'bin', 'trash', 'archive', 'allmail')) ? + 'spam', 'junk', 'bin', 'trash', 'archive', 'allmail', 'all')) ? $sFolderFullName : \md5($sFolderFullName); } diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php index 2bf4f75e0..a49e7b3fa 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php @@ -1,273 +1,273 @@ -Config(); - } - - /** - * @return \MailSo\Log\Logger - */ - public static function Logger() - { - return \RainLoop\Api::Actions()->Logger(); - } - - /** - * @return string - */ - public static function SetupDefaultMailSoConfig() - { - if (\class_exists('MailSo\Config')) - { - if (\RainLoop\Api::Config()->Get('labs', 'disable_iconv_if_mbstring_supported', false) && - \MailSo\Base\Utils::IsMbStringSupported() && \MailSo\Config::$MBSTRING) - { - \MailSo\Config::$ICONV = false; - } - - \MailSo\Config::$MessageListFastSimpleSearch = - !!\RainLoop\Api::Config()->Get('labs', 'imap_message_list_fast_simple_search', true); - - \MailSo\Config::$MessageListCountLimitTrigger = - (int) \RainLoop\Api::Config()->Get('labs', 'imap_message_list_count_limit_trigger', 0); - - \MailSo\Config::$MessageListDateFilter = - (int) \RainLoop\Api::Config()->Get('labs', 'imap_message_list_date_filter', 0); - - \MailSo\Config::$MessageListPermanentFilter = - \trim(\RainLoop\Api::Config()->Get('labs', 'imap_message_list_permanent_filter', '')); - - \MailSo\Config::$MessageAllHeaders = - !!\RainLoop\Api::Config()->Get('labs', 'imap_message_all_headers', false); - - \MailSo\Config::$LargeThreadLimit = - (int) \RainLoop\Api::Config()->Get('labs', 'imap_large_thread_limit', 50); - - \MailSo\Config::$ImapTimeout = - (int) \RainLoop\Api::Config()->Get('labs', 'imap_timeout', 300); - - \MailSo\Config::$BoundaryPrefix = '_RainLoop_'; - - \MailSo\Config::$SystemLogger = \RainLoop\Api::Logger(); - - $sSslCafile = \RainLoop\Api::Config()->Get('ssl', 'cafile', ''); - $sSslCapath = \RainLoop\Api::Config()->Get('ssl', 'capath', ''); - - \RainLoop\Utils::$CookieDefaultPath = \RainLoop\Api::Config()->Get('labs', 'cookie_default_path', ''); - if (\RainLoop\Api::Config()->Get('labs', 'cookie_default_secure', false)) - { - \RainLoop\Utils::$CookieDefaultSecure = true; - } - - if (!empty($sSslCafile) || !empty($sSslCapath)) - { - \MailSo\Hooks::Add('Net.NetClient.StreamContextSettings/Filter', function (&$aStreamContextSettings) use ($sSslCafile, $sSslCapath) { - if (isset($aStreamContextSettings['ssl']) && \is_array($aStreamContextSettings['ssl'])) - { - if (empty($aStreamContextSettings['ssl']['cafile']) && !empty($sSslCafile)) - { - $aStreamContextSettings['ssl']['cafile'] = $sSslCafile; - } - - if (empty($aStreamContextSettings['ssl']['capath']) && !empty($sSslCapath)) - { - $aStreamContextSettings['ssl']['capath'] = $sSslCapath; - } - } - }); - } - - \MailSo\Config::$HtmlStrictDebug = !!\RainLoop\Api::Config()->Get('debug', 'enable', false); - - if (\RainLoop\Api::Config()->Get('labs', 'strict_html_parser', true)) - { - \MailSo\Config::$HtmlStrictAllowedAttributes = array( - // rainloop - 'data-wrp', - // defaults - 'name', - 'dir', 'lang', 'style', 'title', - 'background', 'bgcolor', 'alt', 'height', 'width', 'src', 'href', - 'border', 'bordercolor', 'charset', 'direction', 'language', - // a - 'coords', 'download', 'hreflang', 'shape', - // body - 'alink', 'bgproperties', 'bottommargin', 'leftmargin', 'link', 'rightmargin', 'text', 'topmargin', 'vlink', - 'marginwidth', 'marginheight', 'offset', - // button, - 'disabled', 'type', 'value', - // col - 'align', 'valign', - // font - 'color', 'face', 'size', - // form - 'novalidate', - // hr - 'noshade', - // img - 'hspace', 'sizes', 'srcset', 'vspace', 'usemap', - // input, textarea - 'checked', 'max', 'min', 'maxlength', 'multiple', 'pattern', 'placeholder', 'readonly', 'required', 'step', 'wrap', - // label - 'for', - // meter - 'low', 'high', 'optimum', - // ol - 'reversed', 'start', - // option - 'selected', 'label', - // table - 'cols', 'rows', 'frame', 'rules', 'summary', 'cellpadding', 'cellspacing', - // td - 'abbr', 'axis', 'colspan', 'rowspan', 'headers', 'nowrap' - ); - } - } - } - - /** - * @return string - */ - public static function Version() - { - return APP_VERSION; - } - - /** - * @param string $sEmail - * @param string $sPassword - * @param array $aAdditionalOptions = array() - * @param bool $bUseTimeout = true - * - * @return string - */ - public static function GetUserSsoHash($sEmail, $sPassword, $aAdditionalOptions = array(), $bUseTimeout = true) - { - $sSsoHash = \MailSo\Base\Utils::Sha1Rand($sEmail.$sPassword); - - return \RainLoop\Api::Actions()->Cacher()->Set(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash), - \RainLoop\Utils::EncodeKeyValuesQ(array( - 'Email' => $sEmail, - 'Password' => $sPassword, - 'AdditionalOptions' => $aAdditionalOptions, - 'Time' => $bUseTimeout ? \time() : 0 - ))) ? $sSsoHash : ''; - } - - /** - * @param string $sSsoHash - * - * @return bool - */ - public static function ClearUserSsoHash($sSsoHash) - { - return \RainLoop\Api::Actions()->Cacher()->Delete(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash)); - } - - /** - * @param string $sEmail - * - * @return bool - */ - public static function ClearUserData($sEmail) - { - if (0 < \strlen($sEmail)) - { - $sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail); - - $oStorageProvider = \RainLoop\Api::Actions()->StorageProvider(); - if ($oStorageProvider && $oStorageProvider->IsActive()) - { - $oStorageProvider->DeleteStorage($sEmail); - } - - if (\RainLoop\Api::Actions()->AddressBookProvider() && - \RainLoop\Api::Actions()->AddressBookProvider()->IsActive()) - { - \RainLoop\Api::Actions()->AddressBookProvider()->DeleteAllContacts($sEmail); - } - - return true; - } - - return false; - } - - /** - * @return bool - */ - public static function LogoutCurrentLogginedUser() - { - \RainLoop\Utils::ClearCookie('rlsession'); - return true; - } - - /** - * @return void - */ - public static function ExitOnEnd() - { - if (!\defined('RAINLOOP_EXIT_ON_END')) - { - \define('RAINLOOP_EXIT_ON_END', true); - } - } -} +Config(); + } + + /** + * @return \MailSo\Log\Logger + */ + public static function Logger() + { + return \RainLoop\Api::Actions()->Logger(); + } + + /** + * @return string + */ + public static function SetupDefaultMailSoConfig() + { + if (\class_exists('MailSo\Config')) + { + if (\RainLoop\Api::Config()->Get('labs', 'disable_iconv_if_mbstring_supported', false) && + \MailSo\Base\Utils::IsMbStringSupported() && \MailSo\Config::$MBSTRING) + { + \MailSo\Config::$ICONV = false; + } + + \MailSo\Config::$MessageListFastSimpleSearch = + !!\RainLoop\Api::Config()->Get('labs', 'imap_message_list_fast_simple_search', true); + + \MailSo\Config::$MessageListCountLimitTrigger = + (int) \RainLoop\Api::Config()->Get('labs', 'imap_message_list_count_limit_trigger', 0); + + \MailSo\Config::$MessageListDateFilter = + (int) \RainLoop\Api::Config()->Get('labs', 'imap_message_list_date_filter', 0); + + \MailSo\Config::$MessageListPermanentFilter = + \trim(\RainLoop\Api::Config()->Get('labs', 'imap_message_list_permanent_filter', '')); + + \MailSo\Config::$MessageAllHeaders = + !!\RainLoop\Api::Config()->Get('labs', 'imap_message_all_headers', false); + + \MailSo\Config::$LargeThreadLimit = + (int) \RainLoop\Api::Config()->Get('labs', 'imap_large_thread_limit', 50); + + \MailSo\Config::$ImapTimeout = + (int) \RainLoop\Api::Config()->Get('labs', 'imap_timeout', 300); + + \MailSo\Config::$BoundaryPrefix = '_RainLoop_'; + + \MailSo\Config::$SystemLogger = \RainLoop\Api::Logger(); + + $sSslCafile = \RainLoop\Api::Config()->Get('ssl', 'cafile', ''); + $sSslCapath = \RainLoop\Api::Config()->Get('ssl', 'capath', ''); + + \RainLoop\Utils::$CookieDefaultPath = \RainLoop\Api::Config()->Get('labs', 'cookie_default_path', ''); + if (\RainLoop\Api::Config()->Get('labs', 'cookie_default_secure', false)) + { + \RainLoop\Utils::$CookieDefaultSecure = true; + } + + if (!empty($sSslCafile) || !empty($sSslCapath)) + { + \MailSo\Hooks::Add('Net.NetClient.StreamContextSettings/Filter', function (&$aStreamContextSettings) use ($sSslCafile, $sSslCapath) { + if (isset($aStreamContextSettings['ssl']) && \is_array($aStreamContextSettings['ssl'])) + { + if (empty($aStreamContextSettings['ssl']['cafile']) && !empty($sSslCafile)) + { + $aStreamContextSettings['ssl']['cafile'] = $sSslCafile; + } + + if (empty($aStreamContextSettings['ssl']['capath']) && !empty($sSslCapath)) + { + $aStreamContextSettings['ssl']['capath'] = $sSslCapath; + } + } + }); + } + + \MailSo\Config::$HtmlStrictDebug = !!\RainLoop\Api::Config()->Get('debug', 'enable', false); + + if (\RainLoop\Api::Config()->Get('labs', 'strict_html_parser', true)) + { + \MailSo\Config::$HtmlStrictAllowedAttributes = array( + // rainloop + 'data-wrp', + // defaults + 'name', + 'dir', 'lang', 'style', 'title', + 'background', 'bgcolor', 'alt', 'height', 'width', 'src', 'href', + 'border', 'bordercolor', 'charset', 'direction', 'language', + // a + 'coords', 'download', 'hreflang', 'shape', + // body + 'alink', 'bgproperties', 'bottommargin', 'leftmargin', 'link', 'rightmargin', 'text', 'topmargin', 'vlink', + 'marginwidth', 'marginheight', 'offset', + // button, + 'disabled', 'type', 'value', + // col + 'align', 'valign', + // font + 'color', 'face', 'size', + // form + 'novalidate', + // hr + 'noshade', + // img + 'hspace', 'sizes', 'srcset', 'vspace', 'usemap', + // input, textarea + 'checked', 'max', 'min', 'maxlength', 'multiple', 'pattern', 'placeholder', 'readonly', 'required', 'step', 'wrap', + // label + 'for', + // meter + 'low', 'high', 'optimum', + // ol + 'reversed', 'start', + // option + 'selected', 'label', + // table + 'cols', 'rows', 'frame', 'rules', 'summary', 'cellpadding', 'cellspacing', + // td + 'abbr', 'axis', 'colspan', 'rowspan', 'headers', 'nowrap' + ); + } + } + } + + /** + * @return string + */ + public static function Version() + { + return APP_VERSION; + } + + /** + * @param string $sEmail + * @param string $sPassword + * @param array $aAdditionalOptions = array() + * @param bool $bUseTimeout = true + * + * @return string + */ + public static function GetUserSsoHash($sEmail, $sPassword, $aAdditionalOptions = array(), $bUseTimeout = true) + { + $sSsoHash = \MailSo\Base\Utils::Sha1Rand(\md5($sEmail).\md5($sPassword)); + + return \RainLoop\Api::Actions()->Cacher()->Set(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash), + \RainLoop\Utils::EncodeKeyValuesQ(array( + 'Email' => $sEmail, + 'Password' => $sPassword, + 'AdditionalOptions' => $aAdditionalOptions, + 'Time' => $bUseTimeout ? \time() : 0 + ))) ? $sSsoHash : ''; + } + + /** + * @param string $sSsoHash + * + * @return bool + */ + public static function ClearUserSsoHash($sSsoHash) + { + return \RainLoop\Api::Actions()->Cacher()->Delete(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash)); + } + + /** + * @param string $sEmail + * + * @return bool + */ + public static function ClearUserData($sEmail) + { + if (0 < \strlen($sEmail)) + { + $sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail); + + $oStorageProvider = \RainLoop\Api::Actions()->StorageProvider(); + if ($oStorageProvider && $oStorageProvider->IsActive()) + { + $oStorageProvider->DeleteStorage($sEmail); + } + + if (\RainLoop\Api::Actions()->AddressBookProvider() && + \RainLoop\Api::Actions()->AddressBookProvider()->IsActive()) + { + \RainLoop\Api::Actions()->AddressBookProvider()->DeleteAllContacts($sEmail); + } + + return true; + } + + return false; + } + + /** + * @return bool + */ + public static function LogoutCurrentLogginedUser() + { + \RainLoop\Utils::ClearCookie('rlsession'); + return true; + } + + /** + * @return void + */ + public static function ExitOnEnd() + { + if (!\defined('RAINLOOP_EXIT_ON_END')) + { + \define('RAINLOOP_EXIT_ON_END', true); + } + } +} diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php index 3c49169c9..47ec8cd4e 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php @@ -200,7 +200,6 @@ class Application extends \RainLoop\Config\AbstractConfig 'x_frame_options_header' => array(''), 'openpgp' => array(false), - 'openpgp_public_key_server' => array(''), 'admin_login' => array('admin', 'Login and password for web admin panel'), 'admin_password' => array('12345'), diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Domain/DefaultDomain.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Domain/DefaultDomain.php index e30ba876c..cce572627 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Domain/DefaultDomain.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Domain/DefaultDomain.php @@ -1,404 +1,410 @@ -sDomainPath = \rtrim(\trim($sDomainPath), '\\/'); - $this->oCacher = $oCacher; - } - - /** - * @param string $sName - * @param bool $bBack = false - * - * @return string - */ - public function codeFileName($sName, $bBack = false) - { - if ($bBack && 'default' === $sName) - { - return '*'; - } - else if (!$bBack && '*' === $sName) - { - return 'default'; - } - - if ($bBack) - { - $sName = \MailSo\Base\Utils::IdnToUtf8($sName, true); - } - else - { - $sName = \MailSo\Base\Utils::IdnToAscii($sName, true); - } - - return $bBack ? \str_replace('_wildcard_', '*', $sName) : \str_replace('*', '_wildcard_', $sName); - } - - /** - * @return string - */ - private function wildcardDomainsCacheKey() - { - return '/WildCard/DomainCache/'.\md5(APP_VERSION.APP_PRIVATE_DATA_NAME).'/'; - } - - /** - * @return string - */ - private function getWildcardDomainsLine() - { - if ($this->oCacher) - { - $sResult = $this->oCacher->Get($this->wildcardDomainsCacheKey()); - if (0 < \strlen($sResult)) - { - return $sResult; - } - } - - $sResult = ''; - $aNames = array(); - - $aList = \glob($this->sDomainPath.'/*.ini'); - foreach ($aList as $sFile) - { - $sName = \substr(\basename($sFile), 0, -4); - if ('default' === $sName || false !== \strpos($sName, '_wildcard_')) - { - $aNames[] = $this->codeFileName($sName, true); - } - } - - if (0 < \count($aNames)) - { - \rsort($aNames, SORT_STRING); - $sResult = \implode(' ', $aNames); - } - - if ($this->oCacher) - { - $this->oCacher->Set($this->wildcardDomainsCacheKey(), $sResult); - } - - return $sResult; - } - - /** - * @param string $sName - * @param bool $bFindWithWildCard = false - * @param bool $bCheckDisabled = true - * @param bool $bCheckAliases = true - * - * @return \RainLoop\Model\Domain|null - */ - public function Load($sName, $bFindWithWildCard = false, $bCheckDisabled = true, $bCheckAliases = true) - { - $mResult = null; - - $sDisabled = ''; - $sFoundedValue = ''; - - $sRealFileName = $this->codeFileName($sName); - - if (\file_exists($this->sDomainPath.'/disabled')) - { - $sDisabled = @\file_get_contents($this->sDomainPath.'/disabled'); - } - - if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.ini') && - (!$bCheckDisabled || 0 === \strlen($sDisabled) || false === \strpos(','.$sDisabled.',', ','.\MailSo\Base\Utils::IdnToAscii($sName, true).','))) - { - $aDomain = \RainLoop\Utils::CustomParseIniFile($this->sDomainPath.'/'.$sRealFileName.'.ini'); -// if ($bCheckAliases && !empty($aDomain['alias'])) -// { -// $oDomain = $this->Load($aDomain['alias'], false, false, false); -// if ($oDomain && $oDomain instanceof \RainLoop\Model\Domain) -// { -// $oDomain->SetAliasName($sName); -// } -// -// return $oDomain; -// } - - // fix misspellings (#119) - if (\is_array($aDomain)) - { - if (isset($aDomain['smpt_host'])) - { - $aDomain['smtp_host'] = $aDomain['smpt_host']; - } - - if (isset($aDomain['smpt_port'])) - { - $aDomain['smtp_port'] = $aDomain['smpt_port']; - } - - if (isset($aDomain['smpt_secure'])) - { - $aDomain['smtp_secure'] = $aDomain['smpt_secure']; - } - - if (isset($aDomain['smpt_auth'])) - { - $aDomain['smtp_auth'] = $aDomain['smpt_auth']; - } - } - //--- - - $mResult = \RainLoop\Model\Domain::NewInstanceFromDomainConfigArray($sName, $aDomain); - } - else if ($bCheckAliases && \file_exists($this->sDomainPath.'/'.$sRealFileName.'.alias') && - (!$bCheckDisabled || 0 === \strlen($sDisabled) || false === \strpos(','.$sDisabled.',', ','.\MailSo\Base\Utils::IdnToAscii($sName, true).','))) - { - $sAlias = \trim(\file_get_contents($this->sDomainPath.'/'.$sRealFileName.'.alias')); - if (!empty($sAlias)) - { - $oDomain = $this->Load($sAlias, false, false, false); - if ($oDomain && $oDomain instanceof \RainLoop\Model\Domain) - { - $oDomain->SetAliasName($sName); - } - - return $oDomain; - } - } - else if ($bFindWithWildCard) - { - $sNames = $this->getWildcardDomainsLine(); - if (0 < \strlen($sNames)) - { - if (\RainLoop\Plugins\Helper::ValidateWildcardValues( - \MailSo\Base\Utils::IdnToUtf8($sName, true), $sNames, $sFoundedValue) && 0 < \strlen($sFoundedValue)) - { - if (!$bCheckDisabled || 0 === \strlen($sDisabled) || false === \strpos(','.$sDisabled.',', ','.$sFoundedValue.',')) - { - $mResult = $this->Load($sFoundedValue, false); - } - } - } - } - - return $mResult; - } - - /** - * @param \RainLoop\Model\Domain $oDomain - * - * @return bool - */ - public function Save(\RainLoop\Model\Domain $oDomain) - { - $sRealFileName = $this->codeFileName($oDomain->Name()); - - if ($this->oCacher) - { - $this->oCacher->Delete($this->wildcardDomainsCacheKey()); - } - - $mResult = \file_put_contents($this->sDomainPath.'/'.$sRealFileName.'.ini', $oDomain->ToIniString()); - return \is_int($mResult) && 0 < $mResult; - } - - /** - * @param string $sName - * @param string $sAlias - * - * @return bool - */ - public function SaveAlias($sName, $sAlias) - { - $sRealFileName = $this->codeFileName($sName); - - if ($this->oCacher) - { - $this->oCacher->Delete($this->wildcardDomainsCacheKey()); - } - - $mResult = \file_put_contents($this->sDomainPath.'/'.$sRealFileName.'.alias', $sAlias); - return \is_int($mResult) && 0 < $mResult; - } - - /** - * @param string $sName - * @param bool $bDisable - * - * @return bool - */ - public function Disable($sName, $bDisable) - { - $sName = \MailSo\Base\Utils::IdnToAscii($sName, true); - - $sFile = ''; - if (\file_exists($this->sDomainPath.'/disabled')) - { - $sFile = @\file_get_contents($this->sDomainPath.'/disabled'); - } - - $aResult = array(); - $aNames = \explode(',', $sFile); - if ($bDisable) - { - \array_push($aNames, $sName); - $aResult = $aNames; - } - else - { - foreach ($aNames as $sItem) - { - if ($sName !== $sItem) - { - $aResult[] = $sItem; - } - } - } - - $aResult = \array_unique($aResult); - return false !== \file_put_contents($this->sDomainPath.'/disabled', \trim(\implode(',', $aResult), ', ')); - } - - /** - * @param string $sName - * - * @return bool - */ - public function Delete($sName) - { - $bResult = true; - $sRealFileName = $this->codeFileName($sName); - - if (0 < \strlen($sName)) - { - if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.ini')) - { - $bResult = \unlink($this->sDomainPath.'/'.$sRealFileName.'.ini'); - } - else if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.alias')) - { - $bResult = \unlink($this->sDomainPath.'/'.$sRealFileName.'.alias'); - } - } - - if ($bResult) - { - $this->Disable($sName, false); - } - - if ($this->oCacher) - { - $this->oCacher->Delete($this->wildcardDomainsCacheKey()); - } - - return $bResult; - } - - /** - * @param int $iOffset = 0 - * @param int $iLimit = 20 - * @param int $sSearch = '' - * @param bool $bIncludeAliases = true - * - * @return array - */ - public function GetList($iOffset = 0, $iLimit = 20, $sSearch = '', $bIncludeAliases = true) - { - $aResult = array(); - $aWildCards = array(); - $aAliases = array(); - - $aList = \glob($this->sDomainPath.'/*.{ini,alias}', GLOB_BRACE); - - foreach ($aList as $sFile) - { - $sName = \basename($sFile); - $bAlias = '.alias' === \substr($sName, -6); - - $sName = \preg_replace('/\.(ini|alias)$/', '', $sName); - $sName = $this->codeFileName($sName, true); - - if ($bAlias) - { - if ($bIncludeAliases) - { - $aAliases[] = $sName; - } - } - else if (false !== \strpos($sName, '*')) - { - $aWildCards[] = $sName; - } - else - { - $aResult[] = $sName; - } - } - - \sort($aResult, SORT_STRING); - \sort($aAliases, SORT_STRING); - \rsort($aWildCards, SORT_STRING); - - $aResult = \array_merge($aResult, $aAliases, $aWildCards); - - $iOffset = (0 > $iOffset) ? 0 : $iOffset; - $iLimit = (0 > $iLimit) ? 0 : ((999 < $iLimit) ? 999 : $iLimit); - - $aResult = \array_slice($aResult, $iOffset, $iLimit); - - $aDisabledNames = array(); - if (0 < \count($aResult) && \file_exists($this->sDomainPath.'/disabled')) - { - $sDisabled = @\file_get_contents($this->sDomainPath.'/disabled'); - if (false !== $sDisabled && 0 < strlen($sDisabled)) - { - $aDisabledNames = \explode(',', $sDisabled); - $aDisabledNames = \array_unique($aDisabledNames); - foreach ($aDisabledNames as $iIndex => $sValue) - { - $aDisabledNames[$iIndex] = \MailSo\Base\Utils::IdnToUtf8($sValue, true); - } - } - } - - $aReturn = array(); - foreach ($aResult as $sName) - { - $aReturn[$sName] = array( - !\in_array($sName, $aDisabledNames), - \in_array($sName, $aAliases) - ); - } - - return $aReturn; - } - - /** - * @param string $sSearch = '' - * @param bool $bIncludeAliases = true - * - * @return int - */ - public function Count($sSearch = '', $bIncludeAliases = true) - { - return \count($this->GetList(0, 999, $sSearch, $bIncludeAliases)); - } +sDomainPath = \rtrim(\trim($sDomainPath), '\\/'); + $this->oCacher = $oCacher; + } + + /** + * @param string $sName + * @param bool $bBack = false + * + * @return string + */ + public function codeFileName($sName, $bBack = false) + { + if ($bBack && 'default' === $sName) + { + return '*'; + } + else if (!$bBack && '*' === $sName) + { + return 'default'; + } + + if ($bBack) + { + $sName = \MailSo\Base\Utils::IdnToUtf8($sName, true); + } + else + { + $sName = \MailSo\Base\Utils::IdnToAscii($sName, true); + } + + return $bBack ? \str_replace('_wildcard_', '*', $sName) : \str_replace('*', '_wildcard_', $sName); + } + + /** + * @return string + */ + private function wildcardDomainsCacheKey() + { + return '/WildCard/DomainCache/'.\md5(APP_VERSION.APP_PRIVATE_DATA_NAME).'/'; + } + + /** + * @return string + */ + private function getWildcardDomainsLine() + { + if ($this->oCacher) + { + $sResult = $this->oCacher->Get($this->wildcardDomainsCacheKey()); + if (0 < \strlen($sResult)) + { + return $sResult; + } + } + + $sResult = ''; + $aNames = array(); + + $aList = \glob($this->sDomainPath.'/*.ini'); + foreach ($aList as $sFile) + { + $sName = \substr(\basename($sFile), 0, -4); + if ('default' === $sName || false !== \strpos($sName, '_wildcard_')) + { + $aNames[] = $this->codeFileName($sName, true); + } + } + + if (0 < \count($aNames)) + { + \rsort($aNames, SORT_STRING); + $sResult = \implode(' ', $aNames); + } + + if ($this->oCacher) + { + $this->oCacher->Set($this->wildcardDomainsCacheKey(), $sResult); + } + + return $sResult; + } + + /** + * @param string $sName + * @param bool $bFindWithWildCard = false + * @param bool $bCheckDisabled = true + * @param bool $bCheckAliases = true + * + * @return \RainLoop\Model\Domain|null + */ + public function Load($sName, $bFindWithWildCard = false, $bCheckDisabled = true, $bCheckAliases = true) + { + $mResult = null; + + $sDisabled = ''; + $sFoundedValue = ''; + + $sRealFileName = $this->codeFileName($sName); + + if (\file_exists($this->sDomainPath.'/disabled')) + { + $sDisabled = @\file_get_contents($this->sDomainPath.'/disabled'); + } + + if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.ini') && + (!$bCheckDisabled || 0 === \strlen($sDisabled) || false === \strpos(','.$sDisabled.',', ','.\MailSo\Base\Utils::IdnToAscii($sName, true).','))) + { + $aDomain = \RainLoop\Utils::CustomParseIniFile($this->sDomainPath.'/'.$sRealFileName.'.ini'); +// if ($bCheckAliases && !empty($aDomain['alias'])) +// { +// $oDomain = $this->Load($aDomain['alias'], false, false, false); +// if ($oDomain && $oDomain instanceof \RainLoop\Model\Domain) +// { +// $oDomain->SetAliasName($sName); +// } +// +// return $oDomain; +// } + + // fix misspellings (#119) + if (\is_array($aDomain)) + { + if (isset($aDomain['smpt_host'])) + { + $aDomain['smtp_host'] = $aDomain['smpt_host']; + } + + if (isset($aDomain['smpt_port'])) + { + $aDomain['smtp_port'] = $aDomain['smpt_port']; + } + + if (isset($aDomain['smpt_secure'])) + { + $aDomain['smtp_secure'] = $aDomain['smpt_secure']; + } + + if (isset($aDomain['smpt_auth'])) + { + $aDomain['smtp_auth'] = $aDomain['smpt_auth']; + } + } + //--- + + $mResult = \RainLoop\Model\Domain::NewInstanceFromDomainConfigArray($sName, $aDomain); + } + else if ($bCheckAliases && \file_exists($this->sDomainPath.'/'.$sRealFileName.'.alias') && + (!$bCheckDisabled || 0 === \strlen($sDisabled) || false === \strpos(','.$sDisabled.',', ','.\MailSo\Base\Utils::IdnToAscii($sName, true).','))) + { + $sAlias = \trim(\file_get_contents($this->sDomainPath.'/'.$sRealFileName.'.alias')); + if (!empty($sAlias)) + { + $oDomain = $this->Load($sAlias, false, false, false); + if ($oDomain && $oDomain instanceof \RainLoop\Model\Domain) + { + $oDomain->SetAliasName($sName); + } + + return $oDomain; + } + } + else if ($bFindWithWildCard) + { + $sNames = $this->getWildcardDomainsLine(); + if (0 < \strlen($sNames)) + { + if (\RainLoop\Plugins\Helper::ValidateWildcardValues( + \MailSo\Base\Utils::IdnToUtf8($sName, true), $sNames, $sFoundedValue) && 0 < \strlen($sFoundedValue)) + { + if (!$bCheckDisabled || 0 === \strlen($sDisabled) || false === \strpos(','.$sDisabled.',', ','.$sFoundedValue.',')) + { + $mResult = $this->Load($sFoundedValue, false); + } + } + } + } + + return $mResult; + } + + /** + * @param \RainLoop\Model\Domain $oDomain + * + * @return bool + */ + public function Save(\RainLoop\Model\Domain $oDomain) + { + $sRealFileName = $this->codeFileName($oDomain->Name()); + + if ($this->oCacher) + { + $this->oCacher->Delete($this->wildcardDomainsCacheKey()); + } + + $mResult = \file_put_contents($this->sDomainPath.'/'.$sRealFileName.'.ini', $oDomain->ToIniString()); + return \is_int($mResult) && 0 < $mResult; + } + + /** + * @param string $sName + * @param string $sAlias + * + * @return bool + */ + public function SaveAlias($sName, $sAlias) + { + $sRealFileName = $this->codeFileName($sName); + + if ($this->oCacher) + { + $this->oCacher->Delete($this->wildcardDomainsCacheKey()); + } + + $mResult = \file_put_contents($this->sDomainPath.'/'.$sRealFileName.'.alias', $sAlias); + return \is_int($mResult) && 0 < $mResult; + } + + /** + * @param string $sName + * @param bool $bDisable + * + * @return bool + */ + public function Disable($sName, $bDisable) + { + $sName = \MailSo\Base\Utils::IdnToAscii($sName, true); + + $sFile = ''; + if (\file_exists($this->sDomainPath.'/disabled')) + { + $sFile = @\file_get_contents($this->sDomainPath.'/disabled'); + } + + $aResult = array(); + $aNames = \explode(',', $sFile); + if ($bDisable) + { + \array_push($aNames, $sName); + $aResult = $aNames; + } + else + { + foreach ($aNames as $sItem) + { + if ($sName !== $sItem) + { + $aResult[] = $sItem; + } + } + } + + $aResult = \array_unique($aResult); + return false !== \file_put_contents($this->sDomainPath.'/disabled', \trim(\implode(',', $aResult), ', ')); + } + + /** + * @param string $sName + * + * @return bool + */ + public function Delete($sName) + { + $bResult = true; + $sRealFileName = $this->codeFileName($sName); + + if (0 < \strlen($sName)) + { + if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.ini')) + { + $bResult = \unlink($this->sDomainPath.'/'.$sRealFileName.'.ini'); + } + else if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.alias')) + { + $bResult = \unlink($this->sDomainPath.'/'.$sRealFileName.'.alias'); + } + } + + if ($bResult) + { + $this->Disable($sName, false); + } + + if ($this->oCacher) + { + $this->oCacher->Delete($this->wildcardDomainsCacheKey()); + } + + return $bResult; + } + + /** + * @param int $iOffset = 0 + * @param int $iLimit = 20 + * @param int $sSearch = '' + * @param bool $bIncludeAliases = true + * + * @return array + */ + public function GetList($iOffset = 0, $iLimit = 20, $sSearch = '', $bIncludeAliases = true) + { + $aResult = array(); + $aWildCards = array(); + $aAliases = array(); + +// $aList = \glob($this->sDomainPath.'/*.{ini,alias}', GLOB_BRACE); + $aList = @\array_diff(\scandir($this->sDomainPath), array('.', '..')); + if (\is_array($aList)) + { + foreach ($aList as $sFile) + { + $sName = $sFile; + if ('.ini' === \substr($sName, -4) || '.alias' === \substr($sName, -6)) + { + $bAlias = '.alias' === \substr($sName, -6); + + $sName = \preg_replace('/\.(ini|alias)$/', '', $sName); + $sName = $this->codeFileName($sName, true); + + if ($bAlias) + { + if ($bIncludeAliases) + { + $aAliases[] = $sName; + } + } + else if (false !== \strpos($sName, '*')) + { + $aWildCards[] = $sName; + } + else + { + $aResult[] = $sName; + } + } + } + } + + \sort($aResult, SORT_STRING); + \sort($aAliases, SORT_STRING); + \rsort($aWildCards, SORT_STRING); + + $aResult = \array_merge($aResult, $aAliases, $aWildCards); + + $iOffset = (0 > $iOffset) ? 0 : $iOffset; + $iLimit = (0 > $iLimit) ? 0 : ((999 < $iLimit) ? 999 : $iLimit); + + $aResult = \array_slice($aResult, $iOffset, $iLimit); + + $aDisabledNames = array(); + if (0 < \count($aResult) && \file_exists($this->sDomainPath.'/disabled')) + { + $sDisabled = @\file_get_contents($this->sDomainPath.'/disabled'); + if (false !== $sDisabled && 0 < strlen($sDisabled)) + { + $aDisabledNames = \explode(',', $sDisabled); + $aDisabledNames = \array_unique($aDisabledNames); + foreach ($aDisabledNames as $iIndex => $sValue) + { + $aDisabledNames[$iIndex] = \MailSo\Base\Utils::IdnToUtf8($sValue, true); + } + } + } + + $aReturn = array(); + foreach ($aResult as $sName) + { + $aReturn[$sName] = array( + !\in_array($sName, $aDisabledNames), + \in_array($sName, $aAliases) + ); + } + + return $aReturn; + } + + /** + * @param string $sSearch = '' + * @param bool $bIncludeAliases = true + * + * @return int + */ + public function Count($sSearch = '', $bIncludeAliases = true) + { + return \count($this->GetList(0, 999, $sSearch, $bIncludeAliases)); + } } \ No newline at end of file diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Prem.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Prem.php new file mode 100644 index 000000000..5472079aa --- /dev/null +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Prem.php @@ -0,0 +1,392 @@ +oConfig = $oConfig; + $this->oLogger = $oLogger; + $this->oCacher = $oCacher; + } + + /** + * @return bool + */ + public function Type() + { + static $bResult = null; + if (null === $bResult) + { + $bResult = $this->Parser($this->Fetcher(false, true)); + } + + return $bResult; + } + + /** + * @return bool + */ + public function IsActive() + { + return true; + } + + /** + * @param string $sInput + * @param int $iExpired = 0 + * + * @return bool + */ + public function Parser($sInput, &$iExpired = 0) + { + $aMatch = array(); + if (\preg_match('/^EXPIRED:([\d]+)$/', $sInput, $aMatch)) + { + $iExpired = (int) $aMatch[1]; + return \time() < $iExpired; + } + + return false; + } + + /** + * @param array $aAppData + */ + public function PopulateAppData(&$aAppData) + { + if (\is_array($aAppData)) + { + $aAppData['Community'] = false; + + $oConfig = $this->oConfig; + if ($oConfig && $this->Type()) + { + $aAppData['PremType'] = true; + $aAppData['LoginLogo'] = $oConfig->Get('branding', 'login_logo', ''); + $aAppData['LoginBackground'] = $oConfig->Get('branding', 'login_background', ''); + $aAppData['LoginCss'] = $oConfig->Get('branding', 'login_css', ''); + $aAppData['LoginDescription'] = $oConfig->Get('branding', 'login_desc', ''); + $aAppData['LoginPowered'] = !!$oConfig->Get('branding', 'login_powered', true); + $aAppData['UserLogo'] = $oConfig->Get('branding', 'user_logo', ''); + $aAppData['UserLogoTitle'] = $oConfig->Get('branding', 'user_logo_title', ''); + $aAppData['UserLogoMessage'] = $oConfig->Get('branding', 'user_logo_message', ''); + $aAppData['UserIframeMessage'] = $oConfig->Get('branding', 'user_iframe_message', ''); + $aAppData['UserCss'] = $oConfig->Get('branding', 'user_css', ''); + $aAppData['WelcomePageUrl'] = $oConfig->Get('branding', 'welcome_page_url', ''); + $aAppData['WelcomePageDisplay'] = \strtolower($oConfig->Get('branding', 'welcome_page_display', 'none')); + } + } + } + + public function PremSection(&$oActions, &$oConfig) + { + if ($oActions && $oActions->HasOneOfActionParams(array( + 'LoginLogo', 'LoginBackground', 'LoginDescription', 'LoginCss', 'LoginPowered', + 'UserLogo', 'UserLogoTitle', 'UserLogoMessage', 'UserIframeMessage', 'UserCss', + 'WelcomePageUrl', 'WelcomePageDisplay' + )) && $this->Type()) + { + $oActions->setConfigFromParams($oConfig, 'LoginLogo', 'branding', 'login_logo', 'string'); + $oActions->setConfigFromParams($oConfig, 'LoginBackground', 'branding', 'login_background', 'string'); + $oActions->setConfigFromParams($oConfig, 'LoginDescription', 'branding', 'login_desc', 'string'); + $oActions->setConfigFromParams($oConfig, 'LoginCss', 'branding', 'login_css', 'string'); + $oActions->setConfigFromParams($oConfig, 'LoginPowered', 'branding', 'login_powered', 'bool'); + + $oActions->setConfigFromParams($oConfig, 'UserLogo', 'branding', 'user_logo', 'string'); + $oActions->setConfigFromParams($oConfig, 'UserLogoTitle', 'branding', 'user_logo_title', 'string'); + $oActions->setConfigFromParams($oConfig, 'UserLogoMessage', 'branding', 'user_logo_message', 'string'); + $oActions->setConfigFromParams($oConfig, 'UserIframeMessage', 'branding', 'user_iframe_message', 'string'); + $oActions->setConfigFromParams($oConfig, 'UserCss', 'branding', 'user_css', 'string'); + + $oActions->setConfigFromParams($oConfig, 'WelcomePageUrl', 'branding', 'welcome_page_url', 'string'); + $oActions->setConfigFromParams($oConfig, 'WelcomePageDisplay', 'branding', 'welcome_page_display', 'string'); + } + } + + /** + * @return string + */ + public function Activate($sDomain, $sKey, &$iCode) + { + $iCode = 0; + $sContentType = ''; + + $oHttp = \MailSo\Base\Http::SingletonInstance(); + + $sResult = $oHttp->GetUrlAsString(APP_API_PATH.'activate/'.\urlencode($sDomain).'/'.\urlencode($sKey), + 'RainLoop/'.APP_VERSION, $sContentType, $iCode, $this->oLogger, 10, + $this->oConfig->Get('labs', 'curl_proxy', ''), $this->oConfig->Get('labs', 'curl_proxy_auth', ''), + array(), false + ); + + if (200 !== $iCode) + { + $sResult = ''; + } + + return $sResult; + } + + /** + * @return string + */ + public function Fetcher($sForce = false, $bLongCache = false, $iFastCacheTimeInMin = 10, $iLongCacheTimeInDays = 3) + { + $sDomain = \trim(APP_SITE); + + $oConfig = $this->oConfig; + $oLogger = $this->oLogger; + $oCacher = $this->oCacher; + + $oHttp = \MailSo\Base\Http::SingletonInstance(); + + if (0 === \strlen($sDomain) || $oHttp->CheckLocalhost($sDomain) || !$oCacher || !$oConfig || !$oCacher->Verify(true)) + { + return 'NO'; + } + + $sDomainKeyValue = \RainLoop\KeyPathHelper::LicensingDomainKeyValue($sDomain); + $sDomainLongKeyValue = \RainLoop\KeyPathHelper::LicensingDomainKeyOtherValue($sDomain); + + $sValue = ''; + if (!$sForce) + { + if ($bLongCache) + { + $bLock = $oCacher->GetLock($sDomainLongKeyValue); + $iTime = $bLock ? 0 : $oCacher->GetTimer($sDomainLongKeyValue); + + if ($bLock || (0 < $iTime && \time() < $iTime + (60 * 60 * 24) * $iLongCacheTimeInDays)) + { + $sValue = $oCacher->Get($sDomainLongKeyValue); + } + } + else + { + $iTime = $oCacher->GetTimer($sDomainKeyValue); + if (0 < $iTime && \time() < $iTime + 60 * $iFastCacheTimeInMin) + { + $sValue = $oCacher->Get($sDomainKeyValue); + } + } + } + + if (0 === \strlen($sValue)) + { + if ($bLongCache) + { + if (!$oCacher->SetTimer($sDomainLongKeyValue)) + { + return 'NO'; + } + + $oCacher->SetLock($sDomainLongKeyValue); + } + + $iCode = 0; + $sContentType = ''; + + $sValue = $oHttp->GetUrlAsString(APP_API_PATH.'status/'.\urlencode($sDomain), + 'RainLoop/'.APP_VERSION, $sContentType, $iCode, $oLogger, 5, + $oConfig->Get('labs', 'curl_proxy', ''), $oConfig->Get('labs', 'curl_proxy_auth', ''), + array(), false + ); + + if ($oLogger) + { + $oLogger->Write($sValue); + } + + if (404 === $iCode) + { + $sValue = 'NO'; + } + else if (200 !== $iCode) + { + $sValue = ''; + } + + $oCacher->SetTimer($sDomainKeyValue); + + $oCacher->Set($sDomainKeyValue, $sValue); + $oCacher->Set($sDomainLongKeyValue, $sValue); + + if ($bLongCache) + { + $oCacher->RemoveLock($sDomainLongKeyValue); + } + } + + return $sValue; + } + + public function ClearOldVersion() + { + $sVPath = APP_INDEX_ROOT_PATH.'rainloop/v/'; + + if ($this->oLogger) + { + $this->oLogger->Write('Versions GC: Begin'); + } + + $aDirs = @\array_map('basename', @\array_filter(@\glob($sVPath.'*'), 'is_dir')); + + if ($this->oLogger) + { + $this->oLogger->Write('Versions GC: Count:'.(\is_array($aDirs) ? \count($aDirs) : 0)); + } + + if (\is_array($aDirs) && 5 < \count($aDirs)) + { + \uasort($aDirs, 'version_compare'); + + foreach ($aDirs as $sName) + { + if (APP_DEV_VERSION !== $sName && APP_VERSION !== $sName) + { + if ($this->oLogger) + { + $this->oLogger->Write('Versions GC: Begin to remove "'.$sVPath.$sName.'" version'); + } + + if (@\unlink($sVPath.$sName.'/index.php')) + { + @\MailSo\Base\Utils::RecRmDir($sVPath.$sName); + } + else + { + if ($this->oLogger) + { + $this->oLogger->Write('Versions GC (Error): index file cant be removed from"'.$sVPath.$sName.'"', + \MailSo\Log\Enumerations\Type::ERROR); + } + } + + if ($this->oLogger) + { + $this->oLogger->Write('Versions GC: End to remove "'.$sVPath.$sName.'" version'); + } + + break; + } + } + } + + if ($this->oLogger) + { + $this->oLogger->Write('Versions GC: End'); + } + } + + public function UpdateCore($oActions, $sFile) + { + $bResult = false; + + $sNewVersion = ''; + $sTmp = $oActions->downloadRemotePackageByUrl($sFile); + if (!empty($sTmp)) + { + include_once APP_VERSION_ROOT_PATH.'app/libraries/pclzip/pclzip.lib.php'; + + $oArchive = new \PclZip($sTmp); + $sTmpFolder = APP_PRIVATE_DATA.\md5($sTmp); + + \mkdir($sTmpFolder); + if (\is_dir($sTmpFolder)) + { + $bResult = 0 !== $oArchive->extract(PCLZIP_OPT_PATH, $sTmpFolder); + if (!$bResult) + { + if ($this->oLogger) + { + $this->oLogger->Write('Cannot extract package files: '.$oArchive->errorInfo(), \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER'); + } + } + + if ($bResult && \file_exists($sTmpFolder.'/index.php') && + \is_writable(APP_INDEX_ROOT_PATH.'rainloop/') && + \is_writable(APP_INDEX_ROOT_PATH.'index.php') && + \is_dir($sTmpFolder.'/rainloop/')) + { + $aMatch = array(); + $sIndexFile = \file_get_contents($sTmpFolder.'/index.php'); + if (\preg_match('/\'APP_VERSION\', \'([^\']+)\'/', $sIndexFile, $aMatch) && !empty($aMatch[1])) + { + $sNewVersion = \trim($aMatch[1]); + } + + if (empty($sNewVersion)) + { + if ($this->oLogger) + { + $this->oLogger->Write('Unknown version', \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER'); + } + } + else if (!\is_dir(APP_INDEX_ROOT_PATH.'rainloop/v/'.$sNewVersion)) + { + \MailSo\Base\Utils::CopyDir($sTmpFolder.'/rainloop/', APP_INDEX_ROOT_PATH.'rainloop/'); + + if (\is_dir(APP_INDEX_ROOT_PATH.'rainloop/v/'.$sNewVersion) && + \is_file(APP_INDEX_ROOT_PATH.'rainloop/v/'.$sNewVersion.'/index.php')) + { + $bResult = \copy($sTmpFolder.'/index.php', APP_INDEX_ROOT_PATH.'index.php'); + + if ($bResult) + { + if (\MailSo\Base\Utils::FunctionExistsAndEnabled('opcache_invalidate')) + { + @\opcache_invalidate(APP_INDEX_ROOT_PATH.'index.php', true); + } + + if (\MailSo\Base\Utils::FunctionExistsAndEnabled('apc_delete_file')) + { + @\apc_delete_file(APP_INDEX_ROOT_PATH.'index.php'); + } + } + } + else + { + if ($this->oLogger) + { + $this->oLogger->Write('Cannot copy new package files', \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER'); + $this->oLogger->Write($sTmpFolder.'/rainloop/ -> '.APP_INDEX_ROOT_PATH.'rainloop/', \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER'); + } + } + } + else if (!empty($sNewVersion)) + { + if ($this->oLogger) + { + $this->oLogger->Write('"'.$sNewVersion.'" version already installed', \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER'); + } + } + } + else if ($bResult) + { + if ($this->oLogger) + { + $this->oLogger->Write('Cannot validate package files', \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER'); + } + } + + \MailSo\Base\Utils::RecRmDir($sTmpFolder); + } + else + { + if ($this->oLogger) + { + $this->oLogger->Write('Cannot create tmp folder: '.$sTmpFolder, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER'); + } + } + + @\unlink($sTmp); + } + + return $bResult; + } +} diff --git a/rainloop/v/0.0.0/app/templates/Themes/template.less b/rainloop/v/0.0.0/app/templates/Themes/template.less index 2865cd1a1..71be5f207 100644 --- a/rainloop/v/0.0.0/app/templates/Themes/template.less +++ b/rainloop/v/0.0.0/app/templates/Themes/template.less @@ -1,252 +1,342 @@ - -// mixins +++ -.thm-linear-gradient-mixin(@start, @end) when (iscolor(@start)) and (iscolor(@end)) { - background-color: mix(@start, @end, 60%) !important; - background-image: -moz-linear-gradient(top, @start, @end) !important; // FF 3.6+ - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@start), to(@end)) !important; // Safari 4+, Chrome 2+ - background-image: -webkit-linear-gradient(top, @start, @end) !important; // Safari 5.1+, Chrome 10+ - background-image: -o-linear-gradient(top, @start, @end !important); // Opera 11.10 - background-image: linear-gradient(to bottom, @start, @end) !important; // Standard, IE10 - background-repeat: repeat-x !important; - filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@start),argb(@end))) !important; // IE9 and down -} - -.thm-border-radius(@radius) when (ispixel(@radius)) { - -webkit-border-radius: @radius !important; - -moz-border-radius: @radius !important; - border-radius: @radius !important; -} - -.thm-box-shadow(@shadow) { - -webkit-box-shadow: @shadow !important; - -moz-box-shadow: @shadow !important; - box-shadow: @shadow !important; -} -.thm-body-background-image(@value) when (isstring(@value)) { - background-image: url("@{base}@{value}") !important; -} -.thm-body-background-image(@value) when not (isstring(@value)) { - background-image: @value !important; -} -.thm-rgba-background-color(@simple, @rgba) when (@rgba = false) { - background-color: @simple !important; -} -.thm-rgba-background-color(@simple, @rgba) when not (@rgba = false) { - background-color: @simple !important; - background-color: @rgba !important; -} -// --- mixins - -.thm-body { - color: @main-color; - background-color: @main-background-color; - background-size: @main-background-size; - .thm-body-background-image(@main-background-image); -} - -.thm-loading { - color: @loading-color !important; - text-shadow: @loading-text-shadow !important; - - .e-spinner .e-bounce { - background-color: @loading-color !important; - } -} - -.thm-login-desc .desc { - color: @loading-color !important; - text-shadow: @loading-text-shadow !important; -} - -.thm-login { - border: @login-border !important; - .thm-rgba-background-color(@login-background-color, @login-rgba-background-color); - .thm-linear-gradient-mixin(@login-gradient-start, @login-gradient-end); - .thm-border-radius(@login-border-radius); - .thm-box-shadow(@login-box-shadow); - - &.submitting-pane.submitting { - &:before{ - background: @spinner-background; - .thm-border-radius(@login-border-radius); - } - &:after{ - border-top-color: @spinner-color; - } - } -} - -.thm-login-text { - color: @login-color !important; - - .legend, .e-checkbox-icon, .g-ui-link, .social-button, .language-button { - color: @login-color !important; - } -} - -.thm-powered, .thm-mobile-switcher { - color: @powered-color; - a { - color: @powered-color; - &:hover { - color: lighten(@powered-color, 20%); - } - } -} - -.thm-languages { - color: @languages-color; - .flag-name { - color: @languages-color; - border-color: @languages-color; - } -} - -.g-ui-menu { - color: @dropdown-menu-color !important; - background-color: @dropdown-menu-background-color !important; -} - -.g-ui-menu .e-item > .e-link { - color: @dropdown-menu-color !important; - background-color: @dropdown-menu-background-color !important; - - > i { - color: @dropdown-menu-color !important; - } -} - -.g-ui-menu .e-item.selected > .e-link { - background-color: @dropdown-menu-selected-background-color !important; -} - -.g-ui-menu .e-item > .e-link:hover, .g-ui-menu .e-item > .e-link:focus { - color: @dropdown-menu-hover-color !important; - background-color: @dropdown-menu-hover-background-color !important; - - > i { - color: @dropdown-menu-hover-color !important; - } -} - -.g-ui-menu .e-item.disabled > .e-link, .g-ui-menu .e-item.disabled > .e-link:hover { - color: @dropdown-menu-disabled-color !important; - background-color: @dropdown-menu-background-color !important; - - > i { - color: @dropdown-menu-disabled-color !important; - } -} - -.thm-message-list-top-toolbar, .thm-message-list-bottom-toolbar { - .thm-rgba-background-color(@message-list-toolbar-background-color, @message-list-toolbar-rgba-background-color); - .thm-linear-gradient-mixin(@message-list-toolbar-gradient-start, @message-list-toolbar-gradient-end); -} - -.thm-folders .e-link { - - color: @folders-disabled-color !important; - - &.selectable { - color: @folders-color !important; - } - - &.selectable:hover { - color: @folders-hover-color !important; - .thm-rgba-background-color(@folders-hover-background-color, @folders-hover-rgba-background-color); - } - - &.selectable.selected { - color: @folders-selected-color !important; - .thm-rgba-background-color(@folders-selected-background-color, @folders-selected-rgba-background-color); - } - - &.focused { - color: @folders-focused-color !important; - .thm-rgba-background-color(@folders-focused-background-color, @folders-focused-rgba-background-color); - } - - &.selectable.droppableHover { - color: @folders-drop-color !important; - .thm-rgba-background-color(@folders-drop-background-color, @folders-drop-rgba-background-color); - } -} - -.thm-settings-menu .e-item { - - .e-link { - color: @settings-menu-disabled-color !important; - } - - &.selectable .e-link { - color: @settings-menu-color !important; - } - - &.selectable:hover .e-link { - .thm-rgba-background-color(@settings-menu-hover-background-color, @settings-menu-hover-rgba-background-color); - color: @settings-menu-hover-color !important; - } - - &.selectable.selected .e-link { - .thm-rgba-background-color(@settings-menu-selected-background-color, @settings-menu-selected-rgba-background-color); - color: @settings-menu-selected-color !important; - } -} - -.thm-message-view-background-color { - .thm-rgba-background-color(@message-background-color, @message-rgba-background-color); -} - -#rl-app{ - display: block; -} - -html.no-css { - - margin: 0; - padding: 0; - font-family: Arial, Verdana, Geneva, sans-serif; - - body { - margin: 0; - padding: 0; - } - - #rl-loading, #rl-loading-error { - position: absolute; - font-size: 30px; - line-height: 130%; - top: 50%; - width: 100%; - height: 65px; - margin: 0; - margin-top: -60px; - background-color: transparent; - text-align: center; - color: #333; - } - - .progressjs-container { - display: none; - } - - .thm-body { - color: #333; - background-color: #aaa; - background-image: none; - } - - .thm-loading { - color: #333 !important; - text-shadow: none !important; - - .e-spinner .e-bounce { - display: none !important; - } - } - - .thm-login-desc .desc { - color: #333 !important; - text-shadow: none !important; - } -} \ No newline at end of file + +// mixins +++ +.thm-linear-gradient-mixin(@start, @end) when (iscolor(@start)) and (iscolor(@end)) { + background-color: mix(@start, @end, 60%) !important; + background-image: -moz-linear-gradient(top, @start, @end) !important; // FF 3.6+ + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@start), to(@end)) !important; // Safari 4+, Chrome 2+ + background-image: -webkit-linear-gradient(top, @start, @end) !important; // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(top, @start, @end !important); // Opera 11.10 + background-image: linear-gradient(to bottom, @start, @end) !important; // Standard, IE10 + background-repeat: repeat-x !important; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@start),argb(@end))) !important; // IE9 and down +} + +.thm-border-radius(@radius) when (ispixel(@radius)) { + -webkit-border-radius: @radius !important; + -moz-border-radius: @radius !important; + border-radius: @radius !important; +} + +.thm-box-shadow(@shadow) { + -webkit-box-shadow: @shadow !important; + -moz-box-shadow: @shadow !important; + box-shadow: @shadow !important; +} +.thm-body-background-image(@value) when (isstring(@value)) { + background-image: url("@{base}@{value}") !important; +} +.thm-body-background-image(@value) when not (isstring(@value)) { + background-image: @value !important; +} +.thm-rgba-background-color(@simple, @rgba) when (@rgba = false) { + background-color: @simple !important; +} +.thm-rgba-background-color(@simple, @rgba) when not (@rgba = false) { + background-color: @simple !important; + background-color: @rgba !important; +} +// --- mixins + +.thm-body { + color: @main-color; + background-color: @main-background-color; + background-size: @main-background-size; + .thm-body-background-image(@main-background-image); +} + +.thm-loading { + color: @loading-color !important; + text-shadow: @loading-text-shadow !important; + + .e-spinner .e-bounce { + background-color: @loading-color !important; + } +} + +.thm-login-desc .desc { + color: @loading-color !important; + text-shadow: @loading-text-shadow !important; +} + +.thm-login { + border: @login-border !important; + .thm-rgba-background-color(@login-background-color, @login-rgba-background-color); + .thm-linear-gradient-mixin(@login-gradient-start, @login-gradient-end); + .thm-border-radius(@login-border-radius); + .thm-box-shadow(@login-box-shadow); + + &.submitting-pane.submitting { + &:before{ + background: @spinner-background; + .thm-border-radius(@login-border-radius); + } + &:after{ + border-top-color: @spinner-color; + } + } +} + +.thm-login-text { + color: @login-color !important; + + .legend, .e-checkbox-icon, .g-ui-link, .social-button, .language-button { + color: @login-color !important; + } +} + +.thm-powered, .thm-mobile-switcher { + color: @powered-color; + a { + color: @powered-color; + &:hover { + color: lighten(@powered-color, 20%); + } + } +} + +.thm-languages { + color: @languages-color; + .flag-name { + color: @languages-color; + border-color: @languages-color; + } +} + +.g-ui-menu { + color: @dropdown-menu-color !important; + background-color: @dropdown-menu-background-color !important; +} + +.g-ui-menu .e-item > .e-link { + color: @dropdown-menu-color !important; + background-color: @dropdown-menu-background-color !important; + + > i { + color: @dropdown-menu-color !important; + } +} + +.g-ui-menu .e-item.selected > .e-link { + background-color: @dropdown-menu-selected-background-color !important; +} + +.g-ui-menu .e-item > .e-link:hover, .g-ui-menu .e-item > .e-link:focus { + color: @dropdown-menu-hover-color !important; + background-color: @dropdown-menu-hover-background-color !important; + + > i { + color: @dropdown-menu-hover-color !important; + } +} + +.g-ui-menu .e-item.disabled > .e-link, .g-ui-menu .e-item.disabled > .e-link:hover { + color: @dropdown-menu-disabled-color !important; + background-color: @dropdown-menu-background-color !important; + + > i { + color: @dropdown-menu-disabled-color !important; + } +} + +.thm-message-list-top-toolbar, .thm-message-list-bottom-toolbar { + .thm-rgba-background-color(@message-list-toolbar-background-color, @message-list-toolbar-rgba-background-color); + .thm-linear-gradient-mixin(@message-list-toolbar-gradient-start, @message-list-toolbar-gradient-end); +} + +.thm-folders .e-link { + + color: @folders-disabled-color !important; + + &.selectable { + color: @folders-color !important; + } + + &.selectable:hover { + color: @folders-hover-color !important; + .thm-rgba-background-color(@folders-hover-background-color, @folders-hover-rgba-background-color); + } + + &.selectable.selected { + color: @folders-selected-color !important; + .thm-rgba-background-color(@folders-selected-background-color, @folders-selected-rgba-background-color); + } + + &.focused { + color: @folders-focused-color !important; + .thm-rgba-background-color(@folders-focused-background-color, @folders-focused-rgba-background-color); + } + + &.selectable.droppableHover { + color: @folders-drop-color !important; + .thm-rgba-background-color(@folders-drop-background-color, @folders-drop-rgba-background-color); + } +} + +.thm-settings-menu .e-item { + + .e-link { + color: @settings-menu-disabled-color !important; + } + + &.selectable .e-link { + color: @settings-menu-color !important; + } + + &.selectable:hover .e-link { + .thm-rgba-background-color(@settings-menu-hover-background-color, @settings-menu-hover-rgba-background-color); + color: @settings-menu-hover-color !important; + } + + &.selectable.selected .e-link { + .thm-rgba-background-color(@settings-menu-selected-background-color, @settings-menu-selected-rgba-background-color); + color: @settings-menu-selected-color !important; + } +} + +.thm-message-view-background-color { + .thm-rgba-background-color(@message-background-color, @message-rgba-background-color); +} + +#rl-app{ + display: block; +} + +html.no-css { + + margin: 0; + padding: 0; + font-family: Arial, Verdana, Geneva, sans-serif; + + body { + margin: 0; + padding: 0; + } + + #rl-loading, #rl-loading-error { + position: absolute; + font-size: 30px; + line-height: 130%; + top: 50%; + width: 100%; + height: 65px; + margin: 0; + margin-top: -60px; + background-color: transparent; + text-align: center; + color: #333; + } + + .progressjs-container { + display: none; + } + + .thm-body { + color: #333; + background-color: #aaa; + background-image: none; + } + + .thm-loading { + color: #333 !important; + text-shadow: none !important; + + .e-spinner .e-bounce { + display: none !important; + } + } + + .thm-login-desc .desc { + color: #333 !important; + text-shadow: none !important; + } +} + +// glass style +html.glass { + + @glass-color: #fff !important; + @glass-p-color: #aaa !important; + @glass-m-color: rgba(255, 255, 255, .8) !important; + + .thm-login { + border: none !important; + background: none !important; + background: rgba(0, 0, 0, .3) !important; + box-shadow: none !important; + + .controls { + .input-append .add-on i { + color: @glass-m-color; + text-shadow: none !important; + outline: none !important; + box-shadow: none !important; + } + + + + input { + border: 1px solid none !important; + background: none !important; + outline: none !important; + text-shadow: none !important; + box-shadow: none !important; + + color: @glass-color; + border-color: @glass-m-color; + + &::-webkit-input-placeholder{ + color: @glass-color; + text-shadow: none !important; + } + &::-moz-placeholder{ + color: @glass-color; + text-shadow: none !important; + } + &:-moz-placeholder{ + color: @glass-color; + text-shadow: none !important; + } + &:-ms-input-placeholder{ + color: @glass-color; + text-shadow: none !important; + } + &:input-placeholder{ + color: @glass-color; + text-shadow: none !important; + } + &:placeholder{ + color: @glass-color; + text-shadow: none !important; + } + + &:focus{ + border-color: @glass-color; + } + } + .btn { + border: 1px solid none !important; + background: none !important; + outline: none !important; + text-shadow: none !important; + box-shadow: none !important; + + color: @glass-color; + border-color: @glass-m-color; + + &:hover, &:active{ + border-color: @glass-color; + } + } + } + } + + .thm-login-text { + color: @glass-m-color; + text-shadow: none !important; + + .legend, .e-checkbox-icon, .g-ui-link, .social-button, .language-button { + color: @glass-m-color; + text-shadow: none !important; + } + } +} diff --git a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminLogin.html b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminLogin.html index f90d06e69..2263f8e83 100644 --- a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminLogin.html +++ b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminLogin.html @@ -1,47 +1,47 @@ -