From c23ba31e1787405c235ab7e7f7cf46cc41c1886e Mon Sep 17 00:00:00 2001 From: RainLoop Team Date: Sat, 14 Mar 2015 03:10:00 +0400 Subject: [PATCH] Promises (first look) Thread dropdown Small fixes --- dev/Common/Enums.js | 6 + dev/Common/Globals.js | 3 - dev/Common/Utils.js | 8 +- dev/Promises/AbstractAjax.js | 172 ++ dev/Promises/User/Ajax.js | 58 + dev/Remote/User/Ajax.js | 136 +- dev/Styles/MessageView.less | 14 + dev/View/Popup/Compose.js | 65 +- dev/View/User/MailBox/MessageView.js | 48 +- gulpfile.js | 1 + package.json | 2 +- .../0.0.0/app/libraries/MailSo/Base/Utils.php | 10 + .../app/libraries/MailSo/Mail/MailClient.php | 53 +- .../0.0.0/app/libraries/RainLoop/Actions.php | 37 +- .../templates/Views/User/MailMessageView.html | 34 +- .../templates/Views/User/SystemDropDown.html | 2 +- vendors/Q/.coverignore | 1 + vendors/Q/.gitignore | 14 + vendors/Q/.jshintrc | 27 + vendors/Q/.mailmap | 2 + vendors/Q/.travis.yml | 5 + vendors/Q/CHANGES.md | 762 +++++ vendors/Q/CONTRIBUTING.md | 40 + vendors/Q/Gruntfile.js | 16 + vendors/Q/LICENSE | 18 + vendors/Q/README.md | 869 ++++++ vendors/Q/VERSIONS.md | 18 + vendors/Q/benchmark/compare-with-callbacks.js | 71 + vendors/Q/benchmark/scenarios.js | 36 + vendors/Q/design/README.js | 1026 +++++++ vendors/Q/design/q0.js | 22 + vendors/Q/design/q1.js | 26 + vendors/Q/design/q2.js | 33 + vendors/Q/design/q3.js | 30 + vendors/Q/design/q4.js | 48 + vendors/Q/design/q5.js | 56 + vendors/Q/design/q6.js | 64 + vendors/Q/design/q7.js | 126 + vendors/Q/examples/all.js | 21 + vendors/Q/examples/async-generators/0.html | 36 + .../Q/examples/async-generators/1-return.js | 19 + .../async-generators/2-error-propagation.js | 21 + .../Q/examples/async-generators/3-spawn.js | 21 + .../async-generators/4-flow-control.js | 42 + vendors/Q/examples/async-generators/README.md | 66 + vendors/Q/package.json | 79 + vendors/Q/q.js | 1937 ++++++++++++ vendors/Q/q.png | Bin 0 -> 34119 bytes vendors/Q/q.svg | 114 + vendors/Q/queue.js | 35 + vendors/Q/ref_send.md | 26 + vendors/Q/spec/aplus-adapter.js | 15 + vendors/Q/spec/lib/jasmine-1.2.0/MIT.LICENSE | 20 + .../Q/spec/lib/jasmine-1.2.0/jasmine-html.js | 616 ++++ vendors/Q/spec/lib/jasmine-1.2.0/jasmine.css | 81 + vendors/Q/spec/lib/jasmine-1.2.0/jasmine.js | 2529 ++++++++++++++++ vendors/Q/spec/lib/jasmine-promise.js | 91 + vendors/Q/spec/q-spec.html | 52 + vendors/Q/spec/q-spec.js | 2611 +++++++++++++++++ vendors/Q/spec/queue-spec.js | 180 ++ webpack.config.js | 1 + 61 files changed, 12442 insertions(+), 130 deletions(-) create mode 100644 dev/Promises/AbstractAjax.js create mode 100644 dev/Promises/User/Ajax.js create mode 100644 vendors/Q/.coverignore create mode 100644 vendors/Q/.gitignore create mode 100644 vendors/Q/.jshintrc create mode 100644 vendors/Q/.mailmap create mode 100644 vendors/Q/.travis.yml create mode 100644 vendors/Q/CHANGES.md create mode 100644 vendors/Q/CONTRIBUTING.md create mode 100644 vendors/Q/Gruntfile.js create mode 100644 vendors/Q/LICENSE create mode 100644 vendors/Q/README.md create mode 100644 vendors/Q/VERSIONS.md create mode 100644 vendors/Q/benchmark/compare-with-callbacks.js create mode 100644 vendors/Q/benchmark/scenarios.js create mode 100644 vendors/Q/design/README.js create mode 100644 vendors/Q/design/q0.js create mode 100644 vendors/Q/design/q1.js create mode 100644 vendors/Q/design/q2.js create mode 100644 vendors/Q/design/q3.js create mode 100644 vendors/Q/design/q4.js create mode 100644 vendors/Q/design/q5.js create mode 100644 vendors/Q/design/q6.js create mode 100644 vendors/Q/design/q7.js create mode 100644 vendors/Q/examples/all.js create mode 100644 vendors/Q/examples/async-generators/0.html create mode 100644 vendors/Q/examples/async-generators/1-return.js create mode 100644 vendors/Q/examples/async-generators/2-error-propagation.js create mode 100644 vendors/Q/examples/async-generators/3-spawn.js create mode 100644 vendors/Q/examples/async-generators/4-flow-control.js create mode 100644 vendors/Q/examples/async-generators/README.md create mode 100644 vendors/Q/package.json create mode 100644 vendors/Q/q.js create mode 100644 vendors/Q/q.png create mode 100644 vendors/Q/q.svg create mode 100644 vendors/Q/queue.js create mode 100644 vendors/Q/ref_send.md create mode 100644 vendors/Q/spec/aplus-adapter.js create mode 100644 vendors/Q/spec/lib/jasmine-1.2.0/MIT.LICENSE create mode 100644 vendors/Q/spec/lib/jasmine-1.2.0/jasmine-html.js create mode 100644 vendors/Q/spec/lib/jasmine-1.2.0/jasmine.css create mode 100644 vendors/Q/spec/lib/jasmine-1.2.0/jasmine.js create mode 100644 vendors/Q/spec/lib/jasmine-promise.js create mode 100644 vendors/Q/spec/q-spec.html create mode 100644 vendors/Q/spec/q-spec.js create mode 100644 vendors/Q/spec/queue-spec.js diff --git a/dev/Common/Enums.js b/dev/Common/Enums.js index a3628b601..966775695 100644 --- a/dev/Common/Enums.js +++ b/dev/Common/Enums.js @@ -421,6 +421,12 @@ 'MailServerError': 901, 'ClientViewError': 902, 'InvalidInputArgument': 903, + + 'AjaxFalse': 950, + 'AjaxAbort': 951, + 'AjaxParse': 952, + 'AjaxTimeout': 953, + 'UnknownNotification': 999, 'UnknownError': 999 }; diff --git a/dev/Common/Globals.js b/dev/Common/Globals.js index 3e4bf7431..f5e18500f 100644 --- a/dev/Common/Globals.js +++ b/dev/Common/Globals.js @@ -134,9 +134,6 @@ 'allowedContent': true, 'extraAllowedContent': true, - 'forceEnterMode': true, - - 'autoParagraph': false, 'fillEmptyBlocks': false, 'ignoreEmptyParagraph': true, diff --git a/dev/Common/Utils.js b/dev/Common/Utils.js index 96945141c..2ecbe5bea 100644 --- a/dev/Common/Utils.js +++ b/dev/Common/Utils.js @@ -613,7 +613,7 @@ */ Utils.microtime = function () { - return (new Date()).getTime(); + return (new window.Date()).getTime(); }; /** @@ -848,7 +848,7 @@ }, convertBlockquote = function (sText) { - sText = splitPlainText($.trim(sText)); + sText = Utils.trim(sText); sText = '> ' + sText.replace(/\n/gm, '\n> '); return sText.replace(/(^|\n)([> ]+)/gm, function () { return (arguments && 2 < arguments.length) ? arguments[1] + $.trim(arguments[2].replace(/[\s]/g, '')) + ' ' : ''; @@ -920,8 +920,10 @@ .replace(/&/gi, '&') ; + sText = splitPlainText(Utils.trim(sText)); + iPos = 0; - iLimit = 100; + iLimit = 800; while (0 < iLimit) { diff --git a/dev/Promises/AbstractAjax.js b/dev/Promises/AbstractAjax.js new file mode 100644 index 000000000..921212cf8 --- /dev/null +++ b/dev/Promises/AbstractAjax.js @@ -0,0 +1,172 @@ + +(function () { + + 'use strict'; + + var + _ = require('_'), + $ = require('$'), + Q = require('Q'), + + Consts = require('Common/Consts'), + Enums = require('Common/Enums'), + Utils = require('Common/Utils'), + Links = require('Common/Links'), + + Settings = require('Storage/Settings') + ; + + /** + * @constructor + */ + function AbstractAjaxPromises() + { + this.oRequests = {}; + } + + AbstractAjaxPromises.prototype.func = function (fFunc) + { + fFunc(); + + return this; + }; + + AbstractAjaxPromises.prototype.fastPromise = function (mData) + { + var oDeferred = Q.defer(); + oDeferred.resolve(mData); + return oDeferred.promise; + }; + + 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]; + } + + return this; + }; + + AbstractAjaxPromises.prototype.ajaxRequest = function (sAction, bPost, iTimeOut, oParameters, sAdditionalGetString, fTrigger) + { + var + oH = null, + self = this, + iStart = Utils.microtime(), + oDeferred = Q.defer() + ; + + iTimeOut = Utils.isNormal(iTimeOut) ? iTimeOut : Consts.Defaults.DefaultAjaxTimeout; + sAdditionalGetString = Utils.isUnd(sAdditionalGetString) ? '' : Utils.pString(sAdditionalGetString); + + if (bPost) + { + oParameters['XToken'] = Settings.settingsGet('Token'); + } + + if (fTrigger) + { + fTrigger(true); + } + + 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) { + + var bCached = false; + if (oData && oData['Time']) + { + bCached = Utils.pInt(oData['Time']) > Utils.microtime() - iStart; + } + + if ('success' === sTextStatus) + { + if (oData && oData.Result && sAction === oData.Action) + { + oData.Result.__cached__ = bCached; + oDeferred.resolve(oData.Result); + } + else if (oData && oData.Action) + { + oDeferred.reject(oData.ErrorCode ? oData.ErrorCode : Enums.Notification.AjaxFalse); + } + else + { + oDeferred.reject(Enums.Notification.AjaxParse); + } + } + else if ('timeout' === sTextStatus) + { + oDeferred.reject(Enums.Notification.AjaxTimeout); + } + else if ('abort' === sTextStatus) + { + if (!oData || !oData.__aborted) + { + oDeferred.reject(Enums.Notification.AjaxAbort); + } + } + else + { + oDeferred.reject(Enums.Notification.AjaxParse); + } + + if (self.oRequests[sAction]) + { + self.oRequests[sAction] = null; + delete self.oRequests[sAction]; + } + + if (fTrigger) + { + fTrigger(false); + } + }); + + if (oH) + { + if (this.oRequests[sAction]) + { + this.oRequests[sAction] = null; + delete this.oRequests[sAction]; + } + + this.oRequests[sAction] = oH; + } + + return oDeferred.promise; + }; + + 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); + }; + + AbstractAjaxPromises.prototype.postRequest = function (sAction, fTrigger, oParameters, iTimeOut) + { + oParameters = oParameters || {}; + oParameters['Action'] = sAction; + + return this.ajaxRequest(sAction, true, iTimeOut, oParameters, '', fTrigger); + }; + + module.exports = AbstractAjaxPromises; + +}()); \ No newline at end of file diff --git a/dev/Promises/User/Ajax.js b/dev/Promises/User/Ajax.js new file mode 100644 index 000000000..3f6aa9a1e --- /dev/null +++ b/dev/Promises/User/Ajax.js @@ -0,0 +1,58 @@ + +(function () { + + 'use strict'; + + var + _ = require('_'), + ko = require('ko'), + + AbstractAjaxPromises = require('Promises/AbstractAjax'), + + MessageModel = require('Model/Message') + ; + + /** + * @constructor + * @extends AbstractAjaxPromises + */ + function PromisesUserAjax() + { + AbstractAjaxPromises.call(this); + + this.messageListSimple.loading = ko.observable(false).extend({'rateLimit': 1}); + this.messageListSimple.hash = ''; + this.messageListSimple.cache = null; + } + + PromisesUserAjax.prototype.messageListSimple = function (sFolder, aUids) + { + var self = this, sHash = sFolder + '~' + aUids.join('/'); + if (sHash === this.messageListSimple.hash && this.messageListSimple.cache) + { + return this.fastPromise(this.messageListSimple.cache); + } + + return this.abort('MessageListSimple') + .postRequest('MessageListSimple', this.messageListSimple.loading, { + 'Folder': sFolder, + 'Uids': aUids + }).then(function (aData) { + + var aResult = _.compact(_.map(aData, function (aItem) { + return MessageModel.newInstanceFromJson(aItem); + })); + + self.messageListSimple.hash = sHash; + self.messageListSimple.cache = aResult; + + return aResult; + }) + ; + }; + + _.extend(PromisesUserAjax.prototype, AbstractAjaxPromises.prototype); + + module.exports = new PromisesUserAjax(); + +}()); \ No newline at end of file diff --git a/dev/Remote/User/Ajax.js b/dev/Remote/User/Ajax.js index 36e16ef0a..9a5b592ff 100644 --- a/dev/Remote/User/Ajax.js +++ b/dev/Remote/User/Ajax.js @@ -24,7 +24,7 @@ * @constructor * @extends AbstractRemoteStorage */ - function RemoteUserStorage() + function RemoteUserAjax() { AbstractAjaxRemote.call(this); @@ -33,12 +33,12 @@ this.sSubSubQuery = '&ss=/'; } - _.extend(RemoteUserStorage.prototype, AbstractAjaxRemote.prototype); + _.extend(RemoteUserAjax.prototype, AbstractAjaxRemote.prototype); /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.folders = function (fCallback) + RemoteUserAjax.prototype.folders = function (fCallback) { this.defaultRequest(fCallback, 'Folders', { 'SentFolder': Settings.settingsGet('SentFolder'), @@ -59,7 +59,7 @@ * @param {string=} sAdditionalCode * @param {boolean=} bAdditionalCodeSignMe */ - RemoteUserStorage.prototype.login = function (fCallback, sEmail, sLogin, sPassword, bSignMe, sLanguage, sAdditionalCode, bAdditionalCodeSignMe) + RemoteUserAjax.prototype.login = function (fCallback, sEmail, sLogin, sPassword, bSignMe, sLanguage, sAdditionalCode, bAdditionalCodeSignMe) { this.defaultRequest(fCallback, 'Login', { 'Email': sEmail, @@ -75,7 +75,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.getTwoFactor = function (fCallback) + RemoteUserAjax.prototype.getTwoFactor = function (fCallback) { this.defaultRequest(fCallback, 'GetTwoFactorInfo'); }; @@ -83,7 +83,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.createTwoFactor = function (fCallback) + RemoteUserAjax.prototype.createTwoFactor = function (fCallback) { this.defaultRequest(fCallback, 'CreateTwoFactorSecret'); }; @@ -91,7 +91,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.clearTwoFactor = function (fCallback) + RemoteUserAjax.prototype.clearTwoFactor = function (fCallback) { this.defaultRequest(fCallback, 'ClearTwoFactorInfo'); }; @@ -99,7 +99,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.showTwoFactorSecret = function (fCallback) + RemoteUserAjax.prototype.showTwoFactorSecret = function (fCallback) { this.defaultRequest(fCallback, 'ShowTwoFactorSecret'); }; @@ -108,7 +108,7 @@ * @param {?Function} fCallback * @param {string} sCode */ - RemoteUserStorage.prototype.testTwoFactor = function (fCallback, sCode) + RemoteUserAjax.prototype.testTwoFactor = function (fCallback, sCode) { this.defaultRequest(fCallback, 'TestTwoFactorInfo', { 'Code': sCode @@ -119,7 +119,7 @@ * @param {?Function} fCallback * @param {boolean} bEnable */ - RemoteUserStorage.prototype.enableTwoFactor = function (fCallback, bEnable) + RemoteUserAjax.prototype.enableTwoFactor = function (fCallback, bEnable) { this.defaultRequest(fCallback, 'EnableTwoFactor', { 'Enable': bEnable ? '1' : '0' @@ -129,7 +129,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.clearTwoFactorInfo = function (fCallback) + RemoteUserAjax.prototype.clearTwoFactorInfo = function (fCallback) { this.defaultRequest(fCallback, 'ClearTwoFactorInfo'); }; @@ -137,7 +137,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.contactsSync = function (fCallback) + RemoteUserAjax.prototype.contactsSync = function (fCallback) { this.defaultRequest(fCallback, 'ContactsSync', null, Consts.Defaults.ContactsSyncAjaxTimeout); }; @@ -149,7 +149,7 @@ * @param {string} sUser * @param {string} sPassword */ - RemoteUserStorage.prototype.saveContactsSyncData = function (fCallback, bEnable, sUrl, sUser, sPassword) + RemoteUserAjax.prototype.saveContactsSyncData = function (fCallback, bEnable, sUrl, sUser, sPassword) { this.defaultRequest(fCallback, 'SaveContactsSyncData', { 'Enable': bEnable ? '1' : '0', @@ -165,7 +165,7 @@ * @param {string} sPassword * @param {boolean=} bNew */ - RemoteUserStorage.prototype.accountSetup = function (fCallback, sEmail, sPassword, bNew) + RemoteUserAjax.prototype.accountSetup = function (fCallback, sEmail, sPassword, bNew) { bNew = Utils.isUnd(bNew) ? true : !!bNew; @@ -180,7 +180,7 @@ * @param {?Function} fCallback * @param {string} sEmailToDelete */ - RemoteUserStorage.prototype.accountDelete = function (fCallback, sEmailToDelete) + RemoteUserAjax.prototype.accountDelete = function (fCallback, sEmailToDelete) { this.defaultRequest(fCallback, 'AccountDelete', { 'EmailToDelete': sEmailToDelete @@ -192,7 +192,7 @@ * @param {Array} aAccounts * @param {Array} aIdentities */ - RemoteUserStorage.prototype.accountsAndIdentitiesSortOrder = function (fCallback, aAccounts, aIdentities) + RemoteUserAjax.prototype.accountsAndIdentitiesSortOrder = function (fCallback, aAccounts, aIdentities) { this.defaultRequest(fCallback, 'AccountsAndIdentitiesSortOrder', { 'Accounts': aAccounts, @@ -210,7 +210,7 @@ * @param {string} sSignature * @param {boolean} bSignatureInsertBefore */ - RemoteUserStorage.prototype.identityUpdate = function (fCallback, sId, sEmail, sName, sReplyTo, sBcc, + RemoteUserAjax.prototype.identityUpdate = function (fCallback, sId, sEmail, sName, sReplyTo, sBcc, sSignature, bSignatureInsertBefore) { this.defaultRequest(fCallback, 'IdentityUpdate', { @@ -228,7 +228,7 @@ * @param {?Function} fCallback * @param {string} sIdToDelete */ - RemoteUserStorage.prototype.identityDelete = function (fCallback, sIdToDelete) + RemoteUserAjax.prototype.identityDelete = function (fCallback, sIdToDelete) { this.defaultRequest(fCallback, 'IdentityDelete', { 'IdToDelete': sIdToDelete @@ -238,7 +238,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.accountsAndIdentities = function (fCallback) + RemoteUserAjax.prototype.accountsAndIdentities = function (fCallback) { this.defaultRequest(fCallback, 'AccountsAndIdentities'); }; @@ -246,7 +246,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.accountsCounts = function (fCallback) + RemoteUserAjax.prototype.accountsCounts = function (fCallback) { this.defaultRequest(fCallback, 'AccountsCounts'); }; @@ -254,7 +254,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.filtersSave = function (fCallback, + RemoteUserAjax.prototype.filtersSave = function (fCallback, aFilters, sRaw, bRawIsActive) { this.defaultRequest(fCallback, 'FiltersSave', { @@ -269,7 +269,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.filtersGet = function (fCallback) + RemoteUserAjax.prototype.filtersGet = function (fCallback) { this.defaultRequest(fCallback, 'Filters', {}); }; @@ -277,7 +277,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.templates = function (fCallback) + RemoteUserAjax.prototype.templates = function (fCallback) { this.defaultRequest(fCallback, 'Templates', {}); }; @@ -285,7 +285,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.templateGetById = function (fCallback, sID) + RemoteUserAjax.prototype.templateGetById = function (fCallback, sID) { this.defaultRequest(fCallback, 'TemplateGetByID', { 'ID': sID @@ -295,7 +295,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.templateDelete = function (fCallback, sID) + RemoteUserAjax.prototype.templateDelete = function (fCallback, sID) { this.defaultRequest(fCallback, 'TemplateDelete', { 'IdToDelete': sID @@ -305,7 +305,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.templateSetup = function (fCallback, sID, sName, sBody) + RemoteUserAjax.prototype.templateSetup = function (fCallback, sID, sName, sBody) { this.defaultRequest(fCallback, 'TemplateSetup', { 'ID': sID, @@ -319,7 +319,7 @@ * @param {string} sFolderFullNameRaw * @param {Array} aUids */ - RemoteUserStorage.prototype.messageListSimple = function (fCallback, sFolderFullNameRaw, aUids) + RemoteUserAjax.prototype.messageListSimple = function (fCallback, sFolderFullNameRaw, aUids) { return this.defaultRequest(fCallback, 'MessageListSimple', { 'Folder': Utils.pString(sFolderFullNameRaw), @@ -335,7 +335,7 @@ * @param {string=} sSearch = '' * @param {boolean=} bSilent = false */ - RemoteUserStorage.prototype.messageList = function (fCallback, sFolderFullNameRaw, iOffset, iLimit, sSearch, bSilent) + RemoteUserAjax.prototype.messageList = function (fCallback, sFolderFullNameRaw, iOffset, iLimit, sSearch, bSilent) { sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw); @@ -381,7 +381,7 @@ * @param {?Function} fCallback * @param {Array} aDownloads */ - RemoteUserStorage.prototype.messageUploadAttachments = function (fCallback, aDownloads) + RemoteUserAjax.prototype.messageUploadAttachments = function (fCallback, aDownloads) { this.defaultRequest(fCallback, 'MessageUploadAttachments', { 'Attachments': aDownloads @@ -394,7 +394,7 @@ * @param {number} iUid * @return {boolean} */ - RemoteUserStorage.prototype.message = function (fCallback, sFolderFullNameRaw, iUid) + RemoteUserAjax.prototype.message = function (fCallback, sFolderFullNameRaw, iUid) { sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw); iUid = Utils.pInt(iUid); @@ -421,7 +421,7 @@ * @param {number} iUid * @return {boolean} */ - RemoteUserStorage.prototype.messageThreadsFromCache = function (fCallback, sFolderFullNameRaw, iUid) + RemoteUserAjax.prototype.messageThreadsFromCache = function (fCallback, sFolderFullNameRaw, iUid) { sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw); iUid = Utils.pInt(iUid); @@ -448,7 +448,7 @@ * @param {?Function} fCallback * @param {Array} aExternals */ - RemoteUserStorage.prototype.composeUploadExternals = function (fCallback, aExternals) + RemoteUserAjax.prototype.composeUploadExternals = function (fCallback, aExternals) { this.defaultRequest(fCallback, 'ComposeUploadExternals', { 'Externals': aExternals @@ -460,7 +460,7 @@ * @param {string} sUrl * @param {string} sAccessToken */ - RemoteUserStorage.prototype.composeUploadDrive = function (fCallback, sUrl, sAccessToken) + RemoteUserAjax.prototype.composeUploadDrive = function (fCallback, sUrl, sAccessToken) { this.defaultRequest(fCallback, 'ComposeUploadDrive', { 'AccessToken': sAccessToken, @@ -473,7 +473,7 @@ * @param {string} sFolder * @param {Array=} aList = [] */ - RemoteUserStorage.prototype.folderInformation = function (fCallback, sFolder, aList) + RemoteUserAjax.prototype.folderInformation = function (fCallback, sFolder, aList) { var bRequest = true, @@ -524,7 +524,7 @@ * @param {?Function} fCallback * @param {Array} aFolders */ - RemoteUserStorage.prototype.folderInformationMultiply = function (fCallback, aFolders) + RemoteUserAjax.prototype.folderInformationMultiply = function (fCallback, aFolders) { this.defaultRequest(fCallback, 'FolderInformationMultiply', { 'Folders': aFolders @@ -534,7 +534,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.logout = function (fCallback) + RemoteUserAjax.prototype.logout = function (fCallback) { this.defaultRequest(fCallback, 'Logout'); }; @@ -545,7 +545,7 @@ * @param {Array} aUids * @param {boolean} bSetFlagged */ - RemoteUserStorage.prototype.messageSetFlagged = function (fCallback, sFolderFullNameRaw, aUids, bSetFlagged) + RemoteUserAjax.prototype.messageSetFlagged = function (fCallback, sFolderFullNameRaw, aUids, bSetFlagged) { this.defaultRequest(fCallback, 'MessageSetFlagged', { 'Folder': sFolderFullNameRaw, @@ -560,7 +560,7 @@ * @param {Array} aUids * @param {boolean} bSetSeen */ - RemoteUserStorage.prototype.messageSetSeen = function (fCallback, sFolderFullNameRaw, aUids, bSetSeen) + RemoteUserAjax.prototype.messageSetSeen = function (fCallback, sFolderFullNameRaw, aUids, bSetSeen) { this.defaultRequest(fCallback, 'MessageSetSeen', { 'Folder': sFolderFullNameRaw, @@ -574,7 +574,7 @@ * @param {string} sFolderFullNameRaw * @param {boolean} bSetSeen */ - RemoteUserStorage.prototype.messageSetSeenToAll = function (fCallback, sFolderFullNameRaw, bSetSeen) + RemoteUserAjax.prototype.messageSetSeenToAll = function (fCallback, sFolderFullNameRaw, bSetSeen) { this.defaultRequest(fCallback, 'MessageSetSeenToAll', { 'Folder': sFolderFullNameRaw, @@ -600,7 +600,7 @@ * @param {string} sReferences * @param {boolean} bMarkAsImportant */ - RemoteUserStorage.prototype.saveMessage = function (fCallback, sIdentityID, sMessageFolder, sMessageUid, sDraftFolder, + 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', { @@ -632,7 +632,7 @@ * @param {string} sSubject * @param {string} sText */ - RemoteUserStorage.prototype.sendReadReceiptMessage = function (fCallback, sMessageFolder, sMessageUid, sReadReceipt, sSubject, sText) + RemoteUserAjax.prototype.sendReadReceiptMessage = function (fCallback, sMessageFolder, sMessageUid, sReadReceipt, sSubject, sText) { this.defaultRequest(fCallback, 'SendReadReceiptMessage', { 'MessageFolder': sMessageFolder, @@ -664,7 +664,7 @@ * @param {boolean} bRequestReadReceipt * @param {boolean} bMarkAsImportant */ - RemoteUserStorage.prototype.sendMessage = function (fCallback, sIdentityID, sMessageFolder, sMessageUid, sSentFolder, + RemoteUserAjax.prototype.sendMessage = function (fCallback, sIdentityID, sMessageFolder, sMessageUid, sSentFolder, sTo, sCc, sBcc, sReplyTo, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences, bRequestDsn, bRequestReadReceipt, bMarkAsImportant) { @@ -694,7 +694,7 @@ * @param {?Function} fCallback * @param {Object} oData */ - RemoteUserStorage.prototype.saveSystemFolders = function (fCallback, oData) + RemoteUserAjax.prototype.saveSystemFolders = function (fCallback, oData) { this.defaultRequest(fCallback, 'SystemFoldersUpdate', oData); }; @@ -703,7 +703,7 @@ * @param {?Function} fCallback * @param {Object} oData */ - RemoteUserStorage.prototype.saveSettings = function (fCallback, oData) + RemoteUserAjax.prototype.saveSettings = function (fCallback, oData) { this.defaultRequest(fCallback, 'SettingsUpdate', oData); }; @@ -713,7 +713,7 @@ * @param {string} sPrevPassword * @param {string} sNewPassword */ - RemoteUserStorage.prototype.changePassword = function (fCallback, sPrevPassword, sNewPassword) + RemoteUserAjax.prototype.changePassword = function (fCallback, sPrevPassword, sNewPassword) { this.defaultRequest(fCallback, 'ChangePassword', { 'PrevPassword': sPrevPassword, @@ -726,7 +726,7 @@ * @param {string} sNewFolderName * @param {string} sParentName */ - RemoteUserStorage.prototype.folderCreate = function (fCallback, sNewFolderName, sParentName) + RemoteUserAjax.prototype.folderCreate = function (fCallback, sNewFolderName, sParentName) { this.defaultRequest(fCallback, 'FolderCreate', { 'Folder': sNewFolderName, @@ -738,7 +738,7 @@ * @param {?Function} fCallback * @param {string} sFolderFullNameRaw */ - RemoteUserStorage.prototype.folderDelete = function (fCallback, sFolderFullNameRaw) + RemoteUserAjax.prototype.folderDelete = function (fCallback, sFolderFullNameRaw) { this.defaultRequest(fCallback, 'FolderDelete', { 'Folder': sFolderFullNameRaw @@ -750,7 +750,7 @@ * @param {string} sPrevFolderFullNameRaw * @param {string} sNewFolderName */ - RemoteUserStorage.prototype.folderRename = function (fCallback, sPrevFolderFullNameRaw, sNewFolderName) + RemoteUserAjax.prototype.folderRename = function (fCallback, sPrevFolderFullNameRaw, sNewFolderName) { this.defaultRequest(fCallback, 'FolderRename', { 'Folder': sPrevFolderFullNameRaw, @@ -762,7 +762,7 @@ * @param {?Function} fCallback * @param {string} sFolderFullNameRaw */ - RemoteUserStorage.prototype.folderClear = function (fCallback, sFolderFullNameRaw) + RemoteUserAjax.prototype.folderClear = function (fCallback, sFolderFullNameRaw) { this.defaultRequest(fCallback, 'FolderClear', { 'Folder': sFolderFullNameRaw @@ -774,7 +774,7 @@ * @param {string} sFolderFullNameRaw * @param {boolean} bSubscribe */ - RemoteUserStorage.prototype.folderSetSubscribe = function (fCallback, sFolderFullNameRaw, bSubscribe) + RemoteUserAjax.prototype.folderSetSubscribe = function (fCallback, sFolderFullNameRaw, bSubscribe) { this.defaultRequest(fCallback, 'FolderSubscribe', { 'Folder': sFolderFullNameRaw, @@ -789,7 +789,7 @@ * @param {Array} aUids * @param {string=} sLearning */ - RemoteUserStorage.prototype.messagesMove = function (fCallback, sFolder, sToFolder, aUids, sLearning) + RemoteUserAjax.prototype.messagesMove = function (fCallback, sFolder, sToFolder, aUids, sLearning) { this.defaultRequest(fCallback, 'MessageMove', { 'FromFolder': sFolder, @@ -805,7 +805,7 @@ * @param {string} sToFolder * @param {Array} aUids */ - RemoteUserStorage.prototype.messagesCopy = function (fCallback, sFolder, sToFolder, aUids) + RemoteUserAjax.prototype.messagesCopy = function (fCallback, sFolder, sToFolder, aUids) { this.defaultRequest(fCallback, 'MessageCopy', { 'FromFolder': sFolder, @@ -819,7 +819,7 @@ * @param {string} sFolder * @param {Array} aUids */ - RemoteUserStorage.prototype.messagesDelete = function (fCallback, sFolder, aUids) + RemoteUserAjax.prototype.messagesDelete = function (fCallback, sFolder, aUids) { this.defaultRequest(fCallback, 'MessageDelete', { 'Folder': sFolder, @@ -830,7 +830,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.appDelayStart = function (fCallback) + RemoteUserAjax.prototype.appDelayStart = function (fCallback) { this.defaultRequest(fCallback, 'AppDelayStart'); }; @@ -838,7 +838,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.quota = function (fCallback) + RemoteUserAjax.prototype.quota = function (fCallback) { this.defaultRequest(fCallback, 'Quota'); }; @@ -849,7 +849,7 @@ * @param {number} iLimit * @param {string} sSearch */ - RemoteUserStorage.prototype.contacts = function (fCallback, iOffset, iLimit, sSearch) + RemoteUserAjax.prototype.contacts = function (fCallback, iOffset, iLimit, sSearch) { this.defaultRequest(fCallback, 'Contacts', { 'Offset': iOffset, @@ -864,7 +864,7 @@ * @param {string} sUid * @param {Array} aProperties */ - RemoteUserStorage.prototype.contactSave = function (fCallback, sRequestUid, sUid, aProperties) + RemoteUserAjax.prototype.contactSave = function (fCallback, sRequestUid, sUid, aProperties) { this.defaultRequest(fCallback, 'ContactSave', { 'RequestUid': sRequestUid, @@ -877,7 +877,7 @@ * @param {?Function} fCallback * @param {Array} aUids */ - RemoteUserStorage.prototype.contactsDelete = function (fCallback, aUids) + RemoteUserAjax.prototype.contactsDelete = function (fCallback, aUids) { this.defaultRequest(fCallback, 'ContactsDelete', { 'Uids': aUids.join(',') @@ -889,7 +889,7 @@ * @param {string} sQuery * @param {number} iPage */ - RemoteUserStorage.prototype.suggestions = function (fCallback, sQuery, iPage) + RemoteUserAjax.prototype.suggestions = function (fCallback, sQuery, iPage) { this.defaultRequest(fCallback, 'Suggestions', { 'Query': sQuery, @@ -900,7 +900,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.clearUserBackground = function (fCallback) + RemoteUserAjax.prototype.clearUserBackground = function (fCallback) { this.defaultRequest(fCallback, 'ClearUserBackground'); }; @@ -908,7 +908,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.facebookUser = function (fCallback) + RemoteUserAjax.prototype.facebookUser = function (fCallback) { this.defaultRequest(fCallback, 'SocialFacebookUserInformation'); }; @@ -916,7 +916,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.facebookDisconnect = function (fCallback) + RemoteUserAjax.prototype.facebookDisconnect = function (fCallback) { this.defaultRequest(fCallback, 'SocialFacebookDisconnect'); }; @@ -924,7 +924,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.twitterUser = function (fCallback) + RemoteUserAjax.prototype.twitterUser = function (fCallback) { this.defaultRequest(fCallback, 'SocialTwitterUserInformation'); }; @@ -932,7 +932,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.twitterDisconnect = function (fCallback) + RemoteUserAjax.prototype.twitterDisconnect = function (fCallback) { this.defaultRequest(fCallback, 'SocialTwitterDisconnect'); }; @@ -940,7 +940,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.googleUser = function (fCallback) + RemoteUserAjax.prototype.googleUser = function (fCallback) { this.defaultRequest(fCallback, 'SocialGoogleUserInformation'); }; @@ -948,7 +948,7 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.googleDisconnect = function (fCallback) + RemoteUserAjax.prototype.googleDisconnect = function (fCallback) { this.defaultRequest(fCallback, 'SocialGoogleDisconnect'); }; @@ -956,11 +956,11 @@ /** * @param {?Function} fCallback */ - RemoteUserStorage.prototype.socialUsers = function (fCallback) + RemoteUserAjax.prototype.socialUsers = function (fCallback) { this.defaultRequest(fCallback, 'SocialUsers'); }; - module.exports = new RemoteUserStorage(); + module.exports = new RemoteUserAjax(); }()); \ No newline at end of file diff --git a/dev/Styles/MessageView.less b/dev/Styles/MessageView.less index 0fb9c26a0..a5b518e9a 100644 --- a/dev/Styles/MessageView.less +++ b/dev/Styles/MessageView.less @@ -364,6 +364,20 @@ html.rl-no-preview-pane { border-radius: @rlLowBorderRadius; border-color: darken(@rlMainDarkColor, 5%); } + + .thread-list { + + .e-link { + padding: 3px 5px 3px 10px; + overflow: hidden; + text-overflow: ellipsis; + } + + .hread-date { + font-size: 13px; + color: #999; + } + } } html.rl-no-preview-pane .messageView { diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js index 3764cfb68..16534d83a 100644 --- a/dev/View/Popup/Compose.js +++ b/dev/View/Popup/Compose.js @@ -504,6 +504,8 @@ this.driveCallback = _.bind(this.driveCallback, this); + this.onMessageUploadAttachments = _.bind(this.onMessageUploadAttachments, this); + this.bDisabeCloseOnEsc = true; this.sDefaultKeyScope = Enums.KeyState.Compose; @@ -1228,37 +1230,7 @@ aDownloads = this.getAttachmentsDownloadsForUpload(); if (Utils.isNonEmptyArray(aDownloads)) { - Remote.messageUploadAttachments(function (sResult, oData) { - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - var - oAttachment = null, - sTempName = '' - ; - - if (!self.viewModelVisibility()) - { - for (sTempName in oData.Result) - { - if (oData.Result.hasOwnProperty(sTempName)) - { - oAttachment = self.getAttachmentById(oData.Result[sTempName]); - if (oAttachment) - { - oAttachment.tempName(sTempName); - oAttachment.waiting(false).uploading(false).complete(true); - } - } - } - } - } - else - { - self.setMessageAttachmentFailedDownloadText(); - } - - }, aDownloads); + Remote.messageUploadAttachments(this.onMessageUploadAttachments, aDownloads); } if (oIdentity) @@ -1269,6 +1241,37 @@ this.resizerTrigger(); }; + ComposePopupView.prototype.onMessageUploadAttachments = function (sResult, oData) + { + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) + { + var + oAttachment = null, + sTempName = '' + ; + + if (!this.viewModelVisibility()) + { + for (sTempName in oData.Result) + { + if (oData.Result.hasOwnProperty(sTempName)) + { + oAttachment = this.getAttachmentById(oData.Result[sTempName]); + if (oAttachment) + { + oAttachment.tempName(sTempName); + oAttachment.waiting(false).uploading(false).complete(true); + } + } + } + } + } + else + { + this.setMessageAttachmentFailedDownloadText(); + } + }; + ComposePopupView.prototype.setFocusInPopup = function () { if (!Globals.bMobileDevice) diff --git a/dev/View/User/MailBox/MessageView.js b/dev/View/User/MailBox/MessageView.js index 488c55513..51b877221 100644 --- a/dev/View/User/MailBox/MessageView.js +++ b/dev/View/User/MailBox/MessageView.js @@ -29,6 +29,8 @@ Local = require('Storage/Client'), Remote = require('Remote/User/Ajax'), + Promises = require('Promises/User/Ajax'), + kn = require('Knoin/Knoin'), AbstractView = require('Knoin/AbstractView') ; @@ -73,6 +75,8 @@ this.fullScreenMode = MessageStore.messageFullScreenMode; + this.messageListOfThreadsLoading = Promises.messageListSimple.loading; + this.lastReplyAction_ = ko.observable(''); this.lastReplyAction = ko.computed({ read: this.lastReplyAction_, @@ -205,9 +209,11 @@ // THREADS this.viewThreads = ko.observableArray([]); - this.viewThreadMessages = ko.observableArray([]); this.viewThreads.trigger = ko.observable(false); + this.viewThreadMessages = ko.observableArray([]); + this.viewThreadMessages.hash = ''; + MessageStore.messageLastThreadUidsData.subscribe(function (oData) { if (oData && oData['Uids']) { @@ -290,14 +296,39 @@ }, this.viewThreadsControlForwardAllow); this.threadListCommand = Utils.createCommand(this, function () { - var aList = [], aStatus = this.viewThreads.status(); + + var + self = this, + sFolder = this.viewFolder, + sUid = this.viewUid, + aUids = this.viewThreads(), + aStatus = this.viewThreads.status() + ; + if (aStatus && aStatus[0]) { - this.viewThreadMessages(aList); -// window.console.log(aStatus); + self.viewThreadMessages([]); + Promises.messageListSimple(sFolder, aUids).then(function (aList) { + + _.each(aList, function (oItem) { + if (oItem && oItem.uid) + { + oItem.selected(sUid === oItem.uid); + } + }); + + self.viewThreadMessages(aList); + + }, function (iErrorCode) { + + window.alert(Translator.getNotification(iErrorCode)); + + }); } + }, function () { - return !this.messageLoadingThrottle(); + return !this.messageLoadingThrottle() && + !this.messageListOfThreadsLoading(); }); // PGP @@ -675,6 +706,13 @@ oEvent.stopPropagation(); } }) + .on('click', '.thread-list .thread-list-message', function () { + var oMessage = ko.dataFor(this); + if (oMessage && oMessage.folderFullNameRaw && oMessage.uid) + { + self.openThreadMessage(oMessage.uid); + } + }) .on('click', '.attachmentsPlace .attachmentItem .attachmentNameParent', function () { var diff --git a/gulpfile.js b/gulpfile.js index 4976b8976..036b48a0c 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -168,6 +168,7 @@ cfg.paths.js = { 'vendors/ssm/ssm.min.js', 'vendors/jua/jua.min.js', 'vendors/buzz/buzz.min.js', + 'vendors/Q/q.js', 'vendors/Autolinker/Autolinker.min.js', 'vendors/photoswipe/photoswipe.min.js', 'vendors/photoswipe/photoswipe-ui-default.min.js', diff --git a/package.json b/package.json index 4aaf77d17..05799b2f4 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "RainLoop", "title": "RainLoop Webmail", "version": "1.8.2", - "release": "284", + "release": "287", "description": "Simple, modern & fast web-based email client", "homepage": "http://rainloop.net", "main": "gulpfile.js", diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Base/Utils.php b/rainloop/v/0.0.0/app/libraries/MailSo/Base/Utils.php index e8d41c384..d8b35ccf8 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Base/Utils.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Base/Utils.php @@ -2217,6 +2217,16 @@ END; )); } + /** + * @param string $sIp + * + * @return bool + */ + public static function ValidateIP($sIp) + { + return !empty($sIp) && $sIp === @\filter_var($sIp, FILTER_VALIDATE_IP); + } + /** * @return \Net_IDNA2 */ 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 86c20f23a..ce428e586 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 @@ -154,6 +154,26 @@ class MailClient 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 + ), true); + } + /** * @return string */ @@ -1622,11 +1642,12 @@ class MailClient * @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) + public function MessageListByRequestIndexOrUids(&$oMessageCollection, $aRequestIndexOrUids, $bIndexAsUid, $bSimple = false) { if (\is_array($aRequestIndexOrUids) && 0 < \count($aRequestIndexOrUids)) { @@ -1637,7 +1658,8 @@ class MailClient \MailSo\Imap\Enumerations\FetchType::INTERNALDATE, \MailSo\Imap\Enumerations\FetchType::FLAGS, \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE, - $this->getEnvelopeOrHeadersRequestString() + $bSimple ? $this->getEnvelopeOrHeadersRequestStringForSimpleList() : + $this->getEnvelopeOrHeadersRequestString() ), \MailSo\Base\Utils::PrepearFetchSequence($aRequestIndexOrUids), $bIndexAsUid); if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse)) @@ -1862,6 +1884,33 @@ class MailClient return \array_map('trim', $aResult); } + /** + * @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 string $sFolderName * @param int $iOffset = 0 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 19ce785b3..f177834f7 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -1520,7 +1520,8 @@ class Actions $aResult['AllowDropboxSocial'] = (bool) $oConfig->Get('social', 'dropbox_enable', false); $aResult['DropboxApiKey'] = (string) $oConfig->Get('social', 'dropbox_api_key', ''); - $aResult['SubscriptionEnabled'] = \MailSo\Base\Utils::ValidateDomain($aResult['AdminDomain']); + $aResult['SubscriptionEnabled'] = \MailSo\Base\Utils::ValidateDomain($aResult['AdminDomain']) || + \MailSo\Base\Utils::ValidateIP($aResult['AdminDomain']); $aResult['WeakPassword'] = $oConfig->ValidatePassword('12345'); $aResult['CoreAccess'] = $this->rainLoopCoreAccess(); @@ -5478,6 +5479,40 @@ class Actions return $this->DefaultResponse(__FUNCTION__, $oMessageList); } + /** + * @return array + * + * @throws \MailSo\Base\Exceptions\Exception + */ + public function DoMessageListSimple() + { +// \sleep(2); +// throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList); + + $sFolder = $this->GetActionParam('Folder', ''); + $aUids = $this->GetActionParam('Uids', null); + + if (0 === \strlen($sFolder) || !\is_array($aUids)) + { + throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidInputArgument); + } + + $this->initMailClientConnection(); + + $aMessageList = array(); + + try + { + $aMessageList = $this->MailClient()->MessageListSimple($sFolder, $aUids); + } + catch (\Exception $oException) + { + throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList, $oException); + } + + return $this->DefaultResponse(__FUNCTION__, $aMessageList); + } + /** * @param \RainLoop\Model\Account $oAccount * @param bool $bWithDraftInfo = true diff --git a/rainloop/v/0.0.0/app/templates/Views/User/MailMessageView.html b/rainloop/v/0.0.0/app/templates/Views/User/MailMessageView.html index fc0ef83c5..38dd6f095 100644 --- a/rainloop/v/0.0.0/app/templates/Views/User/MailMessageView.html +++ b/rainloop/v/0.0.0/app/templates/Views/User/MailMessageView.html @@ -186,26 +186,30 @@ - - - - + + - +
+ +
+
+ +
+ diff --git a/rainloop/v/0.0.0/app/templates/Views/User/SystemDropDown.html b/rainloop/v/0.0.0/app/templates/Views/User/SystemDropDown.html index 1fbc9b8f8..5d204a74e 100644 --- a/rainloop/v/0.0.0/app/templates/Views/User/SystemDropDown.html +++ b/rainloop/v/0.0.0/app/templates/Views/User/SystemDropDown.html @@ -19,7 +19,7 @@