diff --git a/js/background.js b/js/background.js index 700050c9d..994d6b2cb 100644 --- a/js/background.js +++ b/js/background.js @@ -402,10 +402,93 @@ error && error.stack ? error.stack : error ); } finally { + initializeRedux(); start(); } }); + function initializeRedux() { + // Here we set up a full redux store with initial state for our LeftPane Root + const convoCollection = window.getConversations(); + const conversations = convoCollection.map( + conversation => conversation.cachedProps + ); + const initialState = { + conversations: { + conversationLookup: Signal.Util.makeLookup(conversations, 'id'), + }, + user: { + regionCode: window.storage.get('regionCode'), + ourNumber: textsecure.storage.user.getNumber(), + i18n: window.i18n, + }, + }; + + const store = Signal.State.createStore(initialState); + window.reduxStore = store; + + const actions = {}; + window.reduxActions = actions; + + // Binding these actions to our redux store and exposing them allows us to update + // redux when things change in the backbone world. + actions.conversations = Signal.State.bindActionCreators( + Signal.State.Ducks.conversations.actions, + store.dispatch + ); + actions.user = Signal.State.bindActionCreators( + Signal.State.Ducks.user.actions, + store.dispatch + ); + + const { + conversationAdded, + conversationChanged, + conversationRemoved, + removeAllConversations, + messageExpired, + } = actions.conversations; + const { userChanged } = actions.user; + + convoCollection.on('remove', conversation => { + const { id } = conversation || {}; + conversationRemoved(id); + }); + convoCollection.on('add', conversation => { + const { id, cachedProps } = conversation || {}; + conversationAdded(id, cachedProps); + }); + convoCollection.on('change', conversation => { + const { id, cachedProps } = conversation || {}; + conversationChanged(id, cachedProps); + }); + convoCollection.on('reset', removeAllConversations); + + Whisper.events.on('messageExpired', messageExpired); + Whisper.events.on('userChanged', userChanged); + + // In the future this listener will be added by the conversation view itself. But + // because we currently have multiple converations open at once, we install just + // one global handler. + // $(document).on('keydown', event => { + // const { ctrlKey, key } = event; + + // We can add Command-E as the Mac shortcut when we add it to our Electron menus: + // https://stackoverflow.com/questions/27380018/when-cmd-key-is-kept-pressed-keyup-is-not-triggered-for-any-other-key + // For now, it will stay as CTRL-E only + // if (key === 'e' && ctrlKey) { + // const state = store.getState(); + // const selectedId = state.conversations.selectedConversation; + // const conversation = ConversationController.get(selectedId); + + // if (conversation && !conversation.get('isArchived')) { + // conversation.setArchived(true); + // conversation.trigger('unload'); + // } + // } + // }); + } + Whisper.events.on('setupWithImport', () => { const { appView } = window.owsDesktopApp; if (appView) { diff --git a/js/views/inbox_view.js b/js/views/inbox_view.js index c7a5b4bf0..07df7db3c 100644 --- a/js/views/inbox_view.js +++ b/js/views/inbox_view.js @@ -1,13 +1,10 @@ /* global ConversationController, extension, - getConversations, getInboxCollection, i18n, Whisper, - textsecure, Signal - */ // eslint-disable-next-line func-names @@ -105,86 +102,11 @@ click: 'onClick', }, setupLeftPane() { - // Here we set up a full redux store with initial state for our LeftPane Root - const convoCollection = getConversations(); - const conversations = convoCollection.map( - conversation => conversation.cachedProps - ); - const initialState = { - conversations: { - conversationLookup: Signal.Util.makeLookup(conversations, 'id'), - }, - user: { - regionCode: window.storage.get('regionCode'), - ourNumber: textsecure.storage.user.getNumber(), - i18n: window.i18n, - }, - }; - - this.store = Signal.State.createStore(initialState); - window.inboxStore = this.store; this.leftPaneView = new Whisper.ReactWrapperView({ - JSX: Signal.State.Roots.createLeftPane(this.store), + JSX: Signal.State.Roots.createLeftPane(window.reduxStore), className: 'left-pane-wrapper', }); - // Enables our redux store to be updated by backbone events in the outside world - const { - conversationAdded, - conversationChanged, - conversationRemoved, - removeAllConversations, - messageExpired, - openConversationExternal, - } = Signal.State.bindActionCreators( - Signal.State.Ducks.conversations.actions, - this.store.dispatch - ); - const { userChanged } = Signal.State.bindActionCreators( - Signal.State.Ducks.user.actions, - this.store.dispatch - ); - - this.openConversationAction = openConversationExternal; - - // In the future this listener will be added by the conversation view itself. But - // because we currently have multiple converations open at once, we install just - // one global handler. - // $(document).on('keydown', event => { - // const { ctrlKey, key } = event; - - // We can add Command-E as the Mac shortcut when we add it to our Electron menus: - // https://stackoverflow.com/questions/27380018/when-cmd-key-is-kept-pressed-keyup-is-not-triggered-for-any-other-key - // For now, it will stay as CTRL-E only - // if (key === 'e' && ctrlKey) { - // const state = this.store.getState(); - // const selectedId = state.conversations.selectedConversation; - // const conversation = ConversationController.get(selectedId); - - // if (conversation && !conversation.get('isArchived')) { - // conversation.setArchived(true); - // conversation.trigger('unload'); - // } - // } - // }); - - this.listenTo(convoCollection, 'remove', conversation => { - const { id } = conversation || {}; - conversationRemoved(id); - }); - this.listenTo(convoCollection, 'add', conversation => { - const { id, cachedProps } = conversation || {}; - conversationAdded(id, cachedProps); - }); - this.listenTo(convoCollection, 'change', conversation => { - const { id, cachedProps } = conversation || {}; - conversationChanged(id, cachedProps); - }); - this.listenTo(convoCollection, 'reset', removeAllConversations); - - Whisper.events.on('messageExpired', messageExpired); - Whisper.events.on('userChanged', userChanged); - // Finally, add it to the DOM this.$('.left-pane-placeholder').append(this.leftPaneView.el); }, @@ -248,8 +170,9 @@ 'private' ); - if (this.openConversationAction) { - this.openConversationAction(id, messageId); + const { openConversationExternal } = window.reduxActions.conversations; + if (openConversationExternal) { + openConversationExternal(id, messageId); } this.conversation_stack.open(conversation); diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json index 87d2f6424..2f63b380d 100644 --- a/ts/util/lint/exceptions.json +++ b/ts/util/lint/exceptions.json @@ -501,7 +501,7 @@ "rule": "jQuery-$(", "path": "js/views/inbox_view.js", "line": " let $el = this.$(`#${id}`);", - "lineNumber": 30, + "lineNumber": 27, "reasonCategory": "usageTrusted", "updated": "2018-09-19T21:59:32.770Z", "reasonDetail": "Protected from arbitrary input" @@ -510,7 +510,7 @@ "rule": "jQuery-prependTo(", "path": "js/views/inbox_view.js", "line": " $el.prependTo(this.el);", - "lineNumber": 39, + "lineNumber": 36, "reasonCategory": "usageTrusted", "updated": "2018-09-19T18:13:29.628Z", "reasonDetail": "Interacting with already-existing DOM nodes" @@ -519,7 +519,7 @@ "rule": "jQuery-$(", "path": "js/views/inbox_view.js", "line": " this.$('.message').text(message);", - "lineNumber": 51, + "lineNumber": 48, "reasonCategory": "usageTrusted", "updated": "2018-09-19T21:59:32.770Z", "reasonDetail": "Protected from arbitrary input" @@ -528,7 +528,7 @@ "rule": "jQuery-$(", "path": "js/views/inbox_view.js", "line": " el: this.$('.conversation-stack'),", - "lineNumber": 68, + "lineNumber": 65, "reasonCategory": "usageTrusted", "updated": "2018-09-19T21:59:32.770Z", "reasonDetail": "Protected from arbitrary input" @@ -537,7 +537,7 @@ "rule": "jQuery-prependTo(", "path": "js/views/inbox_view.js", "line": " this.appLoadingScreen.$el.prependTo(this.el);", - "lineNumber": 75, + "lineNumber": 72, "reasonCategory": "usageTrusted", "updated": "2018-09-19T18:13:29.628Z", "reasonDetail": "Interacting with already-existing DOM nodes" @@ -546,7 +546,7 @@ "rule": "jQuery-append(", "path": "js/views/inbox_view.js", "line": " .append(this.networkStatusView.render().el);", - "lineNumber": 90, + "lineNumber": 87, "reasonCategory": "usageTrusted", "updated": "2018-09-19T18:13:29.628Z", "reasonDetail": "Interacting with already-existing DOM nodes" @@ -555,25 +555,16 @@ "rule": "jQuery-prependTo(", "path": "js/views/inbox_view.js", "line": " banner.$el.prependTo(this.$el);", - "lineNumber": 94, + "lineNumber": 91, "reasonCategory": "usageTrusted", "updated": "2018-09-19T18:13:29.628Z", "reasonDetail": "Interacting with already-existing DOM nodes" }, - { - "rule": "jQuery-$(", - "path": "js/views/inbox_view.js", - "line": " // $(document).on('keydown', event => {", - "lineNumber": 153, - "reasonCategory": "usageTrusted", - "updated": "2019-04-03T00:43:09.315Z", - "reasonDetail": "Interacting with already-existing DOM nodes" - }, { "rule": "jQuery-$(", "path": "js/views/inbox_view.js", "line": " this.$('.left-pane-placeholder').append(this.leftPaneView.el);", - "lineNumber": 189, + "lineNumber": 111, "reasonCategory": "usageTrusted", "updated": "2019-03-08T23:49:08.796Z", "reasonDetail": "Protected from arbitrary input" @@ -582,7 +573,7 @@ "rule": "jQuery-append(", "path": "js/views/inbox_view.js", "line": " this.$('.left-pane-placeholder').append(this.leftPaneView.el);", - "lineNumber": 189, + "lineNumber": 111, "reasonCategory": "usageTrusted", "updated": "2019-03-08T23:49:08.796Z", "reasonDetail": "Protected from arbitrary input" @@ -591,7 +582,7 @@ "rule": "jQuery-$(", "path": "js/views/inbox_view.js", "line": " if (e && this.$(e.target).closest('.placeholder').length) {", - "lineNumber": 230, + "lineNumber": 152, "reasonCategory": "usageTrusted", "updated": "2019-03-08T23:49:08.796Z", "reasonDetail": "Protected from arbitrary input" @@ -600,7 +591,7 @@ "rule": "jQuery-$(", "path": "js/views/inbox_view.js", "line": " this.$('#header, .gutter').addClass('inactive');", - "lineNumber": 234, + "lineNumber": 156, "reasonCategory": "usageTrusted", "updated": "2019-03-08T23:49:08.796Z", "reasonDetail": "Protected from arbitrary input" @@ -609,7 +600,7 @@ "rule": "jQuery-$(", "path": "js/views/inbox_view.js", "line": " this.$('.conversation-stack').addClass('inactive');", - "lineNumber": 238, + "lineNumber": 160, "reasonCategory": "usageTrusted", "updated": "2019-03-08T23:49:08.796Z", "reasonDetail": "Protected from arbitrary input" @@ -618,7 +609,7 @@ "rule": "jQuery-$(", "path": "js/views/inbox_view.js", "line": " this.$('.conversation:first .menu').trigger('close');", - "lineNumber": 240, + "lineNumber": 162, "reasonCategory": "usageTrusted", "updated": "2019-03-08T23:49:08.796Z", "reasonDetail": "Protected from arbitrary input" @@ -627,7 +618,7 @@ "rule": "jQuery-$(", "path": "js/views/inbox_view.js", "line": " if (e && this.$(e.target).closest('.capture-audio').length > 0) {", - "lineNumber": 259, + "lineNumber": 182, "reasonCategory": "usageTrusted", "updated": "2019-03-08T23:49:08.796Z", "reasonDetail": "Protected from arbitrary input" @@ -636,7 +627,7 @@ "rule": "jQuery-$(", "path": "js/views/inbox_view.js", "line": " this.$('.conversation:first .recorder').trigger('close');", - "lineNumber": 262, + "lineNumber": 185, "reasonCategory": "usageTrusted", "updated": "2019-03-08T23:49:08.796Z", "reasonDetail": "Protected from arbitrary input"