diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 59166d6b2f7..46484e20e03 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -822,6 +822,11 @@ "description": "When rendering an address, used to provide context to a post office box" }, + "downloading": { + "message": "Downloading", + "description": + "Shown in the message bubble while a long message attachment is being downloaded" + }, "downloadAttachment": { "message": "Download Attachment", "description": @@ -1248,12 +1253,6 @@ "description": "Warning notification that this version of the app has expired" }, - "androidMessageLengthWarning": { - "message": - "Android clients will only receive the first 2000 characters of this message.", - "description": - "Warning that long messages could not get received completely by Android clients." - }, "upgrade": { "message": "Upgrade", "description": diff --git a/background.html b/background.html index 189dceccc3d..2e0f6014e30 100644 --- a/background.html +++ b/background.html @@ -122,9 +122,6 @@
-
- {{ android-length-warning }} -
diff --git a/js/models/conversations.js b/js/models/conversations.js index 0234f0f6e1a..1e7552a7dea 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -921,12 +921,21 @@ messageWithSchema.attachments.map(loadAttachmentData) ); + const { + body: messageBody, + attachments: finalAttachments, + } = Whisper.Message.getLongMessageAttachment({ + body, + attachments: attachmentsWithData, + now, + }); + // Special-case the self-send case - we send only a sync message if (this.isMe()) { const dataMessage = await textsecure.messaging.getMessageProto( destination, - body, - attachmentsWithData, + messageBody, + finalAttachments, quote, preview, now, @@ -945,8 +954,8 @@ case Message.PRIVATE: return textsecure.messaging.sendMessageToNumber( destination, - body, - attachmentsWithData, + messageBody, + finalAttachments, quote, preview, now, @@ -958,8 +967,8 @@ return textsecure.messaging.sendMessageToGroup( destination, groupNumbers, - body, - attachmentsWithData, + messageBody, + finalAttachments, quote, preview, now, diff --git a/js/models/messages.js b/js/models/messages.js index eaec4720fbd..4c5604d5f04 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -26,6 +26,7 @@ loadPreviewData, upgradeMessageSchema, } = window.Signal.Migrations; + const { bytesFromString } = window.Signal.Crypto; window.AccountCache = Object.create(null); window.AccountJobs = Object.create(null); @@ -480,6 +481,7 @@ return { text: this.createNonBreakingLastSeparator(this.get('body')), + textPending: this.get('bodyPending'), id: this.id, direction: this.isIncoming() ? 'incoming' : 'outgoing', timestamp: this.get('sent_at'), @@ -821,6 +823,12 @@ const attachmentsWithData = await Promise.all( (this.get('attachments') || []).map(loadAttachmentData) ); + const { body, attachments } = Whisper.Message.getLongMessageAttachment({ + body: this.get('body'), + attachments: attachmentsWithData, + now: this.get('sent_at'), + }); + const quoteWithData = await loadQuoteData(this.get('quote')); const previewWithData = await loadPreviewData(this.get('preview')); @@ -829,8 +837,8 @@ const [number] = numbers; const dataMessage = await textsecure.messaging.getMessageProto( number, - this.get('body'), - attachmentsWithData, + body, + attachments, quoteWithData, previewWithData, this.get('sent_at'), @@ -847,8 +855,8 @@ const [number] = numbers; promise = textsecure.messaging.sendMessageToNumber( number, - this.get('body'), - attachmentsWithData, + body, + attachments, quoteWithData, previewWithData, this.get('sent_at'), @@ -863,9 +871,9 @@ promise = textsecure.messaging.sendMessage( { recipients: numbers, - body: this.get('body'), + body, timestamp: this.get('sent_at'), - attachments: attachmentsWithData, + attachments, quote: quoteWithData, preview: previewWithData, needsSync: !this.get('synced'), @@ -905,6 +913,12 @@ const attachmentsWithData = await Promise.all( (this.get('attachments') || []).map(loadAttachmentData) ); + const { body, attachments } = Whisper.Message.getLongMessageAttachment({ + body: this.get('body'), + attachments: attachmentsWithData, + now: this.get('sent_at'), + }); + const quoteWithData = await loadQuoteData(this.get('quote')); const previewWithData = await loadPreviewData(this.get('preview')); @@ -912,8 +926,8 @@ if (number === this.OUR_NUMBER) { const dataMessage = await textsecure.messaging.getMessageProto( number, - this.get('body'), - attachmentsWithData, + body, + attachments, quoteWithData, previewWithData, this.get('sent_at'), @@ -928,8 +942,8 @@ ); const promise = textsecure.messaging.sendMessageToNumber( number, - this.get('body'), - attachmentsWithData, + body, + attachments, quoteWithData, previewWithData, this.get('sent_at'), @@ -1255,9 +1269,34 @@ async queueAttachmentDownloads() { const messageId = this.id; let count = 0; + let bodyPending; + + const [longMessageAttachments, normalAttachments] = _.partition( + this.get('attachments') || [], + attachment => + attachment.contentType === Whisper.Message.LONG_MESSAGE_CONTENT_TYPE + ); + + if (longMessageAttachments.length > 1) { + window.log.error( + `Received more than one long message attachment in message ${this.idForLogging()}` + ); + } + if (longMessageAttachments.length > 0) { + count += 1; + bodyPending = true; + await window.Signal.AttachmentDownloads.addJob( + longMessageAttachments[0], + { + messageId, + type: 'long-message', + index: 0, + } + ); + } const attachments = await Promise.all( - (this.get('attachments') || []).map((attachment, index) => { + normalAttachments.map((attachment, index) => { count += 1; return window.Signal.AttachmentDownloads.addJob(attachment, { messageId, @@ -1351,7 +1390,7 @@ } if (count > 0) { - this.set({ attachments, preview, contact, quote, group }); + this.set({ bodyPending, attachments, preview, contact, quote, group }); await window.Signal.Data.saveMessage(this.attributes, { Message: Whisper.Message, @@ -1837,6 +1876,39 @@ }, }); + // Receive will be enabled before we enable send + Whisper.Message.LONG_MESSAGE_SEND_DISABLED = true; + Whisper.Message.LONG_MESSAGE_CONTENT_TYPE = 'text/x-signal-plain'; + + Whisper.Message.getLongMessageAttachment = ({ body, attachments, now }) => { + if (Whisper.Message.LONG_MESSAGE_SEND_DISABLED) { + return { + body, + attachments, + }; + } + + if (body.length <= 2048) { + return { + body, + attachments, + }; + } + + const data = bytesFromString(body); + const attachment = { + contentType: Whisper.Message.LONG_MESSAGE_CONTENT_TYPE, + fileName: `long-message-${now}.txt`, + data, + size: data.byteLength, + }; + + return { + body: body.slice(0, 2048), + attachments: [attachment, ...attachments], + }; + }; + Whisper.Message.refreshExpirationTimer = () => Whisper.ExpiringMessagesListener.update(); diff --git a/js/modules/attachment_downloads.js b/js/modules/attachment_downloads.js index 9a74b8aed21..d330c8653f5 100644 --- a/js/modules/attachment_downloads.js +++ b/js/modules/attachment_downloads.js @@ -11,6 +11,7 @@ const { saveMessage, setAttachmentDownloadJobPending, } = require('./data'); +const { stringFromBytes } = require('./crypto'); module.exports = { start, @@ -312,6 +313,19 @@ async function _addAttachmentToMessage(message, attachment, { type, index }) { const logPrefix = `${message.idForLogging()} (type: ${type}, index: ${index})`; + if (type === 'long-message') { + try { + const { data } = await Signal.Migrations.loadAttachmentData(attachment); + message.set({ + body: attachment.isError ? message.get('body') : stringFromBytes(data), + bodyPending: false, + }); + } finally { + Signal.Migrations.deleteAttachmentData(attachment.path); + } + return; + } + if (type === 'attachment') { const attachments = message.get('attachments'); if (!attachments || attachments.length <= index) { diff --git a/js/views/conversation_view.js b/js/views/conversation_view.js index e2cee8295d5..d89627d7d6c 100644 --- a/js/views/conversation_view.js +++ b/js/views/conversation_view.js @@ -80,7 +80,6 @@ render_attributes() { return { 'send-message': i18n('sendMessage'), - 'android-length-warning': i18n('androidMessageLengthWarning'), }; }, initialize(options) { @@ -542,13 +541,6 @@ this.$('.capture-audio').show(); } }, - toggleLengthWarning() { - if (this.$('.send-message').val().length > 2000) { - this.$('.android-length-warning').show(); - } else { - this.$('.android-length-warning').hide(); - } - }, captureAudio(e) { e.preventDefault(); @@ -2047,7 +2039,6 @@ return; } this.toggleMicrophone(); - this.toggleLengthWarning(); this.view.measureScrollPosition(); window.autosize(this.$messageField); diff --git a/stylesheets/_ios.scss b/stylesheets/_ios.scss index 57ca2e1a163..cbd61cfaa48 100644 --- a/stylesheets/_ios.scss +++ b/stylesheets/_ios.scss @@ -138,12 +138,6 @@ .module-spinner__arc--incoming { background-color: $color-gray-60; } - .module-spinner__circle--small-incoming { - background-color: $color-white-04; - } - .module-spinner__arc--small-incoming { - background-color: $color-gray-60; - } .module-spinner__circle--outgoing { background-color: $color-white-04; @@ -151,12 +145,6 @@ .module-spinner__arc--outgoing { background-color: $color-white; } - .module-spinner__circle--small-outgoing { - background-color: $color-white-04; - } - .module-spinner__arc--small-outgoing { - background-color: $color-white; - } &.dark-theme { // _modules diff --git a/stylesheets/_modules.scss b/stylesheets/_modules.scss index 61e607d76f5..d341136c021 100644 --- a/stylesheets/_modules.scss +++ b/stylesheets/_modules.scss @@ -2787,34 +2787,49 @@ } } +// In these --small and --mini sizes, we're exploding our @color-svg mixin so we don't +// have to duplicate our background colors for the dark/ios/size matrix. + .module-spinner__container--small { height: 24px; width: 24px; } - .module-spinner__circle--small { - @include color-svg('../images/spinner-track-24.svg', $color-white-04); + -webkit-mask: url('../images/spinner-track-24.svg') no-repeat center; + -webkit-mask-size: 100%; height: 24px; width: 24px; } .module-spinner__arc--small { - @include color-svg('../images/spinner-24.svg', $color-gray-60); + -webkit-mask: url('../images/spinner-24.svg') no-repeat center; + -webkit-mask-size: 100%; height: 24px; width: 24px; } +.module-spinner__container--mini { + height: 14px; + width: 14px; +} +.module-spinner__circle--mini { + -webkit-mask: url('../images/spinner-track-24.svg') no-repeat center; + -webkit-mask-size: 100%; + height: 14px; + width: 14px; +} +.module-spinner__arc--mini { + -webkit-mask: url('../images/spinner-24.svg') no-repeat center; + -webkit-mask-size: 100%; + height: 14px; + width: 14px; +} + .module-spinner__circle--incoming { background-color: $color-white-04; } .module-spinner__arc--incoming { background-color: $color-white; } -.module-spinner__circle--small-incoming { - background-color: $color-white-04; -} -.module-spinner__arc--small-incoming { - background-color: $color-white; -} // Module: Highlighted Message Body diff --git a/stylesheets/_theme_dark.scss b/stylesheets/_theme_dark.scss index b4285a82832..a13fe80d310 100644 --- a/stylesheets/_theme_dark.scss +++ b/stylesheets/_theme_dark.scss @@ -1442,12 +1442,6 @@ body.dark-theme { .module-spinner__arc { background-color: $color-gray-05; } - .module-spinner__circle--small { - background-color: $color-white-04; - } - .module-spinner__arc--small { - background-color: $color-gray-05; - } .module-spinner__circle--incoming { background-color: $color-white-04; @@ -1455,12 +1449,6 @@ body.dark-theme { .module-spinner__arc--incoming { background-color: $color-gray-05; } - .module-spinner__circle--small-incoming { - background-color: $color-white-04; - } - .module-spinner__arc--small-incoming { - background-color: $color-gray-05; - } .module-spinner__circle--outgoing { background-color: $color-white-04; @@ -1468,12 +1456,6 @@ body.dark-theme { .module-spinner__arc--outgoing { background-color: $color-gray-05; } - .module-spinner__circle--small-outgoing { - background-color: $color-white-04; - } - .module-spinner__arc--small-outgoing { - background-color: $color-gray-05; - } // Module: Caption Editor diff --git a/test/index.html b/test/index.html index 98c04b2b543..e6646b03be7 100644 --- a/test/index.html +++ b/test/index.html @@ -112,9 +112,6 @@
-
- {{ android-length-warning }} -
diff --git a/ts/components/Spinner.md b/ts/components/Spinner.md index ee30bbc82ca..1924dcc65fc 100644 --- a/ts/components/Spinner.md +++ b/ts/components/Spinner.md @@ -2,7 +2,10 @@ ```jsx - + +
+ +
``` @@ -10,6 +13,20 @@ ```jsx - + +
+ +
+
+``` + +#### Mini + +```jsx + + +
+ +
``` diff --git a/ts/components/Spinner.tsx b/ts/components/Spinner.tsx index ad2a326d202..acd8e484dae 100644 --- a/ts/components/Spinner.tsx +++ b/ts/components/Spinner.tsx @@ -2,43 +2,37 @@ import React from 'react'; import classNames from 'classnames'; interface Props { - small?: boolean; + size: 'small' | 'mini' | 'normal'; direction?: string; } export class Spinner extends React.Component { public render() { - const { small, direction } = this.props; + const { size, direction } = this.props; return (
diff --git a/ts/components/conversation/Image.tsx b/ts/components/conversation/Image.tsx index 90a4b7c21c1..d94d682fc85 100644 --- a/ts/components/conversation/Image.tsx +++ b/ts/components/conversation/Image.tsx @@ -94,7 +94,7 @@ export class Image extends React.Component { }} // alt={i18n('loading')} > - +
) : ( @@ -490,13 +494,53 @@ Note that timestamp and status can be hidden with the `collapseMetadata` boolean authorColor="purple" direction="outgoing" status="delivered" - text={`Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eget condimentum tellus. Aenean vulputate, dui a gravida rhoncus, mi orci varius urna, ut placerat felis ex ac elit. In pulvinar quis velit convallis varius. Quisque mattis, metus id lobortis porttitor, lacus ex laoreet dui, sit amet laoreet massa leo sed tellus. Phasellus iaculis pulvinar bibendum. In vitae imperdiet felis. Vivamus lacinia eros nec arcu varius, sodales faucibus nulla molestie. Etiam luctus lectus sit amet nulla facilisis, a porta mi tempus. Donec sit amet convallis ipsum. + text={`Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam efficitur finibus tellus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eu metus leo. Nullam consequat leo ut accumsan aliquam. In est elit, faucibus vel arcu vitae, dapibus egestas nunc. Curabitur nec orci semper, auctor justo ornare, sagittis massa. Aliquam ultrices sem ac ex vestibulum dapibus. Etiam erat purus, interdum sit amet magna vitae, elementum lacinia leo. Duis vel mauris dui. Morbi sed accumsan erat, at facilisis metus. Nullam molestie lectus eleifend congue ultrices. Nunc porta at justo semper egestas. Proin non iaculis nibh. Cras sit amet urna dignissim, venenatis arcu a, pulvinar ipsum. - In eros risus, posuere non viverra at, finibus ac elit. Nunc convallis vulputate risus. Donec ligula justo, lacinia id vulputate in, semper non nibh. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque porttitor neque a metus dapibus varius. Sed luctus purus vel semper rhoncus. In imperdiet risus ut convallis porttitor. Fusce vel ligula placerat, imperdiet ante vel, mollis ipsum. + Integer et justo ut urna tempor ultrices. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In bibendum a nulla non blandit. In iaculis id orci maximus elementum. Mauris ultricies ipsum et magna iaculis, non porta orci elementum. Curabitur ipsum magna, porttitor id cursus nec, euismod at orci. Sed et ex id neque hendrerit auctor sed et mauris. In hac habitasse platea dictumst. - Etiam ultricies tortor eget mi sollicitudin suscipit. Nullam non ligula lacinia, ornare tortor in, tempor enim. Nullam nec ullamcorper enim. Vestibulum aliquet leo eget nisl aliquet vulputate. Duis quis nisl ligula. Nunc pulvinar lacus urna. Morbi imperdiet tortor eu finibus dictum. Cras ullamcorper aliquet eros, non malesuada tellus cursus eget. + Aliquam erat volutpat. Mauris quis erat luctus enim tincidunt fringilla. Vestibulum ornare, erat sit amet pretium gravida, tortor ipsum pretium eros, ac congue mauris elit vel elit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas ultrices neque vulputate, pellentesque massa non, imperdiet justo. Curabitur vel ex non enim volutpat fringilla. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In gravida consectetur justo sit amet feugiat. Vivamus non eros dignissim, interdum magna at, suscipit mauris. Duis sit amet dui tempor, ornare arcu ultrices, convallis neque. Proin quis risus leo. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nunc lectus sapien, feugiat sit amet orci nec, consectetur vehicula odio. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Maecenas porta scelerisque egestas. - Cras sagittis, sapien vel gravida pellentesque, sem sem semper velit, vel congue ligula leo aliquet massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur eros diam, tempor sed lacus non, commodo imperdiet quam. Praesent eget tristique lectus, sit amet iaculis felis. Morbi molestie dui blandit augue vulputate tempus. Nulla facilisi. Nulla dictum felis eu nulla rhoncus, sed ultricies est scelerisque. Nam risus arcu, sodales at nisl eget, volutpat elementum lacus. Morbi dictum condimentum lorem, at placerat nulla eleifend a. Vestibulum hendrerit diam vulputate, sollicitudin urna vel, luctus nisl. Mauris semper sem quam, sed venenatis quam convallis in. Donec hendrerit, nibh ut mattis congue, quam nibh consectetur magna, eu posuere urna orci et turpis. Integer vitae arcu vitae est varius maximus. Sed ultrices tortor lacus, venenatis pulvinar nibh ullamcorper sit amet. Nulla vehicula metus sed diam gravida auctor sed cursus enim. Curabitur viverra non erat et mollis.`} + Fusce diam massa, lacinia sit amet vehicula vitae, pretium sed augue. Duis diam velit, efficitur eget fringilla vel, pharetra eu lacus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Maecenas et convallis tellus. Aenean in orci tincidunt, finibus nulla ut, aliquam quam. Nullam feugiat egestas urna, ultricies suscipit justo venenatis eget. Curabitur sollicitudin odio eu tincidunt porta. Nullam in metus in purus rutrum varius et sit amet nibh. Nunc at efficitur turpis, a tincidunt dolor. + + Nam non leo euismod, volutpat leo quis, semper orci. Proin malesuada ultrices ex, nec fringilla ante condimentum eu. Sed vel gravida nibh. Vivamus sed tincidunt sem. Phasellus arcu orci, condimentum nec fringilla ac, maximus a arcu. Mauris sit amet sodales nisl. Etiam molestie consequat auctor. Proin auctor pulvinar mi vitae consequat. + + Phasellus commodo viverra condimentum. Nam vitae facilisis nibh, dapibus eleifend nisl. Quisque eu massa nunc.`} + timestamp={Date.now()} + i18n={util.i18n} + /> + + +``` + +### Pending long message download + +```jsx + +
  • + +
  • +
  • + diff --git a/ts/components/conversation/Message.tsx b/ts/components/conversation/Message.tsx index 8571e249230..9520444da1d 100644 --- a/ts/components/conversation/Message.tsx +++ b/ts/components/conversation/Message.tsx @@ -49,6 +49,7 @@ interface LinkPreviewType { export interface Props { disableMenu?: boolean; text?: string; + textPending?: boolean; id?: string; collapseMetadata?: boolean; direction: 'incoming' | 'outgoing'; @@ -196,6 +197,7 @@ export class Message extends React.PureComponent { i18n, status, text, + textPending, timestamp, } = this.props; @@ -247,7 +249,12 @@ export class Message extends React.PureComponent { /> ) : null} - {direction === 'outgoing' && status !== 'error' ? ( + {textPending ? ( +
    + +
    + ) : null} + {!textPending && direction === 'outgoing' && status !== 'error' ? (
    { > {pending ? (
    - +
    ) : (
    @@ -647,7 +654,7 @@ export class Message extends React.PureComponent { } public renderText() { - const { text, i18n, direction, status } = this.props; + const { text, textPending, i18n, direction, status } = this.props; const contents = direction === 'incoming' && status === 'error' @@ -669,7 +676,11 @@ export class Message extends React.PureComponent { : null )} > - +
    ); } diff --git a/ts/components/conversation/MessageBody.md b/ts/components/conversation/MessageBody.md index 2c9a87b510e..428f9a673e2 100644 --- a/ts/components/conversation/MessageBody.md +++ b/ts/components/conversation/MessageBody.md @@ -36,13 +36,13 @@ ### Jumbomoji disabled ```jsx - + ``` ### Links disabled ```jsx - + ``` ### Emoji in link @@ -50,3 +50,24 @@ ```jsx ``` + +### Text pending + +```jsx + +``` + +### Text pending, disable links + +```jsx + +``` diff --git a/ts/components/conversation/MessageBody.tsx b/ts/components/conversation/MessageBody.tsx index 953c263c23f..fa04036c9bc 100644 --- a/ts/components/conversation/MessageBody.tsx +++ b/ts/components/conversation/MessageBody.tsx @@ -9,6 +9,7 @@ import { LocalizerType, RenderTextCallbackType } from '../../types/Util'; interface Props { text: string; + textPending?: boolean; /** If set, all emoji will be the same size. Otherwise, just one emoji will be large. */ disableJumbomoji?: boolean; /** If set, links will be left alone instead of turned into clickable `` tags. */ @@ -50,23 +51,48 @@ const renderEmoji = ({ * them for you. */ export class MessageBody extends React.Component { - public render() { - const { text, disableJumbomoji, disableLinks, i18n } = this.props; - const sizeClass = disableJumbomoji ? undefined : getSizeClass(text); - - if (disableLinks) { - return renderEmoji({ - i18n, - text, - sizeClass, - key: 0, - renderNonEmoji: renderNewLines, - }); - } + public addDownloading(jsx: JSX.Element): JSX.Element { + const { i18n, textPending } = this.props; return ( + + {jsx} + {textPending ? ( + + {' '} + {i18n('downloading')} + + ) : null} + + ); + } + + public render() { + const { + text, + textPending, + disableJumbomoji, + disableLinks, + i18n, + } = this.props; + const sizeClass = disableJumbomoji ? undefined : getSizeClass(text); + const textWithPending = textPending ? `${text}...` : text; + + if (disableLinks) { + return this.addDownloading( + renderEmoji({ + i18n, + text: textWithPending, + sizeClass, + key: 0, + renderNonEmoji: renderNewLines, + }) + ); + } + + return this.addDownloading( { return renderEmoji({ i18n, diff --git a/ts/components/conversation/_contactUtil.tsx b/ts/components/conversation/_contactUtil.tsx index 9f91538e3cd..496aba756da 100644 --- a/ts/components/conversation/_contactUtil.tsx +++ b/ts/components/conversation/_contactUtil.tsx @@ -25,11 +25,12 @@ export function renderAvatar({ const avatarPath = avatar && avatar.avatar && avatar.avatar.path; const pending = avatar && avatar.avatar && avatar.avatar.pending; const name = getName(contact) || ''; + const spinnerSize = size < 50 ? 'small' : 'normal'; if (pending) { return (
    - +
    ); } diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json index daf8208c7f2..4720e9a601b 100644 --- a/ts/util/lint/exceptions.json +++ b/ts/util/lint/exceptions.json @@ -203,22 +203,6 @@ "updated": "2018-09-19T18:13:29.628Z", "reasonDetail": "Interacting with already-existing DOM nodes" }, - { - "rule": "jQuery-wrap(", - "path": "js/models/messages.js", - "line": " return this.send(wrap(promise));", - "lineNumber": 938, - "reasonCategory": "falseMatch", - "updated": "2018-10-05T23:12:28.961Z" - }, - { - "rule": "jQuery-wrap(", - "path": "js/models/messages.js", - "line": " return wrap(", - "lineNumber": 1185, - "reasonCategory": "falseMatch", - "updated": "2018-10-05T23:12:28.961Z" - }, { "rule": "jQuery-wrap(", "path": "js/modules/crypto.js", diff --git a/ts/util/lint/linter.ts b/ts/util/lint/linter.ts index 5db7b7e6fb3..6e978802379 100644 --- a/ts/util/lint/linter.ts +++ b/ts/util/lint/linter.ts @@ -50,6 +50,7 @@ const results: Array = []; const excludedFiles = [ // High-traffic files in our project + '^js/models/messages.js', '^js/views/conversation_view.js', '^js/views/file_input_view.js', '^js/background.js',