diff --git a/dev/App/User.js b/dev/App/User.js index 0bc8cb8a0..f9ca7415e 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -26,7 +26,6 @@ Cache = require('Common/Cache'), SocialStore = require('Stores/Social'), - AppStore = require('Stores/User/App'), SettingsStore = require('Stores/User/Settings'), AccountStore = require('Stores/User/Account'), IdentityStore = require('Stores/User/Identity'), @@ -40,9 +39,9 @@ Settings = require('Storage/Settings'), Remote = require('Remote/User/Ajax'), + Promises = require('Promises/User/Ajax'), EmailModel = require('Model/Email'), - FolderModel = require('Model/Folder'), AccountModel = require('Model/Account'), IdentityModel = require('Model/Identity'), TemplateModel = require('Model/Template'), @@ -434,27 +433,35 @@ /** * @param {Function=} fCallback */ - AppUser.prototype.folders = function (fCallback) + AppUser.prototype.foldersReload = function (fCallback) { - FolderStore.foldersLoading(true); - - Remote.folders(_.bind(function (sResult, oData) { - - var bResult = false; - FolderStore.foldersLoading(false); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - bResult = true; - this.setFolders(oData); - } - + Promises.foldersReload(FolderStore.foldersLoading).then(function (bValue) { if (fCallback) { - fCallback(bResult); + fCallback(!!bValue); } + }).fail(function () { + if (fCallback) + { + fCallback(false); + } + }); + }; - }, this)); + AppUser.prototype.foldersPromisesActionHelper = function (oPromise, iErrorDefCode) + { + Promises + .abort('Folders') + .fastResolve(true) + .then(function () { + return oPromise; + }) + .fail(function (iErrorCode) { + FolderStore.folderList.error(Translator.getNotification(iErrorCode, '', iErrorDefCode)); + }).fin(function () { + Promises.foldersReloadWithTimeout(FolderStore.foldersLoading); + }).done() + ; }; AppUser.prototype.reloadOpenPgpKeys = function () @@ -1026,157 +1033,6 @@ }, sQuery); }; - /** - * @param {string} sNamespace - * @param {Array} aFolders - * @return {Array} - */ - AppUser.prototype.folderResponseParseRec = function (sNamespace, aFolders) - { - var - self = this, - iIndex = 0, - iLen = 0, - oFolder = null, - oCacheFolder = null, - sFolderFullNameRaw = '', - aSubFolders = [], - aList = [] - ; - - for (iIndex = 0, iLen = aFolders.length; iIndex < iLen; iIndex++) - { - oFolder = aFolders[iIndex]; - if (oFolder) - { - sFolderFullNameRaw = oFolder.FullNameRaw; - - oCacheFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw); - if (!oCacheFolder) - { - oCacheFolder = FolderModel.newInstanceFromJson(oFolder); - if (oCacheFolder) - { - Cache.setFolderToCacheList(sFolderFullNameRaw, oCacheFolder); - Cache.setFolderFullNameRaw(oCacheFolder.fullNameHash, sFolderFullNameRaw, oCacheFolder); - } - } - - if (oCacheFolder) - { - oCacheFolder.collapsed(!self.isFolderExpanded(oCacheFolder.fullNameHash)); - - 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); - } - } - - aSubFolders = oFolder['SubFolders']; - if (aSubFolders && 'Collection/FolderCollection' === aSubFolders['@Object'] && - aSubFolders['@Collection'] && Utils.isArray(aSubFolders['@Collection'])) - { - oCacheFolder.subFolders( - this.folderResponseParseRec(sNamespace, aSubFolders['@Collection'])); - } - - aList.push(oCacheFolder); - } - } - } - - return aList; - }; - - /** - * @param {*} oData - */ - AppUser.prototype.setFolders = function (oData) - { - var - bUpdate = false, - fNormalizeFolder = function (sFolderFullNameRaw) { - return ('' === sFolderFullNameRaw || Consts.Values.UnuseOptionValue === sFolderFullNameRaw || - null !== Cache.getFolderFromCacheList(sFolderFullNameRaw)) ? sFolderFullNameRaw : ''; - } - ; - - if (oData && oData.Result && 'Collection/FolderCollection' === oData.Result['@Object'] && - oData.Result['@Collection'] && Utils.isArray(oData.Result['@Collection'])) - { - if (!Utils.isUnd(oData.Result.Namespace)) - { - FolderStore.namespace = oData.Result.Namespace; - } - - AppStore.threadsAllowed(!!Settings.settingsGet('UseImapThread') && - oData.Result.IsThreadsSupported && true); - - FolderStore.folderList(this.folderResponseParseRec(FolderStore.namespace, oData.Result['@Collection'])); - FolderStore.folderList.optimized(!!oData.Result.Optimized); - - if (oData.Result['SystemFolders'] && '' === '' + - Settings.settingsGet('SentFolder') + - Settings.settingsGet('DraftFolder') + - Settings.settingsGet('SpamFolder') + - Settings.settingsGet('TrashFolder') + - Settings.settingsGet('ArchiveFolder') + - Settings.settingsGet('NullFolder')) - { - // TODO Magic Numbers - Settings.settingsSet('SentFolder', oData.Result['SystemFolders'][2] || null); - Settings.settingsSet('DraftFolder', oData.Result['SystemFolders'][3] || null); - Settings.settingsSet('SpamFolder', oData.Result['SystemFolders'][4] || null); - Settings.settingsSet('TrashFolder', oData.Result['SystemFolders'][5] || null); - Settings.settingsSet('ArchiveFolder', oData.Result['SystemFolders'][12] || null); - - bUpdate = true; - } - - FolderStore.sentFolder(fNormalizeFolder(Settings.settingsGet('SentFolder'))); - FolderStore.draftFolder(fNormalizeFolder(Settings.settingsGet('DraftFolder'))); - FolderStore.spamFolder(fNormalizeFolder(Settings.settingsGet('SpamFolder'))); - FolderStore.trashFolder(fNormalizeFolder(Settings.settingsGet('TrashFolder'))); - FolderStore.archiveFolder(fNormalizeFolder(Settings.settingsGet('ArchiveFolder'))); - - if (bUpdate) - { - Remote.saveSystemFolders(Utils.emptyFunction, { - 'SentFolder': FolderStore.sentFolder(), - 'DraftFolder': FolderStore.draftFolder(), - 'SpamFolder': FolderStore.spamFolder(), - 'TrashFolder': FolderStore.trashFolder(), - 'ArchiveFolder': FolderStore.archiveFolder(), - 'NullFolder': 'NullFolder' - }); - } - - Local.set(Enums.ClientSideKeyName.FoldersLashHash, oData.Result.FoldersHash); - } - }; - - /** - * @param {string} sFullNameHash - * @return {boolean} - */ - AppUser.prototype.isFolderExpanded = function (sFullNameHash) - { - var aExpandedList = Local.get(Enums.ClientSideKeyName.ExpandedFolders); - return Utils.isArray(aExpandedList) && -1 !== _.indexOf(aExpandedList, sFullNameHash); - }; - /** * @param {string} sFullNameHash * @param {boolean} bExpanded @@ -1429,7 +1285,7 @@ //require.ensure([], function() { // require code splitting - self.folders(_.bind(function (bValue) { + self.foldersReload(_.bind(function (bValue) { kn.hideLoading(); @@ -1498,7 +1354,7 @@ }); Events.sub('interval.20m', function () { - self.folders(); + self.foldersReload(); }); iContactsSyncInterval = 5 <= iContactsSyncInterval ? iContactsSyncInterval : 20; diff --git a/dev/Common/Translator.js b/dev/Common/Translator.js index 2c75c358a..cb64166c4 100644 --- a/dev/Common/Translator.js +++ b/dev/Common/Translator.js @@ -235,9 +235,10 @@ /** * @param {number} iCode * @param {*=} mMessage = '' + * @param {*=} mDefCode = null * @return {string} */ - Translator.prototype.getNotification = function (iCode, mMessage) + Translator.prototype.getNotification = function (iCode, mMessage, mDefCode) { iCode = window.parseInt(iCode, 10) || 0; if (Enums.Notification.ClientViewError === iCode && mMessage) @@ -245,7 +246,9 @@ return mMessage; } - return _.isUndefined(this.notificationI18N[iCode]) ? '' : this.notificationI18N[iCode]; + return _.isUndefined(this.notificationI18N[iCode]) ? ( + mDefCode && _.isUndefined(this.notificationI18N[mDefCode]) ? this.notificationI18N[mDefCode] : '' + ) : this.notificationI18N[iCode]; }; /** diff --git a/dev/Model/MessageSimple.js b/dev/Model/MessageSimple.js index fc36dfecd..b7e9dcfbb 100644 --- a/dev/Model/MessageSimple.js +++ b/dev/Model/MessageSimple.js @@ -20,30 +20,18 @@ { AbstractModel.call(this, 'MessageSimpleModel'); - this.selected = false; - - this.folderFullNameRaw = ''; - this.uid = ''; - this.size = 0; - - this.sender = ''; - this.subject = ''; - - this.dateUTC = 0; + this.clear(); } _.extend(MessageSimpleModel.prototype, AbstractModel.prototype); - /** - * @static - * @param {AjaxJsonMessage} oJsonMessage - * @return {?MessageSimpleModel} - */ - MessageSimpleModel.newInstanceFromJson = function (oJsonMessage) - { - var oMessageModel = new MessageSimpleModel(); - return oMessageModel.initByJson(oJsonMessage) ? oMessageModel : null; - }; + MessageSimpleModel.prototype.selected = false; + MessageSimpleModel.prototype.folderFullNameRaw = ''; + MessageSimpleModel.prototype.uid = ''; + MessageSimpleModel.prototype.size = 0; + MessageSimpleModel.prototype.sender = ''; + MessageSimpleModel.prototype.subject = ''; + MessageSimpleModel.prototype.dateInUTC = 0; MessageSimpleModel.prototype.clear = function () { @@ -56,7 +44,7 @@ this.sender = ''; this.subject = ''; - this.dateUTC = 0; + this.dateInUTC = 0; }; /** @@ -77,10 +65,10 @@ this.sender = MessageModel.emailsToLine( MessageModel.initEmailsFromJson(oJsonMessage.From), true); - + this.subject = oJsonMessage.Subject; - this.dateUTC = Utils.pInt(oJsonMessage.DateTimeStampInUTC); + this.dateInUTC = Utils.pInt(oJsonMessage.DateTimeStampInUTC); bResult = true; } @@ -88,6 +76,17 @@ return bResult; }; + /** + * @static + * @param {AjaxJsonMessage} oJsonMessage + * @return {?MessageSimpleModel} + */ + MessageSimpleModel.newInstanceFromJson = function (oJsonMessage) + { + var oMessageModel = new MessageSimpleModel(); + return oMessageModel.initByJson(oJsonMessage) ? oMessageModel : null; + }; + module.exports = MessageSimpleModel; }()); \ No newline at end of file diff --git a/dev/Promises/AbstractAjax.js b/dev/Promises/AbstractAjax.js index 9d6c3e64c..0ef3faf62 100644 --- a/dev/Promises/AbstractAjax.js +++ b/dev/Promises/AbstractAjax.js @@ -5,6 +5,7 @@ var $ = require('$'), + _ = require('_'), Q = require('Q'), Consts = require('Common/Consts'), @@ -12,7 +13,9 @@ Utils = require('Common/Utils'), Links = require('Common/Links'), - Settings = require('Storage/Settings') + Settings = require('Storage/Settings'), + + AbstractBasicPromises = require('Promises/AbstractBasic') ; /** @@ -20,21 +23,18 @@ */ function AbstractAjaxPromises() { - this.oRequests = {}; + AbstractBasicPromises.call(this); + + this.clear(); } - AbstractAjaxPromises.prototype.func = function (fFunc) - { - fFunc(); + _.extend(AbstractAjaxPromises.prototype, AbstractBasicPromises.prototype); - return this; - }; + AbstractAjaxPromises.prototype.oRequests = {}; - AbstractAjaxPromises.prototype.fastResolve = function (mData) + AbstractAjaxPromises.prototype.clear = function () { - var oDeferred = Q.defer(); - oDeferred.resolve(mData); - return oDeferred.promise; + this.oRequests = {}; }; AbstractAjaxPromises.prototype.abort = function (sAction, bClearOnly) @@ -43,7 +43,7 @@ { if (!bClearOnly && this.oRequests[sAction].abort) { - this.oRequests[sAction].__aborted = true; + this.oRequests[sAction].__aborted__ = true; this.oRequests[sAction].abort(); } @@ -71,10 +71,7 @@ oParameters['XToken'] = Settings.settingsGet('Token'); } - if (fTrigger) - { - fTrigger(true); - } + this.setTrigger(fTrigger, true); oH = $.ajax({ 'type': bPost ? 'POST' : 'GET', @@ -96,8 +93,8 @@ { if (oData && oData.Result && sAction === oData.Action) { - oData.Result.__cached__ = bCached; - oDeferred.resolve(oData.Result); + oData.__cached__ = bCached; + oDeferred.resolve(oData); } else if (oData && oData.Action) { @@ -114,7 +111,7 @@ } else if ('abort' === sTextStatus) { - if (!oData || !oData.__aborted) + if (!oData || !oData.__aborted__) { oDeferred.reject(Enums.Notification.AjaxAbort); } @@ -130,10 +127,7 @@ delete self.oRequests[sAction]; } - if (fTrigger) - { - fTrigger(false); - } + self.setTrigger(fTrigger, false); }); if (oH) diff --git a/dev/Promises/AbstractBasic.js b/dev/Promises/AbstractBasic.js new file mode 100644 index 000000000..79996e615 --- /dev/null +++ b/dev/Promises/AbstractBasic.js @@ -0,0 +1,56 @@ + +(function () { + + 'use strict'; + + var + _ = require('_'), + Q = require('Q'), + + Utils = require('Common/Utils') + ; + + /** + * @constructor + */ + function AbstractBasicPromises() + { + this.oPromisesStack = {}; + } + + AbstractBasicPromises.prototype.func = function (fFunc) + { + fFunc(); + return this; + }; + + AbstractBasicPromises.prototype.fastResolve = function (mData) + { + var oDeferred = Q.defer(); + oDeferred.resolve(mData); + return oDeferred.promise; + }; + + AbstractBasicPromises.prototype.fastReject = function (mData) + { + var oDeferred = Q.defer(); + oDeferred.reject(mData); + return oDeferred.promise; + }; + + AbstractBasicPromises.prototype.setTrigger = function (mTrigger, bValue) + { + if (mTrigger) + { + _.each(Utils.isArray(mTrigger) ? mTrigger : [mTrigger], function (fTrigger) { + if (fTrigger) + { + fTrigger(!!bValue); + } + }); + } + }; + + module.exports = AbstractBasicPromises; + +}()); \ No newline at end of file diff --git a/dev/Promises/User/Ajax.js b/dev/Promises/User/Ajax.js index 6bc102a3b..5adf9b5cf 100644 --- a/dev/Promises/User/Ajax.js +++ b/dev/Promises/User/Ajax.js @@ -4,8 +4,20 @@ 'use strict'; var + window = require('window'), _ = require('_'), +// Enums = require('Common/Enums'), +// Utils = require('Common/Utils'), +// Base64 = require('Common/Base64'), +// Cache = require('Common/Cache'), +// +// AppStore = require('Stores/User/App'), +// SettingsStore = require('Stores/User/Settings'), + + MessageSimpleModel = require('Model/MessageSimple'), + + PromisesPopulator = require('Promises/User/Populator'), AbstractAjaxPromises = require('Promises/AbstractAjax') ; @@ -13,17 +25,19 @@ * @constructor * @extends AbstractAjaxPromises */ - function PromisesUserAjax() + function UserAjaxUserPromises() { AbstractAjaxPromises.call(this); this.messageListSimpleHash = ''; this.messageListSimpleCache = null; + + this.sSubSubQuery = '&ss=/'; } - _.extend(PromisesUserAjax.prototype, AbstractAjaxPromises.prototype); + _.extend(UserAjaxUserPromises.prototype, AbstractAjaxPromises.prototype); - PromisesUserAjax.prototype.messageListSimple = function (sFolder, aUids, fTrigger) + UserAjaxUserPromises.prototype.messageListSimple = function (sFolder, aUids, fTrigger) { var self = this, sHash = sFolder + '~' + aUids.join('/'); if (sHash === this.messageListSimpleHash && this.messageListSimpleCache) @@ -35,23 +49,93 @@ .postRequest('MessageListSimple', fTrigger, { 'Folder': sFolder, 'Uids': aUids - }).then(function (aData) { - - var - MessageSimpleModel = require('Model/MessageSimple'), - aResult = _.compact(_.map(aData, function (aItem) { - return MessageSimpleModel.newInstanceFromJson(aItem); - })) - ; + }).then(function (oData) { self.messageListSimpleHash = sHash; - self.messageListSimpleCache = aResult; + self.messageListSimpleCache = _.compact(_.map(oData.Result, function (aItem) { + return MessageSimpleModel.newInstanceFromJson(aItem); + })); - return aResult; + return self.messageListSimpleCache; + + }, function (iError) { + + self.messageListSimpleHash = ''; + self.messageListSimpleCache = null; + + return self.fastReject(iError); }) ; }; - module.exports = new PromisesUserAjax(); + UserAjaxUserPromises.prototype.foldersReload = function (fTrigger) + { + return this.abort('Folders') + .postRequest('Folders', fTrigger).then(function (oData) { + PromisesPopulator.foldersList(oData.Result); + PromisesPopulator.foldersAdditionalParameters(oData.Result); + return true; + }); + }; + + UserAjaxUserPromises.prototype._folders_timeout_ = 0; + UserAjaxUserPromises.prototype.foldersReloadWithTimeout = function (fTrigger) + { + this.setTrigger(fTrigger, true); + + var self = this; + window.clearTimeout(this._folders_timeout_); + this._folders_timeout_ = window.setTimeout(function () { + self.foldersReload(fTrigger); + }, 500); + }; + + + UserAjaxUserPromises.prototype.folderDelete = function (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 + }); + }; + + UserAjaxUserPromises.prototype.folderRename = function (sPrevFolderFullNameRaw, sNewFolderName, fTrigger) + { + return this.postRequest('FolderRename', fTrigger, { + 'Folder': sPrevFolderFullNameRaw, + 'NewFolderName': sNewFolderName + }); + }; + +// UserAjaxUserPromises.prototype.message = function (sFolderFullNameRaw, iUid, fTrigger) +// { +// sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw); +// iUid = Utils.pInt(iUid); +// +// if (Cache.getFolderFromCacheList(sFolderFullNameRaw) && 0 >= iUid) +// { +// return this.abort('Message') +// .getRequest('Message', fTrigger, +// this.sSubSubQuery + Base64.urlsafe_encode([ +// sFolderFullNameRaw, iUid, +// AppStore.projectHash(), +// AppStore.threadsAllowed() && SettingsStore.useThreads() ? '1' : '0' +// ].join(String.fromCharCode(0)))) +// .then(function (oData) { +// return oData; +// }); +// } +// +// return this.fastReject(Enums.Notification.UnknownError); +// }; + + module.exports = new UserAjaxUserPromises(); }()); \ No newline at end of file diff --git a/dev/Promises/User/Populator.js b/dev/Promises/User/Populator.js new file mode 100644 index 000000000..623396bb0 --- /dev/null +++ b/dev/Promises/User/Populator.js @@ -0,0 +1,199 @@ + +(function () { + + 'use strict'; + + var + _ = require('_'), + + Consts = require('Common/Consts'), + Enums = require('Common/Enums'), + Utils = require('Common/Utils'), + Cache = require('Common/Cache'), + + AppStore = require('Stores/User/App'), + FolderStore = require('Stores/User/Folder'), + + Settings = require('Storage/Settings'), + Local = require('Storage/Client'), + + FolderModel = require('Model/Folder'), + + AbstractBasicPromises = require('Promises/AbstractBasic') + ; + + /** + * @constructor + */ + function PromisesUserPopulator() + { + AbstractBasicPromises.call(this); + } + + _.extend(PromisesUserPopulator.prototype, AbstractBasicPromises.prototype); + + /** + * @param {string} sFullNameHash + * @return {boolean} + */ + PromisesUserPopulator.prototype.isFolderExpanded = function (sFullNameHash) + { + var aExpandedList = Local.get(Enums.ClientSideKeyName.ExpandedFolders); + return Utils.isArray(aExpandedList) && -1 !== _.indexOf(aExpandedList, sFullNameHash); + }; + + /** + * @param {string} sFolderFullNameRaw + * @return {string} + */ + PromisesUserPopulator.prototype.normalizeFolder = function (sFolderFullNameRaw) + { + return ('' === sFolderFullNameRaw || Consts.Values.UnuseOptionValue === sFolderFullNameRaw || + null !== Cache.getFolderFromCacheList(sFolderFullNameRaw)) ? sFolderFullNameRaw : ''; + }; + + /** + * @param {string} sNamespace + * @param {Array} aFolders + * @return {Array} + */ + PromisesUserPopulator.prototype.folderResponseParseRec = function (sNamespace, aFolders) + { + var + self = this, + iIndex = 0, + iLen = 0, + oFolder = null, + oCacheFolder = null, + sFolderFullNameRaw = '', + aSubFolders = [], + aList = [] + ; + + for (iIndex = 0, iLen = aFolders.length; iIndex < iLen; iIndex++) + { + oFolder = aFolders[iIndex]; + if (oFolder) + { + sFolderFullNameRaw = oFolder.FullNameRaw; + + oCacheFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw); + if (!oCacheFolder) + { + oCacheFolder = FolderModel.newInstanceFromJson(oFolder); + if (oCacheFolder) + { + Cache.setFolderToCacheList(sFolderFullNameRaw, oCacheFolder); + Cache.setFolderFullNameRaw(oCacheFolder.fullNameHash, sFolderFullNameRaw, oCacheFolder); + } + } + + if (oCacheFolder) + { + oCacheFolder.collapsed(!self.isFolderExpanded(oCacheFolder.fullNameHash)); + + 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); + } + } + + aSubFolders = oFolder['SubFolders']; + if (aSubFolders && 'Collection/FolderCollection' === aSubFolders['@Object'] && + aSubFolders['@Collection'] && Utils.isArray(aSubFolders['@Collection'])) + { + oCacheFolder.subFolders( + this.folderResponseParseRec(sNamespace, aSubFolders['@Collection'])); + } + + aList.push(oCacheFolder); + } + } + } + + return aList; + }; + + PromisesUserPopulator.prototype.foldersList = function (oData) + { + if (oData && 'Collection/FolderCollection' === oData['@Object'] && + oData['@Collection'] && Utils.isArray(oData['@Collection'])) + { + FolderStore.folderList(this.folderResponseParseRec( + Utils.isUnd(oData.Namespace) ? '' : oData.Namespace, oData['@Collection'])); + } + }; + + 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.settingsGet('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')) + { + // TODO Magic Numbers + Settings.settingsSet('SentFolder', oData['SystemFolders'][2] || null); + Settings.settingsSet('DraftFolder', oData['SystemFolders'][3] || null); + Settings.settingsSet('SpamFolder', oData['SystemFolders'][4] || null); + Settings.settingsSet('TrashFolder', oData['SystemFolders'][5] || null); + Settings.settingsSet('ArchiveFolder', oData['SystemFolders'][12] || 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.emptyFunction, { + '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(); + +}()); \ No newline at end of file diff --git a/dev/Remote/User/Ajax.js b/dev/Remote/User/Ajax.js index 9a5b592ff..7e2fabd9e 100644 --- a/dev/Remote/User/Ajax.js +++ b/dev/Remote/User/Ajax.js @@ -721,43 +721,6 @@ }); }; - /** - * @param {?Function} fCallback - * @param {string} sNewFolderName - * @param {string} sParentName - */ - RemoteUserAjax.prototype.folderCreate = function (fCallback, sNewFolderName, sParentName) - { - this.defaultRequest(fCallback, 'FolderCreate', { - 'Folder': sNewFolderName, - 'Parent': sParentName - }, null, '', ['Folders']); - }; - - /** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - */ - RemoteUserAjax.prototype.folderDelete = function (fCallback, sFolderFullNameRaw) - { - this.defaultRequest(fCallback, 'FolderDelete', { - 'Folder': sFolderFullNameRaw - }, null, '', ['Folders']); - }; - - /** - * @param {?Function} fCallback - * @param {string} sPrevFolderFullNameRaw - * @param {string} sNewFolderName - */ - RemoteUserAjax.prototype.folderRename = function (fCallback, sPrevFolderFullNameRaw, sNewFolderName) - { - this.defaultRequest(fCallback, 'FolderRename', { - 'Folder': sPrevFolderFullNameRaw, - 'NewFolderName': sNewFolderName - }, null, '', ['Folders']); - }; - /** * @param {?Function} fCallback * @param {string} sFolderFullNameRaw diff --git a/dev/Settings/User/Folders.js b/dev/Settings/User/Folders.js index 207c456c6..c5812c9ed 100644 --- a/dev/Settings/User/Folders.js +++ b/dev/Settings/User/Folders.js @@ -17,6 +17,7 @@ FolderStore = require('Stores/User/Folder'), + Promises = require('Promises/User/Ajax'), Remote = require('Remote/User/Ajax') ; @@ -69,19 +70,9 @@ { Local.set(Enums.ClientSideKeyName.FoldersLashHash, ''); - FolderStore.foldersRenaming(true); - Remote.folderRename(function (sResult, oData) { - - FolderStore.foldersRenaming(false); - if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) - { - FolderStore.folderList.error( - oData && oData.ErrorCode ? Translator.getNotification(oData.ErrorCode) : Translator.i18n('NOTIFICATIONS/CANT_RENAME_FOLDER')); - } - - require('App/User').folders(); - - }, oFolder.fullNameRaw, sEditName); + require('App/User').foldersPromisesActionHelper( + Promises.folderRename(oFolder.fullNameRaw, sEditName, FolderStore.foldersRenaming), + Enums.Notification.CantRenameFolder); Cache.removeFolderFromCacheList(oFolder.fullNameRaw); @@ -140,19 +131,9 @@ FolderStore.folderList.remove(fRemoveFolder); - FolderStore.foldersDeleting(true); - Remote.folderDelete(function (sResult, oData) { - - FolderStore.foldersDeleting(false); - if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) - { - FolderStore.folderList.error( - oData && oData.ErrorCode ? Translator.getNotification(oData.ErrorCode) : Translator.i18n('NOTIFICATIONS/CANT_DELETE_FOLDER')); - } - - require('App/User').folders(); - - }, oFolderToRemove.fullNameRaw); + require('App/User').foldersPromisesActionHelper( + Promises.folderDelete(oFolderToRemove.fullNameRaw, FolderStore.foldersDeleting), + Enums.Notification.CantDeleteFolder); Cache.removeFolderFromCacheList(oFolderToRemove.fullNameRaw); } diff --git a/dev/Stores/Language.js b/dev/Stores/Language.js index 028813c8a..1d7a274a7 100644 --- a/dev/Stores/Language.js +++ b/dev/Stores/Language.js @@ -4,7 +4,6 @@ 'use strict'; var - _ = require('_'), ko = require('ko'), Utils = require('Common/Utils'), diff --git a/dev/Stores/User/Message.js b/dev/Stores/User/Message.js index d6454fea5..95bb8c688 100644 --- a/dev/Stores/User/Message.js +++ b/dev/Stores/User/Message.js @@ -685,10 +685,6 @@ { this.messageThreadLoading(true); } - else - { - Utils.log('Error: Unknown message request: ' + sFolder + ' ~ ' + sUid + ' [e-102]'); - } if (Enums.Layout.NoPreview === SettingsStore.layout()) { @@ -705,10 +701,6 @@ { this.messageCurrentLoading(true); } - else - { - Utils.log('Error: Unknown message request: ' + oMessage.folderFullNameRaw + ' ~ ' + oMessage.uid + ' [e-101]'); - } } }; diff --git a/dev/Styles/MessageList.less b/dev/Styles/MessageList.less index be52f8696..6d51ce18e 100644 --- a/dev/Styles/MessageList.less +++ b/dev/Styles/MessageList.less @@ -398,7 +398,7 @@ html.rl-no-preview-pane { background-color: #999; color: #fff; border-radius: 6px; - padding: 0px 4px; + padding: 1px 6px 1px 5px; margin-right: 5px; } } diff --git a/dev/View/Popup/FolderCreate.js b/dev/View/Popup/FolderCreate.js index 74eccde79..27d2faba5 100644 --- a/dev/View/Popup/FolderCreate.js +++ b/dev/View/Popup/FolderCreate.js @@ -15,7 +15,7 @@ FolderStore = require('Stores/User/Folder'), - Remote = require('Remote/User/Ajax'), + Promises = require('Promises/User/Ajax'), kn = require('Knoin/Knoin'), AbstractView = require('Knoin/AbstractView') @@ -76,21 +76,9 @@ sParentFolderName = FolderStore.namespace.substr(0, FolderStore.namespace.length - 1); } - FolderStore.foldersCreating(true); - Remote.folderCreate(function (sResult, oData) { - - FolderStore.foldersCreating(false); - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - require('App/User').folders(); - } - else - { - FolderStore.folderList.error( - oData && oData.ErrorCode ? Translator.getNotification(oData.ErrorCode) : Translator.i18n('NOTIFICATIONS/CANT_CREATE_FOLDER')); - } - - }, this.folderName(), sParentFolderName); + require('App/User').foldersPromisesActionHelper( + Promises.folderCreate(this.folderName(), sParentFolderName, FolderStore.foldersCreating), + Enums.Notification.CantCreateFolder); this.cancelCommand(); diff --git a/dev/View/User/MailBox/MessageView.js b/dev/View/User/MailBox/MessageView.js index 812a92066..15b7fe088 100644 --- a/dev/View/User/MailBox/MessageView.js +++ b/dev/View/User/MailBox/MessageView.js @@ -212,7 +212,11 @@ this.viewThreads.trigger = ko.observable(false); this.viewThreadMessages = ko.observableArray([]); - this.viewThreadMessages.hash = ''; + this.viewThreadMessages.error = ko.observable(''); + + this.viewThreadMessages.subscribe(function () { + this.viewThreadMessages.error(''); + }, this); MessageStore.messageLastThreadUidsData.subscribe(function (oData) { if (oData && oData['Uids']) @@ -320,11 +324,11 @@ self.viewThreadMessages(aList); - }, function (iErrorCode) { - - window.alert(Translator.getNotification(iErrorCode)); - - }); + }).fail(function (iErrorCode) { + self.viewThreadMessages([]); + self.viewThreadMessages.error(Translator.getNotification( + iErrorCode, '', Enums.Notification.CantGetMessageList)); + }).done(); } }, function () { diff --git a/package.json b/package.json index ae94f7a0b..86337bfe2 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "RainLoop", "title": "RainLoop Webmail", "version": "1.8.2", - "release": "288", + "release": "289", "description": "Simple, modern & fast web-based email client", "homepage": "http://rainloop.net", "main": "gulpfile.js", @@ -67,5 +67,9 @@ "gulp-beautify": "*", "gulp-plumber": "*", "gulp-concat-util": "*" + }, + "scripts": { + "gulp": "gulp", + "w": "gulp w" } } 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 5b55403c9..7d08991b6 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -5009,6 +5009,9 @@ class Actions */ public function DoFolders() { +// \sleep(1); +// throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::MailServerError); + $sRawKey = (string) $this->GetActionParam('RawKey', ''); if (0 < \strlen($sRawKey)) { @@ -5153,6 +5156,9 @@ class Actions */ public function DoFolderCreate() { +// \sleep(1); +// throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantCreateFolder); + $this->initMailClientConnection(); try @@ -5232,6 +5238,9 @@ class Actions */ public function DoFolderDelete() { +// \sleep(1); +// throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantRenameFolder); + $this->initMailClientConnection(); $sFolderFullNameRaw = $this->GetActionParam('Folder', ''); diff --git a/rainloop/v/0.0.0/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html b/rainloop/v/0.0.0/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html index 52ec0cebb..22d4deb70 100644 --- a/rainloop/v/0.0.0/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html +++ b/rainloop/v/0.0.0/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html @@ -62,6 +62,8 @@