Removes some Backbone views

This commit is contained in:
Josh Perez 2021-06-17 17:15:09 -04:00 committed by GitHub
parent 93bc094342
commit 94d116c621
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 160 additions and 656 deletions

View file

@ -61,7 +61,6 @@
<script type='text/x-tmpl-mustache' id='two-column'>
<div class='module-title-bar-drag-area'></div>
<div class='call-manager-placeholder'></div>
<div class='inbox-container'>
<div class='gutter'>
<div class='left-pane-placeholder'></div>
@ -120,10 +119,6 @@
<button class='finish' tabIndex='1'><span class='icon'></span></button>
</script>
<script type='text/x-tmpl-mustache' id='safety-number-change-dialog'>
<div class='safety-number-change-dialog-wrapper'></div>
</script>
<script type='text/x-tmpl-mustache' id='identicon-svg'>
<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'>
<circle cx='50' cy='50' r='40' fill='{{ color }}' />
@ -342,18 +337,13 @@
<script type='text/javascript' src='js/expiring_tap_to_view_messages.js'></script>
<script type='text/javascript' src='js/views/react_wrapper_view.js'></script>
<script type='text/javascript' src='js/views/list_view.js'></script>
<script type='text/javascript' src='js/views/contact_list_view.js'></script>
<script type='text/javascript' src='js/views/key_verification_view.js'></script>
<script type='text/javascript' src='js/views/group_member_list_view.js'></script>
<script type='text/javascript' src='js/views/recorder_view.js'></script>
<script type='text/javascript' src='js/views/inbox_view.js'></script>
<script type='text/javascript' src='ts/shims/showConfirmationDialog.js'></script>
<script type='text/javascript' src='js/views/identicon_svg_view.js'></script>
<script type='text/javascript' src='js/views/install_view.js'></script>
<script type='text/javascript' src='js/views/banner_view.js'></script>
<script type="text/javascript" src="js/views/phone-input-view.js"></script>
<script type='text/javascript' src='js/views/safety_number_change_dialog_view.js'></script>
<script type='text/javascript' src='js/views/standalone_registration_view.js'></script>
<script type='text/javascript' src='js/views/clear_data_view.js'></script>

View file

