diff --git a/dev/App/Abstract.js b/dev/App/Abstract.js index 3a13d413e..401cdac1f 100644 --- a/dev/App/Abstract.js +++ b/dev/App/Abstract.js @@ -47,7 +47,7 @@ oEvent.originalEvent.lineno, window.location && window.location.toString ? window.location.toString() : '', Globals.$html.attr('class'), - Utils.microtime() - Globals.now + Utils.microtime() - Globals.startMicrotime ); } }); @@ -282,6 +282,8 @@ ko.components.register('TextArea', require('Component/TextArea')); ko.components.register('Radio', require('Component/Radio')); + ko.components.register('x-script', require('Component/Script')); + if (Settings.settingsGet('MaterialDesign') && Globals.bAnimationSupported) { ko.components.register('Checkbox', require('Component/MaterialDesign/Checkbox')); diff --git a/dev/Common/Enums.js b/dev/Common/Enums.js index 966775695..4bf53cc4e 100644 --- a/dev/Common/Enums.js +++ b/dev/Common/Enums.js @@ -15,6 +15,16 @@ 'Unload': 'unload' }; + /** + * @enum {string} + */ + Enums.Focused = { + 'None': 'none', + 'MessageList': 'message-list', + 'MessageView': 'message-view', + 'FolderList': 'folder-list' + }; + /** * @enum {number} */ diff --git a/dev/Common/Globals.js b/dev/Common/Globals.js index 29631d369..1cad8c6c4 100644 --- a/dev/Common/Globals.js +++ b/dev/Common/Globals.js @@ -25,18 +25,13 @@ /** * @type {?} */ - Globals.now = (new window.Date()).getTime(); + Globals.startMicrotime = (new window.Date()).getTime(); /** * @type {?} */ Globals.dropdownVisibility = ko.observable(false).extend({'rateLimit': 0}); - /** - * @type {?} - */ - Globals.tooltipTrigger = ko.observable(false).extend({'rateLimit': 0}); - /** * @type {boolean} */ @@ -258,14 +253,13 @@ }); Globals.keyScopeReal.subscribe(function (sValue) { -// window.console.log(sValue); +// window.console.log('keyScope=' + sValue); // TODO key.setScope(sValue); }); Globals.dropdownVisibility.subscribe(function (bValue) { if (bValue) { - Globals.tooltipTrigger(!Globals.tooltipTrigger()); Globals.keyScope(Enums.KeyState.Menu); } else if (Enums.KeyState.Menu === key.getScope()) diff --git a/dev/Common/Links.js b/dev/Common/Links.js index c6d9473cd..da26296b0 100644 --- a/dev/Common/Links.js +++ b/dev/Common/Links.js @@ -208,14 +208,6 @@ return this.sBase + 'mailbox/' + sInboxFolderName; }; - /** - * @return {string} - */ - Links.prototype.messagePreview = function () - { - return this.sBase + 'mailbox/message-preview'; - }; - /** * @param {string=} sScreenName * @return {string} diff --git a/dev/Common/Selector.js b/dev/Common/Selector.js index 0b6968268..05ebf76bf 100644 --- a/dev/Common/Selector.js +++ b/dev/Common/Selector.js @@ -88,7 +88,7 @@ }, this); - this.selectedItem.extend({'toggleSubscribe': [null, + this.selectedItem = this.selectedItem.extend({'toggleSubscribe': [null, function (oPrev) { if (oPrev) { @@ -102,7 +102,7 @@ } ]}); - this.focusedItem.extend({'toggleSubscribe': [null, + this.focusedItem = this.focusedItem.extend({'toggleSubscribe': [null, function (oPrev) { if (oPrev) { @@ -116,6 +116,8 @@ } ]}); + this.iSelectNextHelper = 0; + this.iFocusedNextHelper = 0; this.oContentVisible = null; this.oContentScrollable = null; @@ -257,6 +259,39 @@ self.focusedItem(self.selectedItem()); } } + + if ((0 !== this.iSelectNextHelper || 0 !== this.iFocusedNextHelper) && 0 < aItems.length && !self.focusedItem()) + { + oTemp = null; + if (0 !== this.iFocusedNextHelper) + { + oTemp = aItems[-1 === this.iFocusedNextHelper ? aItems.length - 1 : 0] || null; + } + + if (!oTemp && 0 !== this.iSelectNextHelper) + { + oTemp = aItems[-1 === this.iSelectNextHelper ? aItems.length - 1 : 0] || null; + } + + if (oTemp) + { + if (0 !== this.iSelectNextHelper) + { + self.selectedItem(oTemp || null); + } + + self.focusedItem(oTemp || null); + + self.scrollToFocused(); + + _.delay(function () { + self.scrollToFocused(); + }, 100); + } + + this.iSelectNextHelper = 0; + this.iFocusedNextHelper = 0; + } } aCache = []; @@ -295,6 +330,12 @@ this.newSelectPosition(Enums.EventKeyCode.Up, false, bForceSelect); }; + Selector.prototype.unselect = function () + { + this.selectedItem(null); + this.focusedItem(null); + }; + Selector.prototype.init = function (oContentVisible, oContentScrollable, sKeyScope) { this.oContentVisible = oContentVisible; @@ -493,7 +534,7 @@ } }); - if (!oResult && bForceSelect && (Enums.EventKeyCode.Down === iEventKeyCode || Enums.EventKeyCode.Up === iEventKeyCode)) + if (!oResult && (Enums.EventKeyCode.Down === iEventKeyCode || Enums.EventKeyCode.Up === iEventKeyCode)) { this.doUpUpOrDownDown(Enums.EventKeyCode.Up === iEventKeyCode); } diff --git a/dev/Component/Abstract.js b/dev/Component/Abstract.js index 8e3175ecb..4b5dfb91b 100644 --- a/dev/Component/Abstract.js +++ b/dev/Component/Abstract.js @@ -39,16 +39,17 @@ * @return {Object} */ AbstractComponent.componentExportHelper = function (ClassObject, sTemplateID) { - return { + var oComponent = { viewModel: { - createViewModel: function(oParams, oCmponentInfo) { + createViewModel: function(oParams, oComponentInfo) { oParams = oParams || {}; oParams.element = null; - if (oCmponentInfo.element) + if (oComponentInfo.element) { - oParams.element = $(oCmponentInfo.element); + oParams.component = oComponentInfo; + oParams.element = $(oComponentInfo.element); require('Common/Translator').i18nToNodes(oParams.element); @@ -60,11 +61,14 @@ return new ClassObject(oParams); } - }, - template: { - element: sTemplateID } }; + + oComponent['template'] = sTemplateID ? { + element: sTemplateID + } : ''; + + return oComponent; }; module.exports = AbstractComponent; diff --git a/dev/Component/Script.js b/dev/Component/Script.js new file mode 100644 index 000000000..3e4ab8c75 --- /dev/null +++ b/dev/Component/Script.js @@ -0,0 +1,38 @@ + +(function () { + + 'use strict'; + + var + _ = require('_'), + + AbstractComponent = require('Component/Abstract') + ; + + /** + * @constructor + * + * @param {Object} oParams + * + * @extends AbstractComponent + */ + function ScriptComponent(oParams) + { + AbstractComponent.call(this); + + if (oParams.component && oParams.component.templateNodes && oParams.element) + { + oParams.element.text(''); + if (oParams.component.templateNodes[0] && oParams.component.templateNodes[0].nodeValue) + { + oParams.element.replaceWith( + $('').text(oParams.component.templateNodes[0].nodeValue)); + } + } + } + + _.extend(ScriptComponent.prototype, AbstractComponent.prototype); + + module.exports = AbstractComponent.componentExportHelper(ScriptComponent); + +}()); diff --git a/dev/External/Opentip.js b/dev/External/Opentip.js new file mode 100644 index 000000000..5063edf5e --- /dev/null +++ b/dev/External/Opentip.js @@ -0,0 +1,38 @@ + +(function () { + + 'use strict'; + + var + window = require('window'), + Opentip = window.Opentip + ; + + Opentip.styles.rainloop = { + 'extends': 'standard', + 'group': 'rainloopTips', + 'fixed': true, + 'target': true, + + 'removeElementsOnHide': true, + + 'background': '#fff', + 'shadow': false, + + 'borderColor': '#999', + 'borderRadius': 2, + 'borderWidth': 1 + }; + + Opentip.styles.rainloopTip = { + 'extends': 'rainloop', + 'group': 'rainloopTips' + }; + + Opentip.styles.rainloopTestTip = { + 'extends': 'rainloop' + }; + + module.exports = Opentip; + +}()); diff --git a/dev/External/ko.js b/dev/External/ko.js index eb2c1d8b4..cbd3279f4 100644 --- a/dev/External/ko.js +++ b/dev/External/ko.js @@ -7,26 +7,15 @@ window = require('window'), _ = require('_'), $ = require('$'), + Opentip = require('Opentip'), - fDisposalTooltipHelper = function (oElement, $oEl, oSubscription) { + fDisposalTooltipHelper = function (oElement) { ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () { - if (oSubscription && oSubscription.dispose) + if (oElement && oElement.__opentip) { - oSubscription.dispose(); + oElement.__opentip.deactivate(); } - - if ($oEl) - { - $oEl.off('click.koTooltip'); - - if ($oEl.tooltip) - { - $oEl.tooltip('destroy'); - } - } - - $oEl = null; }); } ; @@ -37,43 +26,80 @@ var $oEl = null, bi18n = true, - sClass = '', - sPlacement = '', - oSubscription = null, - Globals = require('Common/Globals'), - Translator = require('Common/Translator') + sValue = '', + Translator = null, + Globals = require('Common/Globals') ; if (!Globals.bMobileDevice) { $oEl = $(oElement); - sClass = $oEl.data('tooltip-class') || ''; bi18n = 'on' === ($oEl.data('tooltip-i18n') || 'on'); - sPlacement = $oEl.data('tooltip-placement') || 'top'; + sValue = bi18n ? ko.unwrap(fValueAccessor()) : fValueAccessor()(); - $oEl.tooltip({ - 'delay': { - 'show': 500, - 'hide': 100 - }, - 'html': true, - 'container': 'body', - 'placement': sPlacement, - 'trigger': 'hover', - 'title': function () { - var sValue = bi18n ? ko.unwrap(fValueAccessor()) : fValueAccessor()(); - return '' === sValue || $oEl.is('.disabled') || Globals.dropdownVisibility() ? '' : - '' + (bi18n ? Translator.i18n(sValue) : sValue) + ''; + if (sValue) + { + oElement.__opentip = new Opentip(oElement, { + 'style': 'rainloopTip', + 'element': oElement, + 'tipJoint': $oEl.data('tooltip-join') || 'bottom' + }); + + oElement.__opentip.setContent( + bi18n ? require('Common/Translator').i18n(sValue) : sValue); + + Globals.dropdownVisibility.subscribe(function (bV) { + if (bV) { + oElement.__opentip.deactivate(); + } else { + oElement.__opentip.activate(); + } + }); + + if (bi18n) + { + Translator = require('Common/Translator'); + + oElement.__opentip.setContent(Translator.i18n(sValue)); + + Translator.trigger.subscribe(function () { + oElement.__opentip.setContent(Translator.i18n(sValue)); + }); + + Globals.dropdownVisibility.subscribe(function () { + if (oElement && oElement.__opentip) + { + oElement.__opentip.setContent(require('Common/Translator').i18n(sValue)); + } + }); + } + else + { + oElement.__opentip.setContent(sValue); } - }).on('click.koTooltip', function () { - $oEl.tooltip('hide'); - }); - oSubscription = Globals.tooltipTrigger.subscribe(function () { - $oEl.tooltip('hide'); - }); + fDisposalTooltipHelper(oElement); + } + } + }, + 'update': function (oElement, fValueAccessor) { - fDisposalTooltipHelper(oElement, $oEl, oSubscription); + var + bi18n = true, + sValue = '', + Globals = require('Common/Globals') + ; + + if (!Globals.bMobileDevice && oElement.__opentip) + { + bi18n = 'on' === ($(oElement).data('tooltip-i18n') || 'on'); + sValue = bi18n ? ko.unwrap(fValueAccessor()) : fValueAccessor()(); + + if (sValue) + { + oElement.__opentip.setContent( + bi18n ? require('Common/Translator').i18n(sValue) : sValue); + } } } }; @@ -81,46 +107,59 @@ ko.bindingHandlers.tooltipForTest = { 'init': function (oElement) { - var - $oEl = $(oElement), - oSubscription = null, - Globals = require('Common/Globals') - ; + var $oEl = $(oElement); - $oEl.tooltip({ - 'container': 'body', - 'trigger': 'hover manual', - 'title': function () { - return $oEl.data('tooltip3-data') || ''; + oElement.__opentip = new Opentip(oElement, { + 'style': 'rainloopTestTip', + 'element': oElement, + 'tipJoint': $oEl.data('tooltip-join') || 'top' + }); + + oElement.__opentip.deactivate(); + + $(window.document).on('click', function () { + if (oElement && oElement.__opentip) + { + oElement.__opentip.hide(); } }); - $(window.document).on('click', function () { - $oEl.tooltip('hide'); - }); - - oSubscription = Globals.tooltipTrigger.subscribe(function () { - $oEl.tooltip('hide'); - }); - - fDisposalTooltipHelper(oElement, $oEl, oSubscription); + fDisposalTooltipHelper(oElement); }, 'update': function (oElement, fValueAccessor) { - var sValue = ko.unwrap(fValueAccessor()); - if ('' === sValue) - { - $(oElement).data('tooltip3-data', '').tooltip('hide'); - } - else - { - $(oElement).data('tooltip3-data', sValue); - _.delay(function () { - if ($(oElement).is(':visible')) + var + $oEl = $(oElement), + sValue = ko.unwrap(fValueAccessor()), + oOpenTips = oElement.__opentip + ; + + if (oOpenTips) + { + if ('' === sValue) + { + oOpenTips.hide(); + oOpenTips.setContent(''); + oOpenTips.deactivate(); + } + else + { + if ($oEl.is(':visible')) { - $(oElement).tooltip('show'); + oOpenTips.activate(); + oOpenTips.setContent(sValue); + + _.delay(function () { + oOpenTips.show(); + }, 100); } - }, 100); + else + { + oOpenTips.hide(); + oOpenTips.setContent(''); + oOpenTips.deactivate(); + } + } } } }; @@ -152,6 +191,8 @@ $oEl.find('.dropdown-toggle').dropdown('toggle'); } + $oEl.find('.dropdown-toggle').focus(); + require('Common/Utils').detectDropdownVisibility(); fValueAccessor()(false); } diff --git a/dev/Knoin/Knoin.js b/dev/Knoin/Knoin.js index 4c7910159..c8052eda5 100644 --- a/dev/Knoin/Knoin.js +++ b/dev/Knoin/Knoin.js @@ -198,8 +198,6 @@ Globals.popupVisibilityNames.remove(this.viewModelName); oViewModel.viewModelDom.css('z-index', 2000); - Globals.tooltipTrigger(!Globals.tooltipTrigger()); - _.delay(function () { self.viewModelDom.hide(); }, 300); @@ -288,6 +286,7 @@ var self = this, oScreen = null, + bSameScreen= false, oCross = null ; @@ -311,6 +310,8 @@ if (oScreen && oScreen.__started) { + bSameScreen = this.oCurrentScreen && oScreen === this.oCurrentScreen; + if (!oScreen.__builded) { oScreen.__builded = true; @@ -328,7 +329,7 @@ _.defer(function () { // hide screen - if (self.oCurrentScreen) + if (self.oCurrentScreen && !bSameScreen) { Utils.delegateRun(self.oCurrentScreen, 'onHide'); Utils.delegateRun(self.oCurrentScreen, 'onHideWithDelay', [], 500); @@ -365,7 +366,7 @@ self.oCurrentScreen = oScreen; // show screen - if (self.oCurrentScreen) + if (self.oCurrentScreen && !bSameScreen) { Utils.delegateRun(self.oCurrentScreen, 'onShow'); if (self.oCurrentScreen.onShowTrigger) diff --git a/dev/Screen/User/MailBox.js b/dev/Screen/User/MailBox.js index e98426af3..3c73ae1a1 100644 --- a/dev/Screen/User/MailBox.js +++ b/dev/Screen/User/MailBox.js @@ -14,6 +14,7 @@ Cache = require('Common/Cache'), + AppStore = require('Stores/User/App'), AccountStore = require('Stores/User/Account'), SettingsStore = require('Stores/User/Settings'), FolderStore = require('Stores/User/Folder'), @@ -60,7 +61,9 @@ MailBoxUserScreen.prototype.onShow = function () { this.updateWindowTitle(); - Globals.keyScope(Enums.KeyState.MessageList); + + AppStore.focusedState(Enums.Focused.None); + AppStore.focusedState(Enums.Focused.MessageList); }; /** @@ -69,35 +72,25 @@ * @param {string} sSearch * @param {boolean=} bPreview = false */ - MailBoxUserScreen.prototype.onRoute = function (sFolderHash, iPage, sSearch, bPreview) + MailBoxUserScreen.prototype.onRoute = function (sFolderHash, iPage, sSearch) { - if (Utils.isUnd(bPreview) ? false : !!bPreview) + var + sFolderFullNameRaw = Cache.getFolderFullNameRaw(sFolderHash), + oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw) + ; + + if (oFolder) { - if (Enums.Layout.NoPreview === SettingsStore.layout() && !MessageStore.message()) - { - require('App/User').historyBack(); - } - } - else - { - var - sFolderFullNameRaw = Cache.getFolderFullNameRaw(sFolderHash), - oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw) - ; + FolderStore.currentFolder(oFolder); + MessageStore.messageListPage(iPage); + MessageStore.messageListSearch(sSearch); - if (oFolder) - { - FolderStore.currentFolder(oFolder); - MessageStore.messageListPage(iPage); - MessageStore.messageListSearch(sSearch); +// if (Enums.Layout.NoPreview === SettingsStore.layout() && MessageStore.message()) +// { +// MessageStore.message(null); +// } - if (Enums.Layout.NoPreview === SettingsStore.layout() && MessageStore.message()) - { - MessageStore.message(null); - } - - require('App/User').reloadMessageList(); - } + require('App/User').reloadMessageList(); } }; @@ -147,9 +140,6 @@ { var sInboxFolderName = Cache.getFolderInboxName(), - fNormP = function () { - return [sInboxFolderName, 1, '', true]; - }, fNormS = function (oRequest, oVals) { oVals[0] = Utils.pString(oVals[0]); oVals[1] = Utils.pInt(oVals[1]); @@ -162,7 +152,7 @@ oVals[1] = 1; } - return [decodeURI(oVals[0]), oVals[1], decodeURI(oVals[2]), false]; + return [decodeURI(oVals[0]), oVals[1], decodeURI(oVals[2])]; }, fNormD = function (oRequest, oVals) { oVals[0] = Utils.pString(oVals[0]); @@ -173,7 +163,7 @@ oVals[0] = sInboxFolderName; } - return [decodeURI(oVals[0]), 1, decodeURI(oVals[1]), false]; + return [decodeURI(oVals[0]), 1, decodeURI(oVals[1])]; } ; @@ -181,7 +171,6 @@ [/^([a-zA-Z0-9]+)\/p([1-9][0-9]*)\/(.+)\/?$/, {'normalize_': fNormS}], [/^([a-zA-Z0-9]+)\/p([1-9][0-9]*)$/, {'normalize_': fNormS}], [/^([a-zA-Z0-9]+)\/(.+)\/?$/, {'normalize_': fNormD}], - [/^message-preview$/, {'normalize_': fNormP}], [/^([^\/]*)$/, {'normalize_': fNormS}] ]; }; diff --git a/dev/Settings/User/Filters.js b/dev/Settings/User/Filters.js index b3ed0292f..f5f133299 100644 --- a/dev/Settings/User/Filters.js +++ b/dev/Settings/User/Filters.js @@ -73,10 +73,13 @@ self.haveChanges(false); self.updateList(); } + else if (oData && oData.ErrorCode) + { + self.saveErrorText(oData.ErrorMessageAdditional || Translator.getNotification(oData.ErrorCode)); + } else { - self.saveErrorText(oData && oData.ErrorCode ? Translator.getNotification(oData.ErrorCode) : - Translator.getNotification(Enums.Notification.CantSaveFilters)); + self.saveErrorText(Translator.getNotification(Enums.Notification.CantSaveFilters)); } }, this.filters(), this.filterRaw(), this.filterRaw.active()); @@ -97,6 +100,10 @@ this.filterRaw.error(false); }, this); + this.haveChanges.subscribe(function () { + this.saveErrorText(''); + }, this); + this.filterRaw.active.subscribe(function () { this.haveChanges(true); this.filterRaw.error(false); diff --git a/dev/Stores/User/App.js b/dev/Stores/User/App.js index 71e25c390..fb4a994f6 100644 --- a/dev/Stores/User/App.js +++ b/dev/Stores/User/App.js @@ -6,6 +6,9 @@ var ko = require('ko'), + Enums = require('Common/Enums'), + Globals = require('Common/Globals'), + Settings = require('Storage/Settings'), AppStore = require('Stores/App') @@ -18,6 +21,25 @@ { AppStore.call(this); + this.focusedState = ko.observable(Enums.Focused.None); + + this.focusedState.subscribe(function (mValue) { + + switch (mValue) + { + case Enums.Focused.MessageList: + Globals.keyScope(Enums.KeyState.MessageList); + break; + case Enums.Focused.MessageView: + Globals.keyScope(Enums.KeyState.MessageView); + break; + case Enums.Focused.FolderList: + Globals.keyScope(Enums.KeyState.FolderList); + break; + } + + }, this); + this.projectHash = ko.observable(''); this.threadsAllowed = ko.observable(false); diff --git a/dev/Stores/User/Folder.js b/dev/Stores/User/Folder.js index c04d173e2..dfa5c6b66 100644 --- a/dev/Stores/User/Folder.js +++ b/dev/Stores/User/Folder.js @@ -9,7 +9,6 @@ Enums = require('Common/Enums'), Consts = require('Common/Consts'), - Globals = require('Common/Globals'), Utils = require('Common/Utils'), Cache = require('Common/Cache') @@ -29,7 +28,6 @@ this.namespace = ''; this.folderList = ko.observableArray([]); - this.folderList.focused = ko.observable(false); this.folderList.optimized = ko.observable(false); this.folderList.error = ko.observable(''); @@ -180,17 +178,6 @@ this.spamFolder.subscribe(fSetSystemFolderType(Enums.FolderType.Spam), this); this.trashFolder.subscribe(fSetSystemFolderType(Enums.FolderType.Trash), this); this.archiveFolder.subscribe(fSetSystemFolderType(Enums.FolderType.Archive), this); - - this.folderList.focused.subscribe(function (bValue) { - if (bValue) - { - Globals.keyScope(Enums.KeyState.FolderList); - } - else if (Enums.KeyState.FolderList === Globals.keyScope()) - { - Globals.keyScope(Enums.KeyState.MessageList); - } - }); }; /** diff --git a/dev/Stores/User/Message.js b/dev/Stores/User/Message.js index db4a69c15..54222b153 100644 --- a/dev/Stores/User/Message.js +++ b/dev/Stores/User/Message.js @@ -61,8 +61,6 @@ this.selectorMessageSelected = ko.observable(null); this.selectorMessageFocused = ko.observable(null); - this.message.focused = ko.observable(false); - this.message.viewTrigger = ko.observable(false); this.messageLastThreadUidsData = ko.observable(null); @@ -180,41 +178,22 @@ }, 500)); this.message.subscribe(function (oMessage) { - if (!oMessage) + + if (oMessage) { - this.message.focused(false); + if (Enums.Layout.NoPreview === SettingsStore.layout()) + { + AppStore.focusedState(Enums.Focused.MessageView); + } + } + else + { + AppStore.focusedState(Enums.Focused.MessageList); + this.messageFullScreenMode(false); this.hideMessageBodies(); + } - if (Enums.Layout.NoPreview === SettingsStore.layout() && - -1 < window.location.hash.indexOf('message-preview')) - { - require('App/User').historyBack(); - } - } - else if (Enums.Layout.NoPreview === SettingsStore.layout()) - { - this.message.focused(true); - } - }, this); - - this.message.focused.subscribe(function (bValue) { - if (bValue) - { - FolderStore.folderList.focused(false); - Globals.keyScope(Enums.KeyState.MessageView); - } - else if (Enums.KeyState.MessageView === Globals.keyScope()) - { - if (Enums.Layout.NoPreview === SettingsStore.layout() && this.message()) - { - Globals.keyScope(Enums.KeyState.MessageView); - } - else - { - Globals.keyScope(Enums.KeyState.MessageList); - } - } }, this); this.messageLoading.subscribe(function (bValue) { @@ -671,12 +650,6 @@ this.message(this.staticMessage.populateByMessageListItem(oMessage)); this.populateMessageBody(this.message()); - - if (Enums.Layout.NoPreview === SettingsStore.layout()) - { - kn.setHash(Links.messagePreview(), true); - this.message.focused(true); - } } else { @@ -690,12 +663,6 @@ { this.messageThreadLoading(true); } - - if (Enums.Layout.NoPreview === SettingsStore.layout()) - { - kn.setHash(Links.messagePreview(), true); - this.message.focused(true); - } }; MessageUserStore.prototype.populateMessageBody = function (oMessage) diff --git a/dev/Styles/MessageView.less b/dev/Styles/MessageView.less index 0d74b1651..4489ba028 100644 --- a/dev/Styles/MessageView.less +++ b/dev/Styles/MessageView.less @@ -397,7 +397,7 @@ html.rl-no-preview-pane { background-color: #F5F5F5; color: #555; text-decoration: underline; - border-bottom: 1px dashed #555; + border-top: 1px dashed #555; } } } diff --git a/dev/Styles/_BootstrapFix.less b/dev/Styles/_BootstrapFix.less index e1c7c7dcc..9bb2619b8 100644 --- a/dev/Styles/_BootstrapFix.less +++ b/dev/Styles/_BootstrapFix.less @@ -161,9 +161,6 @@ html.rgba.textshadow { opacity: 1; } - .tooltip-class { - } - .tooltip-inner { max-width: 380px; text-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2); diff --git a/dev/Styles/_End.less b/dev/Styles/_End.less index f5a3a04b2..a0b0e8c4a 100644 --- a/dev/Styles/_End.less +++ b/dev/Styles/_End.less @@ -31,3 +31,10 @@ #rl-content { display: block; } + +.opentip-container { + z-index: 2001 !important; + .ot-content { + font-size: 13px; + } +} diff --git a/dev/View/User/AbstractSystemDropDown.js b/dev/View/User/AbstractSystemDropDown.js index e8a5ac5f6..8344185ac 100644 --- a/dev/View/User/AbstractSystemDropDown.js +++ b/dev/View/User/AbstractSystemDropDown.js @@ -13,6 +13,7 @@ Links = require('Common/Links'), AccountStore = require('Stores/User/Account'), + MessageStore = require('Stores/User/Message'), Settings = require('Storage/Settings'), @@ -88,6 +89,8 @@ key('`', [Enums.KeyState.MessageList, Enums.KeyState.MessageView, Enums.KeyState.Settings], function () { if (self.viewModelVisibility()) { + MessageStore.messageFullScreenMode(false); + self.accountMenuDropdownTrigger(true); } }); diff --git a/dev/View/User/MailBox/FolderList.js b/dev/View/User/MailBox/FolderList.js index 4c644bd51..7004b0fb3 100644 --- a/dev/View/User/MailBox/FolderList.js +++ b/dev/View/User/MailBox/FolderList.js @@ -52,6 +52,10 @@ this.allowContacts = !!AppStore.contactsIsAllowed(); + this.folderListFocused = ko.computed(function () { + return Enums.Focused.FolderList === AppStore.focusedState(); + }); + kn.constructorEnd(this); } @@ -144,7 +148,7 @@ var $items = $('.b-folders .e-item .e-link:not(.hidden).focused', oDom); if ($items.length && $items[0]) { - FolderStore.folderList.focused(false); + AppStore.focusedState(Enums.Focused.MessageList); $items.click(); } @@ -168,13 +172,13 @@ }); key('esc, tab, shift+tab, right', Enums.KeyState.FolderList, function () { - FolderStore.folderList.focused(false); + AppStore.focusedState(Enums.Focused.MessageList); return false; }); - FolderStore.folderList.focused.subscribe(function (bValue) { + AppStore.focusedState.subscribe(function (mValue) { $('.b-folders .e-item .e-link.focused', oDom).removeClass('focused'); - if (bValue) + if (Enums.Focused.FolderList === mValue) { $('.b-folders .e-item .e-link.selected', oDom).addClass('focused'); } diff --git a/dev/View/User/MailBox/MessageList.js b/dev/View/User/MailBox/MessageList.js index 995e81fa3..977895412 100644 --- a/dev/View/User/MailBox/MessageList.js +++ b/dev/View/User/MailBox/MessageList.js @@ -4,6 +4,7 @@ 'use strict'; var + window = require('window'), _ = require('_'), $ = require('$'), ko = require('ko'), @@ -22,6 +23,7 @@ Cache = require('Common/Cache'), + AppStore = require('Stores/User/App'), QuotaStore = require('Stores/User/Quota'), SettingsStore = require('Stores/User/Settings'), FolderStore = require('Stores/User/Folder'), @@ -53,7 +55,9 @@ this.message = MessageStore.message; this.messageList = MessageStore.messageList; this.messageListDisableAutoSelect = MessageStore.messageListDisableAutoSelect; + this.folderList = FolderStore.folderList; + this.selectorMessageSelected = MessageStore.selectorMessageSelected; this.selectorMessageFocused = MessageStore.selectorMessageFocused; this.isMessageSelected = MessageStore.isMessageSelected; @@ -187,6 +191,10 @@ return this.isSpamFolder() && !this.isSpamDisabled() && !this.isDraftFolder() && !this.isSentFolder(); }, this); + this.messageListFocused = ko.computed(function () { + return Enums.Focused.MessageList === AppStore.focusedState(); + }); + this.canBeMoved = this.hasCheckedOrSelectedLines; this.clearCommand = Utils.createCommand(this, function () { @@ -255,15 +263,16 @@ return this.useAutoSelect(); }, this)); -// this.selector.on('onUpUpOrDownDown', _.bind(function (bV) { -// }, this)); + this.selector.on('onUpUpOrDownDown', _.bind(function (bV) { + this.goToUpUpOrDownDown(bV); + }, this)); Events - .sub('mailbox.message-list.selector.go-down', function () { - this.selector.goDown(true); + .sub('mailbox.message-list.selector.go-down', function (bSelect) { + this.selector.goDown(bSelect); }, this) - .sub('mailbox.message-list.selector.go-up', function () { - this.selector.goUp(true); + .sub('mailbox.message-list.selector.go-up', function (bSelect) { + this.selector.goUp(bSelect); }, this) ; @@ -282,6 +291,67 @@ */ MessageListMailBoxUserView.prototype.emptySubjectValue = ''; + MessageListMailBoxUserView.prototype.iGoToUpUpOrDownDownTimeout = 0; + + MessageListMailBoxUserView.prototype.goToUpUpOrDownDown = function (bUp) + { + var self = this; + + 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 (oCurrent) + { + oNext = oItem; + } + + if (oItem.current) + { + oCurrent = oItem; + oPrev = oTemp; + } + + if (oNext) + { + return true; + } + + oTemp = oItem; + } + + 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); + } + + }, 350); + }; + MessageListMailBoxUserView.prototype.useAutoSelect = function () { if (this.messageListDisableAutoSelect()) @@ -534,6 +604,18 @@ } }; + MessageListMailBoxUserView.prototype.gotoPage = function (oPage) + { + if (oPage) + { + kn.setHash(Links.mailBox( + FolderStore.currentFolderFullNameHash(), + oPage.value, + MessageStore.messageListSearch() + )); + } + }; + MessageListMailBoxUserView.prototype.onBuild = function (oDom) { var self = this; @@ -545,21 +627,13 @@ oDom .on('click', '.messageList .b-message-list-wrapper', function () { - if (self.message.focused()) + if (Enums.Focused.MessageView === AppStore.focusedState()) { - self.message.focused(false); + AppStore.focusedState(Enums.Focused.MessageList); } }) .on('click', '.e-pagenator .e-page', function () { - var oPage = ko.dataFor(this); - if (oPage) - { - kn.setHash(Links.mailBox( - FolderStore.currentFolderFullNameHash(), - oPage.value, - MessageStore.messageListSearch() - )); - } + self.gotoPage(ko.dataFor(this)); }) .on('click', '.messageList .checkboxCkeckAll', function () { self.checkAll(!self.checkAll()); @@ -691,11 +765,11 @@ key('tab, shift+tab, left, right', Enums.KeyState.MessageList, function (event, handler) { if (event && handler && ('shift+tab' === handler.shortcut || 'left' === handler.shortcut)) { - FolderStore.folderList.focused(true); + AppStore.focusedState(Enums.Focused.FolderList); } else if (self.message()) { - self.message.focused(true); + AppStore.focusedState(Enums.Focused.MessageView); } return false; diff --git a/dev/View/User/MailBox/MessageView.js b/dev/View/User/MailBox/MessageView.js index 7f04ec38a..2fffa593d 100644 --- a/dev/View/User/MailBox/MessageView.js +++ b/dev/View/User/MailBox/MessageView.js @@ -21,6 +21,7 @@ Cache = require('Common/Cache'), + AppStore = require('Stores/User/App'), SettingsStore = require('Stores/User/Settings'), AccountStore = require('Stores/User/Account'), FolderStore = require('Stores/User/Folder'), @@ -98,6 +99,12 @@ this.moreDropdownTrigger = ko.observable(false); this.messageDomFocused = ko.observable(false).extend({'rateLimit': 0}); + // TODO +// ko.computed(function () { +// window.console.log('focus:' + AppStore.focusedState() + ', dom:' + +// this.messageDomFocused() + ', key:' + Globals.keyScope() + ' ~ ' + Globals.keyScopeReal()); +// }, this).extend({'throttle': 1}); + this.messageVisibility = ko.computed(function () { return !this.messageLoadingThrottle() && !!this.message(); }, this); @@ -341,13 +348,6 @@ !this.messageListOfThreadsLoading(); }); - this.threadsDropdownTrigger.subscribe(function (bValue) { - if (bValue && this.message()) - { - this.threadListCommand(); - } - }, this); - // PGP this.viewPgpPassword = ko.observable(''); this.viewPgpSignedVerifyStatus = ko.computed(function () { @@ -480,12 +480,28 @@ this.messageLoadingThrottle.subscribe(Utils.windowResizeCallback); + this.messageFocused = ko.computed(function () { + return Enums.Focused.MessageView === AppStore.focusedState(); + }); + + this.messageListAndMessageViewLoading = ko.computed(function () { + return MessageStore.messageListCompleteLoadingThrottle() || MessageStore.messageLoadingThrottle(); + }); + this.goUpCommand = Utils.createCommand(this, function () { - Events.pub('mailbox.message-list.selector.go-up'); + Events.pub('mailbox.message-list.selector.go-up', [ + Enums.Layout.NoPreview === this.layout() ? !!this.message() : true + ]); + }, function () { + return !this.messageListAndMessageViewLoading(); }); this.goDownCommand = Utils.createCommand(this, function () { - Events.pub('mailbox.message-list.selector.go-down'); + Events.pub('mailbox.message-list.selector.go-down', [ + Enums.Layout.NoPreview === this.layout() ? !!this.message() : true + ]); + }, function () { + return !this.messageListAndMessageViewLoading(); }); Events.sub('mailbox.message-view.toggle-full-screen', function () { @@ -604,9 +620,9 @@ ; this.fullScreenMode.subscribe(function (bValue) { - if (bValue) + if (bValue && self.message()) { - self.message.focused(true); + AppStore.focusedState(Enums.Focused.MessageView); } }, this); @@ -718,8 +734,23 @@ oEvent.stopPropagation(); } }) - .on('click', '.thread-list .more-threads', function () { + .on('click', '.thread-list .more-threads', function (e) { + + var oLast = null; + if (!e || 0 === e.clientX) // probably enter + { + // It's a bad bad hack :( + oLast = $('.thread-list .e-item.thread-list-message.real-msg.more-that:first a.e-link', oDom); + } + self.viewThreadMessages.showMore(true); + self.threadsDropdownTrigger(true); + + if (oLast) + { + oLast.focus(); + } + return false; }) .on('click', '.thread-list .thread-list-message', function () { @@ -745,28 +776,16 @@ }) ; - this.message.focused.subscribe(function (bValue) { - if (bValue && !Utils.inFocus()) { - this.messageDomFocused(true); - } else { - this.messageDomFocused(false); + AppStore.focusedState.subscribe(function (sValue) { + if (Enums.Focused.MessageView !== sValue) + { this.scrollMessageToTop(); this.scrollMessageToLeft(); } }, this); - this.messageDomFocused.subscribe(function (bValue) { - if (!bValue && Enums.KeyState.MessageView === Globals.keyScope()) - { - this.message.focused(false); - } - }, this); - - Globals.keyScope.subscribe(function (sValue) { - if (Enums.KeyState.MessageView === sValue && this.message.focused()) - { - this.messageDomFocused(true); - } + Globals.keyScopeReal.subscribe(function (sValue) { + this.messageDomFocused(Enums.KeyState.MessageView === sValue && !Utils.inFocus()); }, this); this.oMessageScrollerDom = oDom.find('.messageItem .content'); @@ -801,7 +820,7 @@ if (Enums.Layout.NoPreview !== this.layout()) { - this.message.focused(false); + AppStore.focusedState(Enums.Focused.MessageList); } } else if (Enums.Layout.NoPreview === this.layout()) @@ -810,7 +829,7 @@ } else { - this.message.focused(false); + AppStore.focusedState(Enums.Focused.MessageList); } return false; @@ -878,9 +897,10 @@ }); key('t', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { - if (MessageStore.message()) + if (MessageStore.message() && self.viewThreadsControlVisibility()) { self.threadsDropdownTrigger(true); + self.threadListCommand(); return false; } }); @@ -943,11 +963,11 @@ return true; } - self.message.focused(false); + AppStore.focusedState(Enums.Focused.MessageList); } else { - self.message.focused(false); + AppStore.focusedState(Enums.Focused.MessageList); } } else if (self.message() && Enums.Layout.NoPreview === self.layout() && event && handler && 'left' === handler.shortcut) diff --git a/gulpfile.js b/gulpfile.js index f80806e5a..d60eeb45d 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -99,6 +99,7 @@ cfg.paths.css = { 'vendors/jquery-letterfx/jquery-letterfx.min.css', 'vendors/simple-pace/styles.css', 'vendors/inputosaurus/inputosaurus.css', + 'vendors/opentip/opentip.css', 'vendors/photoswipe/photoswipe.css', 'vendors/photoswipe/default-skin/default-skin.css', 'vendors/flags/flags-fixed.css', @@ -169,6 +170,7 @@ cfg.paths.js = { 'vendors/jua/jua.min.js', 'vendors/buzz/buzz.min.js', 'vendors/Q/q.min.js', + 'vendors/opentip/opentip-jquery.min.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 911feddc9..5f000ca45 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "RainLoop", "title": "RainLoop Webmail", - "version": "1.8.2", - "release": "291", + "version": "1.8.3", + "release": "292", "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/RainLoop/Actions.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php index be951719b..02219378f 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -5418,7 +5418,7 @@ class Actions */ public function DoMessageList() { -// \sleep(2); +// \sleep(1); // throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList); $sFolder = ''; diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Filters.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Filters.php index b10ab578d..ce256cbe4 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Filters.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Filters.php @@ -60,6 +60,12 @@ class Filters extends \RainLoop\Providers\AbstractProvider { throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ConnectionError, $oException); } + catch (\MailSo\Sieve\Exceptions\NegativeResponseException $oException) + { + throw new \RainLoop\Exceptions\ClientException( + \RainLoop\Notifications::ClientViewError, $oException, + \implode("\r\n", $oException->GetResponses())); + } catch (\Exception $oException) { throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSaveFilters, $oException); diff --git a/rainloop/v/0.0.0/app/templates/Views/Common/PopupsLanguages.html b/rainloop/v/0.0.0/app/templates/Views/Common/PopupsLanguages.html index 690cb3fab..898d563b0 100644 --- a/rainloop/v/0.0.0/app/templates/Views/Common/PopupsLanguages.html +++ b/rainloop/v/0.0.0/app/templates/Views/Common/PopupsLanguages.html @@ -8,7 +8,7 @@