@ -51,9 +51,6 @@ const {
} = require('../../ts/components/conversation/MessageDetail');
const { Quote } = require('../../ts/components/conversation/Quote');
const { ProgressModal } = require('../../ts/components/ProgressModal');
const {
SafetyNumberChangeDialog,
} = require('../../ts/components/SafetyNumberChangeDialog');
const {
StagedLinkPreview,
} = require('../../ts/components/conversation/StagedLinkPreview');
@ -79,13 +76,9 @@ const {
createConversationHeader,
} = require('../../ts/state/roots/createConversationHeader');
const { createApp } = require('../../ts/state/roots/createApp');
const { createCallManager } = require('../../ts/state/roots/createCallManager');
const {
createForwardMessageModal,
} = require('../../ts/state/roots/createForwardMessageModal');
const {
createGlobalModalContainer,
} = require('../../ts/state/roots/createGlobalModalContainer');
const {
createGroupLinkManagement,
} = require('../../ts/state/roots/createGroupLinkManagement');
@ -347,7 +340,6 @@ exports.setup = (options = {}) => {
MessageDetail,
Quote,
ProgressModal,
SafetyNumberChangeDialog,
StagedLinkPreview,
DisappearingTimeDialog,
Types: {
@ -357,14 +349,12 @@ exports.setup = (options = {}) => {
const Roots = {
createApp,
createCallManager,
createChatColorPicker,
createCompositionArea,
createContactModal,
createConversationDetails,
createConversationHeader,
createForwardMessageModal,
createGlobalModalContainer,
createGroupLinkManagement,
createGroupV1MigrationModal,
createGroupV2JoinModal,

View file

@ -1,38 +0,0 @@
// Copyright 2017-2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
/* global Whisper, $ */
// eslint-disable-next-line func-names
(function () {
window.Whisper = window.Whisper || {};
Whisper.BannerView = Whisper.View.extend({
className: 'banner',
template: () => $('#banner').html(),
events: {
'click .dismiss': 'onDismiss',
'click .body': 'onClick',
},
initialize(options) {
this.message = options.message;
this.callbacks = {
onDismiss: options.onDismiss,
onClick: options.onClick,
};
this.render();
},
render_attributes() {
return {
message: this.message,
};
},
onDismiss(e) {
this.callbacks.onDismiss();
e.stopPropagation();
},
onClick() {
this.callbacks.onClick();
},
});
})();

View file

@ -1,49 +0,0 @@
// Copyright 2015-2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
/* global Whisper, textsecure, $ */
// eslint-disable-next-line func-names
(function () {
window.Whisper = window.Whisper || {};
Whisper.ContactListView = Whisper.ListView.extend({
tagName: 'div',
itemView: Whisper.View.extend({
tagName: 'div',
className: 'contact',
template: () => $('#contact').html(),
initialize(options) {
this.ourNumber = textsecure.storage.user.getNumber();
this.listenBack = options.listenBack;
this.loading = false;
this.conversation = options.conversation;
this.listenTo(this.model, 'change', this.render);
},
render() {
if (this.contactView) {
this.contactView.remove();
this.contactView = null;
}
const formattedContact = this.model.format();
this.contactView = new Whisper.ReactWrapperView({
className: 'contact-wrapper',
Component: window.Signal.Components.ContactListItem,
props: {
...formattedContact,
onClick: () =>
this.conversation.trigger(
'show-contact-modal',
formattedContact.id
),
},
});
this.$el.append(this.contactView.el);
return this;
},
}),
});
})();

View file

@ -1,42 +0,0 @@
// Copyright 2015-2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
/* global Whisper, i18n, $ */
// eslint-disable-next-line func-names
(function () {
window.Whisper = window.Whisper || {};
Whisper.GroupMemberList = Whisper.View.extend({
className: 'group-member-list panel',
template: () => $('#group-member-list').html(),
initialize(options) {
this.needVerify = options.needVerify;
this.render();
this.member_list_view = new Whisper.ContactListView({
collection: this.model,
className: 'members',
toInclude: {
listenBack: options.listenBack,
conversation: options.conversation,
},
});
this.member_list_view.render();
this.$('.container').append(this.member_list_view.el);
},
render_attributes() {
let summary;
if (this.needVerify) {
summary = i18n('membersNeedingVerification');
}
return {
members: i18n('groupMembers'),
summary,
};
},
});
})();

View file

@ -137,8 +137,6 @@
this.startConnectionListener();
} else {
this.setupLeftPane();
this.setupCallManagerUI();
this.setupGlobalModalContainer();
}
Whisper.events.on('pack-install-failed', () => {
@ -155,28 +153,6 @@
events: {
click: 'onClick',
},
setupCallManagerUI() {
if (this.callManagerView) {
return;
}
this.callManagerView = new Whisper.ReactWrapperView({
className: 'call-manager-wrapper',
JSX: Signal.State.Roots.createCallManager(window.reduxStore),
});
this.$('.call-manager-placeholder').append(this.callManagerView.el);
},
setupGlobalModalContainer() {
if (this.globalModalContainerView) {
return;
}
this.globalModalContainerView = new Whisper.ReactWrapperView({
JSX: Signal.State.Roots.createGlobalModalContainer(window.reduxStore),
});
const node = document.querySelector('.inbox-container');
if (node) {
node.appendChild(this.globalModalContainerView.el);
}
},
setupLeftPane() {
if (this.leftPaneView) {
return;
@ -217,8 +193,6 @@
},
onEmpty() {
this.setupLeftPane();
this.setupCallManagerUI();
this.setupGlobalModalContainer();
const view = this.appLoadingScreen;
if (view) {
@ -241,14 +215,6 @@
this.$('#header, .gutter').addClass('inactive');
this.$('.conversation-stack').removeClass('inactive');
},
focusHeader() {
this.$('.conversation-stack').addClass('inactive');
this.$('#header, .gutter').removeClass('inactive');
this.$('.conversation:first .menu').trigger('close');
},
reloadBackgroundPage() {
window.location.reload();
},
closeRecording(e) {
if (e && this.$(e.target).closest('.capture-audio').length > 0) {
return;

View file

@ -1,43 +0,0 @@
// Copyright 2014-2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
/* global Backbone, Whisper, _ */
// eslint-disable-next-line func-names
(function () {
window.Whisper = window.Whisper || {};
/*
* Generic list view that watches a given collection, wraps its members in
* a given child view and adds the child view elements to its own element.
*/
Whisper.ListView = Backbone.View.extend({
tagName: 'ul',
itemView: Backbone.View,
initialize(options) {
this.options = options || {};
this.listenTo(this.collection, 'add', this.addOne);
this.listenTo(this.collection, 'reset', this.addAll);
},
addOne(model) {
if (this.itemView) {
const options = _.extend({}, this.options.toInclude, { model });
// eslint-disable-next-line new-cap
const view = new this.itemView(options);
this.$el.append(view.render().el);
this.$el.trigger('add');
}
},
addAll() {
this.$el.html('');
this.collection.each(this.addOne, this);
},
render() {
this.addAll();
return this;
},
});
})();

View file

@ -1,41 +0,0 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
/* global Whisper, Signal, $ */
// eslint-disable-next-line func-names
(function () {
window.Whisper = window.Whisper || {};
Whisper.SafetyNumberChangeDialogView = Whisper.View.extend({
template: () => $('#safety-number-change-dialog').html(),
initialize(options) {
const dialog = new Whisper.ReactWrapperView({
Component: window.Signal.Components.SafetyNumberChangeDialog,
props: {
confirmText: options.confirmText,
contacts: options.contacts.map(contact => contact.format()),
i18n: window.i18n,
onCancel: () => {
dialog.remove();
this.remove();
options.reject();
},
onConfirm: () => {
dialog.remove();
this.remove();
options.resolve();
},
renderSafetyNumber(props) {
return Signal.State.Roots.createSafetyNumberViewer(
window.reduxStore,
props
);
},
},
});
this.$('.safety-number-change-dialog-wrapper').append(dialog.el);
},
});
})();

View file

@ -43,7 +43,6 @@
<script type='text/x-tmpl-mustache' id='two-column'>
<div class='module-title-bar-drag-area'></div>
<div class='call-manager-placeholder'></div>
<div class='inbox-container'>
<div class='gutter'>
<div class='left-pane-placeholder'></div>
@ -92,30 +91,14 @@
<script type='text/x-tmpl-mustache' id='conversation'>
<div class='conversation-header'></div>
<div class='main panel'>
<div class='discussion-container'>
<div class='bar-container hide'>
<div class='bar active progress-bar-striped progress-bar'></div>
</div>
</div>
<div class='timeline-placeholder' aria-live='polite'></div>
<div class='bottom-bar' id='footer'>
<div class='emoji-panel-container'></div>
<div class='attachment-list'></div>
<div class='compose'>
<form class='send clearfix file-input'>
<div class='flex'>
<button class='emoji'></button>
<textarea class='send-message' placeholder='{{ send-message }}' rows='1' dir='auto'></textarea>
<div class='capture-audio'>
<button class='microphone'></button>
</div>
<div class='choose-file'>
<button class='paperclip thumbnail'></button>
<input type='file' class='file-input' multiple='multiple'>
</div>
</div>
</form>
</div>
<div class='compose'>
<form class='send clearfix file-input'>
<input type="file" class="file-input" multiple="multiple">
<div class='composition-area-placeholder'></div>
</form>
</div>
</div>
</div>
</script>
@ -131,10 +114,6 @@
<button class='close'><span class='icon'></span></button>
</script>
<script type='text/x-tmpl-mustache' id='safety-number-change-dialog'>
<div class='safety-number-change-dialog-wrapper'></div>
</script>
<script type='text/x-tmpl-mustache' id='identicon-svg'>
<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'>
<circle cx='50' cy='50' r='40' fill='{{ color }}' />

View file

@ -1,26 +0,0 @@
// Copyright 2014-2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
/* global Backbone, Whisper */
describe('ListView', () => {
let collection;
beforeEach(() => {
collection = new Backbone.Collection();
});
it('should add children to the list element as they are added to the collection', () => {
const view = new Whisper.ListView({ collection });
collection.add('hello');
assert.equal(view.$el.children().length, 1);
collection.add('world');
assert.equal(view.$el.children().length, 2);
});
it('should add all the children to the list element on reset', () => {
const view = new Whisper.ListView({ collection });
collection.reset(['goodbye', 'world']);
assert.equal(view.$el.children().length, 2);
});
});

View file

@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect } from 'react';
import classNames from 'classnames';
import { AppViewType } from '../state/ducks/app';
@ -10,12 +10,16 @@ import { ThemeType } from '../types/Util';
export type PropsType = {
appView: AppViewType;
hasInitialLoadCompleted: boolean;
renderCallManager: () => JSX.Element;
renderGlobalModalContainer: () => JSX.Element;
theme: ThemeType;
};
export const App = ({
appView,
hasInitialLoadCompleted,
renderCallManager,
renderGlobalModalContainer,
theme,
}: PropsType): JSX.Element => {
let contents;
@ -28,6 +32,20 @@ export const App = ({
contents = <Inbox hasInitialLoadCompleted={hasInitialLoadCompleted} />;
}
// This is here so that themes are properly applied to anything that is
// created in a portal and exists outside of the <App /> container.
useEffect(() => {
document.body.classList.remove('light-theme');
document.body.classList.remove('dark-theme');
if (theme === ThemeType.dark) {
document.body.classList.add('dark-theme');
}
if (theme === ThemeType.light) {
document.body.classList.add('light-theme');
}
}, [theme]);
return (
<div
className={classNames({
@ -36,6 +54,8 @@ export const App = ({
'dark-theme': theme === ThemeType.dark,
})}
>
{renderGlobalModalContainer()}
{renderCallManager()}
{contents}
</div>
);

View file

@ -19,14 +19,13 @@ export type GroupV2Membership = {
export type Props = {
canAddNewMembers: boolean;
i18n: LocalizerType;
maxShownMemberCount?: number;
memberships: Array<GroupV2Membership>;
showContactModal: (conversationId: string) => void;
startAddingNewMembers: () => void;
i18n: LocalizerType;
startAddingNewMembers?: () => void;
};
const MAX_MEMBER_COUNT = 5;
const collator = new Intl.Collator(undefined, { sensitivity: 'base' });
function sortConversationTitles(
left: GroupV2Membership,
@ -68,18 +67,20 @@ function sortMemberships(
export const ConversationDetailsMembershipList: React.ComponentType<Props> = ({
canAddNewMembers,
i18n,
maxShownMemberCount = 5,
memberships,
showContactModal,
startAddingNewMembers,
i18n,
}) => {
const [showAllMembers, setShowAllMembers] = React.useState<boolean>(false);
const sortedMemberships = sortMemberships(memberships);
const shouldHideRestMembers = sortedMemberships.length - MAX_MEMBER_COUNT > 1;
const shouldHideRestMembers =
sortedMemberships.length - maxShownMemberCount > 1;
const membersToShow =
shouldHideRestMembers && !showAllMembers
? MAX_MEMBER_COUNT
? maxShownMemberCount
: sortedMemberships.length;
return (
@ -94,7 +95,7 @@ export const ConversationDetailsMembershipList: React.ComponentType<Props> = ({
<div className="module-conversation-details-membership-list__add-members-icon" />
}
label={i18n('ConversationDetailsMembershipList--add-members')}
onClick={startAddingNewMembers}
onClick={() => startAddingNewMembers?.()}
/>
)}
{sortedMemberships.slice(0, membersToShow).map(({ isAdmin, member }) => (

View file

@ -5405,23 +5405,3 @@ const sortConversationTitles = (
) => {
return collator.compare(left.getTitle(), right.getTitle());
};
// We need a custom collection here to get the sorting we need
window.Whisper.GroupConversationCollection = window.Backbone.Collection.extend({
model: window.Whisper.GroupMemberConversation,
initialize() {
this.collator = new Intl.Collator(undefined, { sensitivity: 'base' });
},
comparator(left: WhatIsThis, right: WhatIsThis) {
if (left.isAdmin && !right.isAdmin) {
return -1;
}
if (!left.isAdmin && right.isAdmin) {
return 1;
}
return sortConversationTitles(left, right, this.collator);
},
});

View file

@ -17,8 +17,8 @@ type ConfirmationDialogViewProps = {
resolve: () => void;
};
let confirmationDialogViewNode: HTMLElement | null = null;
let confirmationDialogPreviousFocus: HTMLElement | null = null;
let confirmationDialogViewNode: HTMLElement | undefined;
let confirmationDialogPreviousFocus: HTMLElement | undefined;
function removeConfirmationDialog() {
if (!confirmationDialogViewNode) {
@ -34,7 +34,7 @@ function removeConfirmationDialog() {
) {
confirmationDialogPreviousFocus.focus();
}
confirmationDialogViewNode = null;
confirmationDialogViewNode = undefined;
}
function showConfirmationDialog(options: ConfirmationDialogViewProps) {

View file

@ -0,0 +1,67 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
// This file is here temporarily while we're switching off of Backbone into
// React. In the future, and in React-land, please just import and use
// the component directly. This is the thin API layer to bridge the gap
// while we convert things over. Please delete this file once all usages are
// ported over.
import React from 'react';
import { unmountComponentAtNode, render } from 'react-dom';
import { ConversationModel } from '../models/conversations';
import { SafetyNumberChangeDialog } from '../components/SafetyNumberChangeDialog';
export type SafetyNumberChangeViewProps = {
confirmText?: string;
contacts: Array<ConversationModel>;
reject: () => void;
resolve: () => void;
};
let dialogContainerNode: HTMLElement | undefined;
function removeDialog() {
if (!dialogContainerNode) {
return;
}
unmountComponentAtNode(dialogContainerNode);
document.body.removeChild(dialogContainerNode);
dialogContainerNode = undefined;
}
export function showSafetyNumberChangeDialog(
options: SafetyNumberChangeViewProps
): void {
if (dialogContainerNode) {
removeDialog();
}
dialogContainerNode = document.createElement('div');
document.body.appendChild(dialogContainerNode);
render(
<SafetyNumberChangeDialog
confirmText={options.confirmText}
contacts={options.contacts.map(contact => contact.format())}
i18n={window.i18n}
onCancel={() => {
options.reject();
removeDialog();
}}
onConfirm={() => {
options.resolve();
removeDialog();
}}
renderSafetyNumber={props => {
return window.Signal.State.Roots.createSafetyNumberViewer(
window.reduxStore,
props
);
}}
/>,
dialogContainerNode
);
}

View file

@ -1,15 +0,0 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import { Provider } from 'react-redux';
import { Store } from 'redux';
import { SmartCallManager } from '../smart/CallManager';
export const createCallManager = (store: Store): React.ReactElement => (
<Provider store={store}>
<SmartCallManager />
</Provider>
);

View file

@ -1,17 +0,0 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import { Provider } from 'react-redux';
import { Store } from 'redux';
import { SmartGlobalModalContainer } from '../smart/GlobalModalContainer';
export const createGlobalModalContainer = (
store: Store
): React.ReactElement => (
<Provider store={store}>
<SmartGlobalModalContainer />
</Provider>
);

View file

@ -1,21 +0,0 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { connect } from 'react-redux';
import { App } from '../../components/App';
import { StateType } from '../reducer';
import { getIntl, getTheme } from '../selectors/user';
import { mapDispatchToProps } from '../actions';
const mapStateToProps = (state: StateType) => {
return {
...state.app,
i18n: getIntl(state),
theme: getTheme(state),
};
};
const smart = connect(mapStateToProps, mapDispatchToProps);
export const SmartApp = smart(App);

25
ts/state/smart/App.tsx Normal file
View file

@ -0,0 +1,25 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import { connect } from 'react-redux';
import { App, PropsType } from '../../components/App';
import { SmartCallManager } from './CallManager';
import { SmartGlobalModalContainer } from './GlobalModalContainer';
import { StateType } from '../reducer';
import { getTheme } from '../selectors/user';
import { mapDispatchToProps } from '../actions';
const mapStateToProps = (state: StateType): PropsType => {
return {
...state.app,
renderCallManager: () => <SmartCallManager />,
renderGlobalModalContainer: () => <SmartGlobalModalContainer />,
theme: getTheme(state),
};
};
const smart = connect(mapStateToProps, mapDispatchToProps);
export const SmartApp = smart(App);

View file

@ -252,22 +252,6 @@
"updated": "2020-08-21T11:29:29.636Z",
"reasonDetail": "Interacting with already-existing DOM nodes"
},
{
"rule": "jQuery-$(",
"path": "js/views/banner_view.js",
"line": " template: () => $('#banner').html(),",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, read-only access"
},
{
"rule": "jQuery-html(",
"path": "js/views/banner_view.js",
"line": " template: () => $('#banner').html(),",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, read-only access"
},
{
"rule": "jQuery-$(",
"path": "js/views/clear_data_view.js",
@ -284,30 +268,6 @@
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, read-only access"
},
{
"rule": "jQuery-$(",
"path": "js/views/contact_list_view.js",
"line": " template: () => $('#contact').html(),",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, read-only access"
},
{
"rule": "jQuery-append(",
"path": "js/views/contact_list_view.js",
"line": " this.$el.append(this.contactView.el);",
"reasonCategory": "usageTrusted",
"updated": "2019-07-31T00:19:18.696Z",
"reasonDetail": "Known DOM elements"
},
{
"rule": "jQuery-html(",
"path": "js/views/contact_list_view.js",
"line": " template: () => $('#contact').html(),",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, read-only access"
},
{
"rule": "jQuery-$(",
"path": "js/views/debug_log_view.js",
@ -420,38 +380,6 @@
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, read-only access"
},
{
"rule": "jQuery-$(",
"path": "js/views/group_member_list_view.js",
"line": " this.$('.container').append(this.member_list_view.el);",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, adding sub-view to DOM"
},
{
"rule": "jQuery-$(",
"path": "js/views/group_member_list_view.js",
"line": " template: () => $('#group-member-list').html(),",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, read-only access"
},
{
"rule": "jQuery-append(",
"path": "js/views/group_member_list_view.js",
"line": " this.$('.container').append(this.member_list_view.el);",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, adding sub-view to DOM"
},
{
"rule": "jQuery-html(",
"path": "js/views/group_member_list_view.js",
"line": " template: () => $('#group-member-list').html(),",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, read-only access"
},
{
"rule": "jQuery-$(",
"path": "js/views/identicon_svg_view.js",
@ -476,14 +404,6 @@
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, read-only access"
},
{
"rule": "jQuery-$(",
"path": "js/views/inbox_view.js",
"line": " this.$('.call-manager-placeholder').append(this.callManagerView.el);",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Adding sub-view to DOM"
},
{
"rule": "jQuery-$(",
"path": "js/views/inbox_view.js",
@ -500,14 +420,6 @@
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Providing reference to DOM for sub-view"
},
{
"rule": "jQuery-$(",
"path": "js/views/inbox_view.js",
"line": " this.$('#header, .gutter').addClass('inactive');",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, adding or removing classes"
},
{
"rule": "jQuery-$(",
"path": "js/views/inbox_view.js",
@ -516,22 +428,6 @@
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, adding or removing classes"
},
{
"rule": "jQuery-$(",
"path": "js/views/inbox_view.js",
"line": " this.$('.conversation-stack').addClass('inactive');",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, adding or removing classes"
},
{
"rule": "jQuery-$(",
"path": "js/views/inbox_view.js",
"line": " this.$('#header, .gutter').removeClass('inactive');",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, adding or removing classes"
},
{
"rule": "jQuery-$(",
"path": "js/views/inbox_view.js",
@ -583,18 +479,9 @@
{
"rule": "jQuery-$(",
"path": "js/views/inbox_view.js",
"line": " this.$('.conversation:first .menu').trigger('close');",
"line": " this.$('#header, .gutter').addClass('inactive');",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, trigging DOM event"
},
{
"rule": "jQuery-append(",
"path": "js/views/inbox_view.js",
"line": " this.$('.call-manager-placeholder').append(this.callManagerView.el);",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Adding sub-view to DOM"
"updated": "2021-06-15T23:46:51.629Z"
},
{
"rule": "jQuery-append(",
@ -812,22 +699,6 @@
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, read-only access"
},
{
"rule": "jQuery-append(",
"path": "js/views/list_view.js",
"line": " this.$el.append(view.render().el);",
"reasonCategory": "usageTrusted",
"updated": "2018-09-19T18:13:29.628Z",
"reasonDetail": "Interacting with already-existing DOM nodes"
},
{
"rule": "jQuery-html(",
"path": "js/views/list_view.js",
"line": " this.$el.html('');",
"reasonCategory": "usageTrusted",
"updated": "2018-09-15T00:38:04.183Z",
"reasonDetail": "Hard-coded value"
},
{
"rule": "jQuery-$(",
"path": "js/views/phone-input-view.js",
@ -932,36 +803,6 @@
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, read-only access"
},
{
"rule": "jQuery-$(",
"path": "js/views/safety_number_change_dialog_view.js",
"line": " this.$('.safety-number-change-dialog-wrapper').append(dialog.el);",
"reasonCategory": "usageTrusted",
"updated": "2020-06-23T06:48:06.829Z"
},
{
"rule": "jQuery-$(",
"path": "js/views/safety_number_change_dialog_view.js",
"line": " template: () => $('#safety-number-change-dialog').html(),",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, read-only access"
},
{
"rule": "jQuery-append(",
"path": "js/views/safety_number_change_dialog_view.js",
"line": " this.$('.safety-number-change-dialog-wrapper').append(dialog.el);",
"reasonCategory": "usageTrusted",
"updated": "2020-06-23T06:48:06.829Z"
},
{
"rule": "jQuery-html(",
"path": "js/views/safety_number_change_dialog_view.js",
"line": " template: () => $('#safety-number-change-dialog').html(),",
"reasonCategory": "usageTrusted",
"updated": "2021-02-26T18:44:56.450Z",
"reasonDetail": "Static selector, read-only access"
},
{
"rule": "jQuery-$(",
"path": "js/views/settings_view.js",
@ -14348,4 +14189,4 @@
"updated": "2021-03-18T21:41:28.361Z",
"reasonDetail": "A generic hook. Typically not to be used with non-DOM values."
}
]
]

View file

@ -21,7 +21,6 @@ import { GroupNameCollisionsWithIdsByTitle } from '../util/groupMemberNameCollis
import {
isDirectConversation,
isGroupV1,
isGroupV2,
isMe,
} from '../util/whatTypeOfConversation';
import {
@ -31,6 +30,8 @@ import {
isOutgoing,
isTapToView,
} from '../state/selectors/message';
import { ConversationDetailsMembershipList } from '../components/conversation/conversation-details/ConversationDetailsMembershipList';
import { showSafetyNumberChangeDialog } from '../shims/showSafetyNumberChangeDialog';
type GetLinkPreviewImageResult = {
data: ArrayBuffer;
@ -367,7 +368,6 @@ Whisper.ConversationView = Whisper.View.extend({
// Events on Conversation model
this.listenTo(this.model, 'destroy', this.stopListening);
this.listenTo(this.model, 'change:verified', this.onVerifiedChange);
this.listenTo(this.model, 'newmessage', this.lazyUpdateVerified);
// These are triggered by InboxView
@ -573,8 +573,8 @@ Whisper.ConversationView = Whisper.View.extend({
onShowAllMedia: () => {
this.showAllMedia();
},
onShowGroupMembers: async () => {
await this.showMembers();
onShowGroupMembers: () => {
this.showGV1Members();
},
onGoBack: () => {
this.resetPanel();
@ -1446,9 +1446,6 @@ Whisper.ConversationView = Whisper.View.extend({
if (this.captureAudioView) {
this.captureAudioView.remove();
}
if (this.banner) {
this.banner.remove();
}
if (this.lastSeenIndicator) {
this.lastSeenIndicator.remove();
}
@ -2132,55 +2129,6 @@ Whisper.ConversationView = Whisper.View.extend({
return Promise.all(untrusted.map((contact: any) => contact.setApproved()));
},
openSafetyNumberScreens(unverified: any) {
if (unverified.length === 1) {
this.showSafetyNumber(unverified.at(0).id);
return;
}
this.showMembers(null, unverified, { needVerify: true });
},
onVerifiedChange() {
const { model }: { model: ConversationModel } = this;
if (model.isUnverified()) {
const unverified = model.getUnverified();
let message;
if (!unverified.length) {
return;
}
if (unverified.length > 1) {
message = window.i18n('multipleNoLongerVerified');
} else {
message = window.i18n('noLongerVerified', [
unverified.at(0).getTitle(),
]);
}
// Need to re-add, since unverified set may have changed
if (this.banner) {
this.banner.remove();
this.banner = null;
}
this.banner = new Whisper.BannerView({
message,
onDismiss: () => {
this.markAllAsVerifiedDefault(unverified);
},
onClick: () => {
this.openSafetyNumberScreens(unverified);
},
});
const container = this.$('.discussion-container');
container.append(this.banner.el);
} else if (this.banner) {
this.banner.remove();
this.banner = null;
}
},
toggleMicrophone() {
this.compositionApi.current.setShowMic(!this.hasFiles());
},
@ -2314,7 +2262,6 @@ Whisper.ConversationView = Whisper.View.extend({
this.statusFetch = statusPromise.then(() =>
// eslint-disable-next-line more/no-then
model.updateVerified().then(() => {
this.onVerifiedChange();
this.statusFetch = null;
})
);
@ -2736,35 +2683,32 @@ Whisper.ConversationView = Whisper.View.extend({
this.compositionApi.current.resetEmojiResults(false);
},
async showMembers(
_e: unknown,
providedMembers: void | Backbone.Collection<ConversationModel>,
options: any = {}
) {
showGV1Members() {
const { model }: { model: ConversationModel } = this;
window._.defaults(options, { needVerify: false });
const { contactCollection } = model;
let contactCollection = providedMembers || model.contactCollection;
const memberships =
contactCollection?.map((conversation: ConversationModel) => {
return {
isAdmin: false,
member: conversation.format(),
};
}) || [];
if (!providedMembers && isGroupV2(model.attributes)) {
contactCollection = new Whisper.GroupConversationCollection(
this.model.get('membersV2').map(({ conversationId, role }: any) => ({
conversation: window.ConversationController.get(conversationId),
isAdmin:
role === window.textsecure.protobuf.Member.Role.ADMINISTRATOR,
}))
);
}
const view = new Whisper.GroupMemberList({
model: contactCollection,
// we pass this in to allow nested panels
listenBack: this.listenBack.bind(this),
needVerify: options.needVerify,
conversation: model,
const view = new Whisper.ReactWrapperView({
className: 'group-member-list panel',
Component: ConversationDetailsMembershipList,
props: {
canAddNewMembers: false,
i18n: window.i18n,
maxShownMemberCount: 32,
memberships,
showContactModal: this.showContactModal.bind(this),
},
});
this.listenBack(view);
view.render();
},
forceSend({
@ -3695,7 +3639,7 @@ Whisper.ConversationView = Whisper.View.extend({
confirmText?: string
) {
return new Promise(resolve => {
const dialog = new Whisper.SafetyNumberChangeDialogView({
showSafetyNumberChangeDialog({
confirmText,
contacts,
reject: () => {
@ -3705,8 +3649,6 @@ Whisper.ConversationView = Whisper.View.extend({
resolve(true);
},
});
this.$el.prepend(dialog.el);
});
},

5
ts/window.d.ts vendored
View file

@ -48,14 +48,12 @@ import { ConversationController } from './ConversationController';
import { ReduxActions } from './state/types';
import { createStore } from './state/createStore';
import { createApp } from './state/roots/createApp';
import { createCallManager } from './state/roots/createCallManager';
import { createChatColorPicker } from './state/roots/createChatColorPicker';
import { createCompositionArea } from './state/roots/createCompositionArea';
import { createContactModal } from './state/roots/createContactModal';
import { createConversationDetails } from './state/roots/createConversationDetails';
import { createConversationHeader } from './state/roots/createConversationHeader';
import { createForwardMessageModal } from './state/roots/createForwardMessageModal';
import { createGlobalModalContainer } from './state/roots/createGlobalModalContainer';
import { createGroupLinkManagement } from './state/roots/createGroupLinkManagement';
import { createGroupV1MigrationModal } from './state/roots/createGroupV1MigrationModal';
import { createGroupV2JoinModal } from './state/roots/createGroupV2JoinModal';
@ -480,14 +478,12 @@ declare global {
createStore: typeof createStore;
Roots: {
createApp: typeof createApp;
createCallManager: typeof createCallManager;
createChatColorPicker: typeof createChatColorPicker;
createCompositionArea: typeof createCompositionArea;
createContactModal: typeof createContactModal;
createConversationDetails: typeof createConversationDetails;
createConversationHeader: typeof createConversationHeader;
createForwardMessageModal: typeof createForwardMessageModal;
createGlobalModalContainer: typeof createGlobalModalContainer;
createGroupLinkManagement: typeof createGroupLinkManagement;
createGroupV1MigrationModal: typeof createGroupV1MigrationModal;
createGroupV2JoinModal: typeof createGroupV2JoinModal;
@ -658,7 +654,6 @@ export type WhisperType = {
reject: Function
) => void;
};
GroupConversationCollection: typeof ConversationModelCollectionType;
ConversationCollection: typeof ConversationModelCollectionType;
ConversationCollectionType: ConversationModelCollectionType;
Conversation: typeof ConversationModel;