diff --git a/package.json b/package.json index 2b637f68c6..831644083a 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ }, "dependencies": { "babel-runtime": "^6.11.6", + "bluebird": "^3.5.0", "blueimp-canvas-to-blob": "^3.5.0", "browser-encrypt-attachment": "^0.3.0", "browser-request": "^0.3.3", @@ -68,7 +69,6 @@ "matrix-js-sdk": "matrix-org/matrix-js-sdk#develop", "optimist": "^0.6.1", "prop-types": "^15.5.8", - "q": "^1.4.1", "react": "^15.4.0", "react-addons-css-transition-group": "15.3.2", "react-dom": "^15.4.0", diff --git a/src/ContentMessages.js b/src/ContentMessages.js index 315c312b9f..93013cfd6c 100644 --- a/src/ContentMessages.js +++ b/src/ContentMessages.js @@ -16,7 +16,7 @@ limitations under the License. 'use strict'; -var q = require('q'); +import Promise from 'bluebird'; var extend = require('./extend'); var dis = require('./dispatcher'); var MatrixClientPeg = require('./MatrixClientPeg'); @@ -52,7 +52,7 @@ const MAX_HEIGHT = 600; * and a thumbnail key. */ function createThumbnail(element, inputWidth, inputHeight, mimeType) { - const deferred = q.defer(); + const deferred = Promise.defer(); var targetWidth = inputWidth; var targetHeight = inputHeight; @@ -95,7 +95,7 @@ function createThumbnail(element, inputWidth, inputHeight, mimeType) { * @return {Promise} A promise that resolves with the html image element. */ function loadImageElement(imageFile) { - const deferred = q.defer(); + const deferred = Promise.defer(); // Load the file into an html element const img = document.createElement("img"); @@ -154,7 +154,7 @@ function infoForImageFile(matrixClient, roomId, imageFile) { * @return {Promise} A promise that resolves with the video image element. */ function loadVideoElement(videoFile) { - const deferred = q.defer(); + const deferred = Promise.defer(); // Load the file into an html element const video = document.createElement("video"); @@ -210,7 +210,7 @@ function infoForVideoFile(matrixClient, roomId, videoFile) { * is read. */ function readFileAsArrayBuffer(file) { - const deferred = q.defer(); + const deferred = Promise.defer(); const reader = new FileReader(); reader.onload = function(e) { deferred.resolve(e.target.result); @@ -288,7 +288,7 @@ class ContentMessages { content.info.mimetype = file.type; } - const def = q.defer(); + const def = Promise.defer(); if (file.type.indexOf('image/') == 0) { content.msgtype = 'm.image'; infoForImageFile(matrixClient, roomId, file).then(imageInfo=>{ diff --git a/src/Lifecycle.js b/src/Lifecycle.js index 00a82bad21..eb2156e780 100644 --- a/src/Lifecycle.js +++ b/src/Lifecycle.js @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import q from 'q'; +import Promise from 'bluebird'; import Matrix from 'matrix-js-sdk'; import MatrixClientPeg from './MatrixClientPeg'; @@ -116,12 +116,12 @@ export function loadSession(opts) { */ export function attemptTokenLogin(queryParams, defaultDeviceDisplayName) { if (!queryParams.loginToken) { - return q(false); + return Promise.resolve(false); } if (!queryParams.homeserver) { console.warn("Cannot log in with token: can't determine HS URL to use"); - return q(false); + return Promise.resolve(false); } // create a temporary MatrixClient to do the login @@ -197,7 +197,7 @@ function _registerAsGuest(hsUrl, isUrl, defaultDeviceDisplayName) { // localStorage (e.g. teamToken, isGuest etc.) function _restoreFromLocalStorage() { if (!localStorage) { - return q(false); + return Promise.resolve(false); } const hsUrl = localStorage.getItem("mx_hs_url"); const isUrl = localStorage.getItem("mx_is_url") || 'https://matrix.org'; @@ -229,14 +229,14 @@ function _restoreFromLocalStorage() { } } else { console.log("No previous session found."); - return q(false); + return Promise.resolve(false); } } function _handleRestoreFailure(e) { console.log("Unable to restore session", e); - const def = q.defer(); + const def = Promise.defer(); const SessionRestoreErrorDialog = sdk.getComponent('views.dialogs.SessionRestoreErrorDialog'); diff --git a/src/Login.js b/src/Login.js index 8225509919..049b79c2f4 100644 --- a/src/Login.js +++ b/src/Login.js @@ -18,7 +18,7 @@ limitations under the License. import Matrix from "matrix-js-sdk"; import { _t } from "./languageHandler"; -import q from 'q'; +import Promise from 'bluebird'; import url from 'url'; export default class Login { @@ -144,7 +144,7 @@ export default class Login { const client = this._createTemporaryClient(); return client.login('m.login.password', loginParams).then(function(data) { - return q({ + return Promise.resolve({ homeserverUrl: self._hsUrl, identityServerUrl: self._isUrl, userId: data.user_id, @@ -160,7 +160,7 @@ export default class Login { }); return fbClient.login('m.login.password', loginParams).then(function(data) { - return q({ + return Promise.resolve({ homeserverUrl: self._fallbackHsUrl, identityServerUrl: self._isUrl, userId: data.user_id, diff --git a/src/RoomNotifs.js b/src/RoomNotifs.js index 88b6e56c7f..5cc078dc59 100644 --- a/src/RoomNotifs.js +++ b/src/RoomNotifs.js @@ -16,7 +16,7 @@ limitations under the License. import MatrixClientPeg from './MatrixClientPeg'; import PushProcessor from 'matrix-js-sdk/lib/pushprocessor'; -import q from 'q'; +import Promise from 'bluebird'; export const ALL_MESSAGES_LOUD = 'all_messages_loud'; export const ALL_MESSAGES = 'all_messages'; @@ -87,7 +87,7 @@ function setRoomNotifsStateMuted(roomId) { ], })); - return q.all(promises); + return Promise.all(promises); } function setRoomNotifsStateUnmuted(roomId, newState) { @@ -126,7 +126,7 @@ function setRoomNotifsStateUnmuted(roomId, newState) { promises.push(cli.setPushRuleEnabled('global', 'room', roomId, true)); } - return q.all(promises); + return Promise.all(promises); } function findOverrideMuteRule(roomId) { diff --git a/src/Rooms.js b/src/Rooms.js index 3ac7c68533..2e3f4457f0 100644 --- a/src/Rooms.js +++ b/src/Rooms.js @@ -15,7 +15,7 @@ limitations under the License. */ import MatrixClientPeg from './MatrixClientPeg'; -import q from 'q'; +import Promise from 'bluebird'; /** * Given a room object, return the alias we should use for it, @@ -102,7 +102,7 @@ export function guessAndSetDMRoom(room, isDirect) { */ export function setDMRoom(roomId, userId) { if (MatrixClientPeg.get().isGuest()) { - return q(); + return Promise.resolve(); } const mDirectEvent = MatrixClientPeg.get().getAccountData('m.direct'); diff --git a/src/ScalarAuthClient.js b/src/ScalarAuthClient.js index 6908a7f67d..b1d17b93a9 100644 --- a/src/ScalarAuthClient.js +++ b/src/ScalarAuthClient.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -var q = require("q"); +import Promise from 'bluebird'; var request = require('browser-request'); var SdkConfig = require('./SdkConfig'); @@ -39,7 +39,7 @@ class ScalarAuthClient { // Returns a scalar_token string getScalarToken() { var tok = window.localStorage.getItem("mx_scalar_token"); - if (tok) return q(tok); + if (tok) return Promise.resolve(tok); // No saved token, so do the dance to get one. First, we // need an openid bearer token from the HS. @@ -53,7 +53,7 @@ class ScalarAuthClient { } exchangeForScalarToken(openid_token_object) { - var defer = q.defer(); + var defer = Promise.defer(); var scalar_rest_url = SdkConfig.get().integrations_rest_url; request({ diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js index fef84468ec..4c66c90598 100644 --- a/src/UserSettingsStore.js +++ b/src/UserSettingsStore.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import q from 'q'; +import Promise from 'bluebird'; import MatrixClientPeg from './MatrixClientPeg'; import Notifier from './Notifier'; import { _t } from './languageHandler'; @@ -48,7 +48,7 @@ export default { loadThreePids: function() { if (MatrixClientPeg.get().isGuest()) { - return q({ + return Promise.resolve({ threepids: [], }); // guests can't poke 3pid endpoint } diff --git a/src/autocomplete/Autocompleter.js b/src/autocomplete/Autocompleter.js index 62b5a870f3..6b8cd66ae2 100644 --- a/src/autocomplete/Autocompleter.js +++ b/src/autocomplete/Autocompleter.js @@ -22,7 +22,7 @@ import DuckDuckGoProvider from './DuckDuckGoProvider'; import RoomProvider from './RoomProvider'; import UserProvider from './UserProvider'; import EmojiProvider from './EmojiProvider'; -import Q from 'q'; +import Promise from 'bluebird'; export type SelectionRange = { start: number, @@ -57,7 +57,7 @@ export async function getCompletions(query: string, selection: SelectionRange, f state (== "fulfilled" || "rejected") and value. */ const completionsList = await Q.allSettled( PROVIDERS.map(provider => { - return Q(provider.getCompletions(query, selection, force)) + return Promise.resolve(provider.getCompletions(query, selection, force)) .timeout(PROVIDER_COMPLETION_TIMEOUT); }), ); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 75a15d71ee..b90cb53435 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import q from 'q'; +import Promise from 'bluebird'; import React from 'react'; import Matrix from "matrix-js-sdk"; @@ -224,7 +224,7 @@ module.exports = React.createClass({ // Used by _viewRoom before getting state from sync this.firstSyncComplete = false; - this.firstSyncPromise = q.defer(); + this.firstSyncPromise = Promise.defer(); if (this.props.config.sync_timeline_limit) { MatrixClientPeg.opts.initialSyncLimit = this.props.config.sync_timeline_limit; @@ -323,9 +323,9 @@ module.exports = React.createClass({ return; } - // the extra q() ensures that synchronous exceptions hit the same codepath as + // the extra Promise.resolve() ensures that synchronous exceptions hit the same codepath as // asynchronous ones. - return q().then(() => { + return Promise.resolve().then(() => { return Lifecycle.loadSession({ fragmentQueryParams: this.props.startingFragmentQueryParams, enableGuest: this.props.enableGuest, @@ -694,7 +694,7 @@ module.exports = React.createClass({ // Wait for the first sync to complete so that if a room does have an alias, // it would have been retrieved. - let waitFor = q(null); + let waitFor = Promise.resolve(null); if (!this.firstSyncComplete) { if (!this.firstSyncPromise) { console.warn('Cannot view a room before first sync. room_id:', roomInfo.room_id); @@ -1039,7 +1039,7 @@ module.exports = React.createClass({ // since we're about to start the client and therefore about // to do the first sync this.firstSyncComplete = false; - this.firstSyncPromise = q.defer(); + this.firstSyncPromise = Promise.defer(); const cli = MatrixClientPeg.get(); // Allow the JS SDK to reap timeline events. This reduces the amount of diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index f12e80b944..094251f4c1 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -22,7 +22,7 @@ limitations under the License. var React = require("react"); var ReactDOM = require("react-dom"); -var q = require("q"); +import Promise from 'bluebird'; var classNames = require("classnames"); var Matrix = require("matrix-js-sdk"); import { _t } from '../../languageHandler'; @@ -775,7 +775,7 @@ module.exports = React.createClass({ onSearchResultsFillRequest: function(backwards) { if (!backwards) { - return q(false); + return Promise.resolve(false); } if (this.state.searchResults.next_batch) { @@ -785,7 +785,7 @@ module.exports = React.createClass({ return this._handleSearchResult(searchPromise); } else { debuglog("no more search results"); - return q(false); + return Promise.resolve(false); } }, @@ -846,7 +846,7 @@ module.exports = React.createClass({ return; } - q().then(() => { + Promise.resolve().then(() => { const signUrl = this.props.thirdPartyInvite ? this.props.thirdPartyInvite.inviteSignUrl : undefined; dis.dispatch({ @@ -865,7 +865,7 @@ module.exports = React.createClass({ } } } - return q(); + return Promise.resolve(); }); }, diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index f035efee92..a8a2ec181b 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -17,7 +17,7 @@ limitations under the License. var React = require("react"); var ReactDOM = require("react-dom"); var GeminiScrollbar = require('react-gemini-scrollbar'); -var q = require("q"); +import Promise from 'bluebird'; var KeyCode = require('../../KeyCode'); var DEBUG_SCROLL = false; @@ -145,7 +145,7 @@ module.exports = React.createClass({ return { stickyBottom: true, startAtBottom: true, - onFillRequest: function(backwards) { return q(false); }, + onFillRequest: function(backwards) { return Promise.resolve(false); }, onUnfillRequest: function(backwards, scrollToken) {}, onScroll: function() {}, }; @@ -386,19 +386,12 @@ module.exports = React.createClass({ debuglog("ScrollPanel: starting "+dir+" fill"); // onFillRequest can end up calling us recursively (via onScroll - // events) so make sure we set this before firing off the call. That - // does present the risk that we might not ever actually fire off the - // fill request, so wrap it in a try/catch. + // events) so make sure we set this before firing off the call. this._pendingFillRequests[dir] = true; - var fillPromise; - try { - fillPromise = this.props.onFillRequest(backwards); - } catch (e) { - this._pendingFillRequests[dir] = false; - throw e; - } - q.finally(fillPromise, () => { + Promise.try(() => { + return this.props.onFillRequest(backwards); + }).finally(() => { this._pendingFillRequests[dir] = false; }).then((hasMoreResults) => { if (this.unmounted) { diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js index cdee03ab63..dc9c0fc9ba 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.js @@ -17,7 +17,7 @@ limitations under the License. var React = require('react'); var ReactDOM = require("react-dom"); -var q = require("q"); +import Promise from 'bluebird'; var Matrix = require("matrix-js-sdk"); var EventTimeline = Matrix.EventTimeline; @@ -311,13 +311,13 @@ var TimelinePanel = React.createClass({ if (!this.state[canPaginateKey]) { debuglog("TimelinePanel: have given up", dir, "paginating this timeline"); - return q(false); + return Promise.resolve(false); } if(!this._timelineWindow.canPaginate(dir)) { debuglog("TimelinePanel: can't", dir, "paginate any further"); this.setState({[canPaginateKey]: false}); - return q(false); + return Promise.resolve(false); } debuglog("TimelinePanel: Initiating paginate; backwards:"+backwards); diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 14432dff81..a172ca4dbf 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -22,7 +22,7 @@ const PlatformPeg = require("../../PlatformPeg"); const Modal = require('../../Modal'); const dis = require("../../dispatcher"); import sessionStore from '../../stores/SessionStore'; -const q = require('q'); +import Promise from 'bluebird'; const packageJson = require('../../../package.json'); const UserSettingsStore = require('../../UserSettingsStore'); const CallMediaHandler = require('../../CallMediaHandler'); @@ -199,7 +199,7 @@ module.exports = React.createClass({ this._addThreepid = null; if (PlatformPeg.get()) { - q().then(() => { + Promise.resolve().then(() => { return PlatformPeg.get().getAppVersion(); }).done((appVersion) => { if (this._unmounted) return; @@ -297,7 +297,7 @@ module.exports = React.createClass({ }, _refreshMediaDevices: function() { - q().then(() => { + Promise.resolve().then(() => { return CallMediaHandler.getDevices(); }).then((mediaDevices) => { // console.log("got mediaDevices", mediaDevices, this._unmounted); @@ -312,7 +312,7 @@ module.exports = React.createClass({ _refreshFromServer: function() { const self = this; - q.all([ + Promise.all([ UserSettingsStore.loadProfileInfo(), UserSettingsStore.loadThreePids(), ]).done(function(resps) { self.setState({ @@ -564,15 +564,16 @@ module.exports = React.createClass({ }); // reject the invites const promises = rooms.map((room) => { - return MatrixClientPeg.get().leave(room.roomId); + return MatrixClientPeg.get().leave(room.roomId).catch((e) => { + // purposefully drop errors to the floor: we'll just have a non-zero number on the UI + // after trying to reject all the invites. + }); }); - // purposefully drop errors to the floor: we'll just have a non-zero number on the UI - // after trying to reject all the invites. - q.allSettled(promises).then(() => { + Promise.all(promises).then(() => { this.setState({ rejectingInvites: false, }); - }).done(); + }); }, _onExportE2eKeysClicked: function() { diff --git a/src/components/structures/login/Registration.js b/src/components/structures/login/Registration.js index 388198bb02..fe05ba4cfd 100644 --- a/src/components/structures/login/Registration.js +++ b/src/components/structures/login/Registration.js @@ -17,7 +17,7 @@ limitations under the License. import Matrix from 'matrix-js-sdk'; -import q from 'q'; +import Promise from 'bluebird'; import React from 'react'; import sdk from '../../../index'; @@ -180,7 +180,7 @@ module.exports = React.createClass({ // will just nop. The point of this being we might not have the email address // that the user registered with at this stage (depending on whether this // is the client they initiated registration). - let trackPromise = q(null); + let trackPromise = Promise.resolve(null); if (this._rtsClient && extra.emailSid) { // Track referral if this.props.referrer set, get team_token in order to // retrieve team config and see welcome page etc. @@ -232,7 +232,7 @@ module.exports = React.createClass({ _setupPushers: function(matrixClient) { if (!this.props.brand) { - return q(); + return Promise.resolve(); } return matrixClient.getPushers().then((resp)=>{ const pushers = resp.pushers; diff --git a/src/components/views/dialogs/ChatInviteDialog.js b/src/components/views/dialogs/ChatInviteDialog.js index a85efadef7..d3a208a785 100644 --- a/src/components/views/dialogs/ChatInviteDialog.js +++ b/src/components/views/dialogs/ChatInviteDialog.js @@ -23,7 +23,7 @@ import MatrixClientPeg from '../../../MatrixClientPeg'; import DMRoomMap from '../../../utils/DMRoomMap'; import Modal from '../../../Modal'; import AccessibleButton from '../elements/AccessibleButton'; -import q from 'q'; +import Promise from 'bluebird'; import dis from '../../../dispatcher'; const TRUNCATE_QUERY_LIST = 40; @@ -498,7 +498,7 @@ module.exports = React.createClass({ } // wait a bit to let the user finish typing - return q.delay(500).then(() => { + return Promise.delay(500).then(() => { if (cancelled) return null; return MatrixClientPeg.get().lookupThreePid(medium, address); }).then((res) => { diff --git a/src/components/views/dialogs/SetMxIdDialog.js b/src/components/views/dialogs/SetMxIdDialog.js index d428223ad6..4d4f672f2b 100644 --- a/src/components/views/dialogs/SetMxIdDialog.js +++ b/src/components/views/dialogs/SetMxIdDialog.js @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import q from 'q'; +import Promise from 'bluebird'; import React from 'react'; import sdk from '../../../index'; import MatrixClientPeg from '../../../MatrixClientPeg'; diff --git a/src/components/views/elements/EditableTextContainer.js b/src/components/views/elements/EditableTextContainer.js index d6f9c555c6..aeb32c07ec 100644 --- a/src/components/views/elements/EditableTextContainer.js +++ b/src/components/views/elements/EditableTextContainer.js @@ -16,7 +16,7 @@ limitations under the License. import React from 'react'; import sdk from '../../../index'; -import q from 'q'; +import Promise from 'bluebird'; /** * A component which wraps an EditableText, with a spinner while updates take @@ -148,5 +148,5 @@ EditableTextContainer.defaultProps = { initialValue: "", placeholder: "", blurToSubmit: false, - onSubmit: function(v) {return q(); }, + onSubmit: function(v) {return Promise.resolve(); }, }; diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index da6447c7e5..dcc073c80e 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -24,7 +24,7 @@ import Modal from '../../../Modal'; import sdk from '../../../index'; import dis from '../../../dispatcher'; import { decryptFile, readBlobAsDataUri } from '../../../utils/DecryptFile'; -import q from 'q'; +import Promise from 'bluebird'; import UserSettingsStore from '../../../UserSettingsStore'; import { _t } from '../../../languageHandler'; @@ -123,7 +123,7 @@ module.exports = React.createClass({ this.fixupHeight(); const content = this.props.mxEvent.getContent(); if (content.file !== undefined && this.state.decryptedUrl === null) { - let thumbnailPromise = q(null); + let thumbnailPromise = Promise.resolve(null); if (content.info.thumbnail_file) { thumbnailPromise = decryptFile( content.info.thumbnail_file, diff --git a/src/components/views/messages/MVideoBody.js b/src/components/views/messages/MVideoBody.js index f31b94df80..06c233e012 100644 --- a/src/components/views/messages/MVideoBody.js +++ b/src/components/views/messages/MVideoBody.js @@ -20,7 +20,7 @@ import React from 'react'; import MFileBody from './MFileBody'; import MatrixClientPeg from '../../../MatrixClientPeg'; import { decryptFile, readBlobAsDataUri } from '../../../utils/DecryptFile'; -import q from 'q'; +import Promise from 'bluebird'; import UserSettingsStore from '../../../UserSettingsStore'; import { _t } from '../../../languageHandler'; @@ -89,7 +89,7 @@ module.exports = React.createClass({ componentDidMount: function() { const content = this.props.mxEvent.getContent(); if (content.file !== undefined && this.state.decryptedUrl === null) { - var thumbnailPromise = q(null); + var thumbnailPromise = Promise.resolve(null); if (content.info.thumbnail_file) { thumbnailPromise = decryptFile( content.info.thumbnail_file diff --git a/src/components/views/room_settings/AliasSettings.js b/src/components/views/room_settings/AliasSettings.js index b9c9c7d989..ba0663153e 100644 --- a/src/components/views/room_settings/AliasSettings.js +++ b/src/components/views/room_settings/AliasSettings.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -var q = require("q"); +import Promise from 'bluebird'; var React = require('react'); var ObjectUtils = require("../../../ObjectUtils"); var MatrixClientPeg = require('../../../MatrixClientPeg'); @@ -104,7 +104,7 @@ module.exports = React.createClass({ } if (oldCanonicalAlias !== this.state.canonicalAlias) { console.log("AliasSettings: Updating canonical alias"); - promises = [q.all(promises).then( + promises = [Promise.all(promises).then( MatrixClientPeg.get().sendStateEvent( this.props.roomId, "m.room.canonical_alias", { alias: this.state.canonicalAlias diff --git a/src/components/views/room_settings/ColorSettings.js b/src/components/views/room_settings/ColorSettings.js index 5fc845a541..b37802d304 100644 --- a/src/components/views/room_settings/ColorSettings.js +++ b/src/components/views/room_settings/ColorSettings.js @@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -var q = require("q"); +import Promise from 'bluebird'; var React = require('react'); var sdk = require('../../../index'); @@ -72,7 +72,7 @@ module.exports = React.createClass({ saveSettings: function() { // : Promise if (!this.state.hasChanged) { - return q(); // They didn't explicitly give a color to save. + return Promise.resolve(); // They didn't explicitly give a color to save. } var originalState = this.getInitialState(); if (originalState.primary_color !== this.state.primary_color || @@ -92,7 +92,7 @@ module.exports = React.createClass({ } }); } - return q(); // no color diff + return Promise.resolve(); // no color diff }, _getColorIndex: function(scheme) { diff --git a/src/components/views/room_settings/UrlPreviewSettings.js b/src/components/views/room_settings/UrlPreviewSettings.js index e5236b90cc..5ee18badaa 100644 --- a/src/components/views/room_settings/UrlPreviewSettings.js +++ b/src/components/views/room_settings/UrlPreviewSettings.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -var q = require("q"); +import Promise from 'bluebird'; var React = require('react'); var MatrixClientPeg = require('../../../MatrixClientPeg'); var sdk = require("../../../index"); diff --git a/src/components/views/rooms/Autocomplete.js b/src/components/views/rooms/Autocomplete.js index 026be0da62..1ea2eada7c 100644 --- a/src/components/views/rooms/Autocomplete.js +++ b/src/components/views/rooms/Autocomplete.js @@ -5,7 +5,7 @@ import flatMap from 'lodash/flatMap'; import isEqual from 'lodash/isEqual'; import sdk from '../../../index'; import type {Completion} from '../../../autocomplete/Autocompleter'; -import Q from 'q'; +import Promise from 'bluebird'; import UserSettingsStore from '../../../UserSettingsStore'; import {getCompletions} from '../../../autocomplete/Autocompleter'; @@ -64,7 +64,7 @@ export default class Autocomplete extends React.Component { // Hide the autocomplete box hide: true, }); - return Q(null); + return Promise.resolve(null); } let autocompleteDelay = UserSettingsStore.getLocalSetting('autocompleteDelay', 200); @@ -73,7 +73,7 @@ export default class Autocomplete extends React.Component { autocompleteDelay = 0; } - const deferred = Q.defer(); + const deferred = Promise.defer(); this.debounceCompletionsRequest = setTimeout(() => { this.processQuery(query, selection).then(() => { deferred.resolve(); @@ -176,7 +176,7 @@ export default class Autocomplete extends React.Component { } forceComplete() { - const done = Q.defer(); + const done = Promise.defer(); this.setState({ forceComplete: true, hide: false, diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index 63737d5fad..37a9bcd0cd 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -17,7 +17,7 @@ var React = require('react'); import { _t } from '../../../languageHandler'; var classNames = require('classnames'); var Matrix = require("matrix-js-sdk"); -var q = require('q'); +import Promise from 'bluebird'; var MatrixClientPeg = require("../../../MatrixClientPeg"); var Modal = require("../../../Modal"); var Entities = require("../../../Entities"); diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index e9dc216fa7..98dfc6452f 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -22,7 +22,7 @@ import {Editor, EditorState, RichUtils, CompositeDecorator, import classNames from 'classnames'; import escape from 'lodash/escape'; -import Q from 'q'; +import Promise from 'bluebird'; import MatrixClientPeg from '../../../MatrixClientPeg'; import type {MatrixClient} from 'matrix-js-sdk/lib/matrix'; diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index d255670a52..387aca2fa5 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import q from 'q'; +import Promise from 'bluebird'; import React from 'react'; import { _t, _tJsx } from '../../../languageHandler'; import MatrixClientPeg from '../../../MatrixClientPeg'; @@ -183,8 +183,14 @@ module.exports = React.createClass({ }); }, + /** + * Returns a promise which resolves once all of the save operations have completed or failed. + * + * The result is a list of promise state snapshots, each with the form + * `{ state: "fulfilled", value: v }` or `{ state: "rejected", reason: r }`. + */ save: function() { - var stateWasSetDefer = q.defer(); + var stateWasSetDefer = Promise.defer(); // the caller may have JUST called setState on stuff, so we need to re-render before saving // else we won't use the latest values of things. // We can be a bit cheeky here and set a loading flag, and listen for the callback on that @@ -194,8 +200,18 @@ module.exports = React.createClass({ this.setState({ _loading: false}); }); + function mapPromiseToSnapshot(p) { + return p.then((r) => { + return { state: "fulfilled", value: r }; + }, (e) => { + return { state: "rejected", reason: e }; + }); + } + return stateWasSetDefer.promise.then(() => { - return q.allSettled(this._calcSavePromises()); + return Promise.all( + this._calcSavePromises().map(mapPromiseToSnapshot), + ); }); }, @@ -282,7 +298,7 @@ module.exports = React.createClass({ // color scheme var p; p = this.saveColor(); - if (!q.isFulfilled(p)) { + if (!Promise.isFulfilled(p)) { promises.push(p); } @@ -294,7 +310,7 @@ module.exports = React.createClass({ // encryption p = this.saveEnableEncryption(); - if (!q.isFulfilled(p)) { + if (!Promise.isFulfilled(p)) { promises.push(p); } @@ -305,25 +321,25 @@ module.exports = React.createClass({ }, saveAliases: function() { - if (!this.refs.alias_settings) { return [q()]; } + if (!this.refs.alias_settings) { return [Promise.resolve()]; } return this.refs.alias_settings.saveSettings(); }, saveColor: function() { - if (!this.refs.color_settings) { return q(); } + if (!this.refs.color_settings) { return Promise.resolve(); } return this.refs.color_settings.saveSettings(); }, saveUrlPreviewSettings: function() { - if (!this.refs.url_preview_settings) { return q(); } + if (!this.refs.url_preview_settings) { return Promise.resolve(); } return this.refs.url_preview_settings.saveSettings(); }, saveEnableEncryption: function() { - if (!this.refs.encrypt) { return q(); } + if (!this.refs.encrypt) { return Promise.resolve(); } var encrypt = this.refs.encrypt.checked; - if (!encrypt) { return q(); } + if (!encrypt) { return Promise.resolve(); } var roomId = this.props.room.roomId; return MatrixClientPeg.get().sendStateEvent( diff --git a/src/components/views/settings/ChangePassword.js b/src/components/views/settings/ChangePassword.js index 099ae2deae..14ec9806b4 100644 --- a/src/components/views/settings/ChangePassword.js +++ b/src/components/views/settings/ChangePassword.js @@ -21,7 +21,7 @@ var MatrixClientPeg = require("../../../MatrixClientPeg"); var Modal = require("../../../Modal"); var sdk = require("../../../index"); -import q from 'q'; +import Promise from 'bluebird'; import AccessibleButton from '../elements/AccessibleButton'; import { _t } from '../../../languageHandler'; @@ -161,7 +161,7 @@ module.exports = React.createClass({ }, _optionallySetEmail: function() { - const deferred = q.defer(); + const deferred = Promise.defer(); // Ask for an email otherwise the user has no way to reset their password const SetEmailDialog = sdk.getComponent("dialogs.SetEmailDialog"); Modal.createDialog(SetEmailDialog, { diff --git a/src/createRoom.js b/src/createRoom.js index 916405776d..74e4b3c2fc 100644 --- a/src/createRoom.js +++ b/src/createRoom.js @@ -21,7 +21,7 @@ import { _t } from './languageHandler'; import dis from "./dispatcher"; import * as Rooms from "./Rooms"; -import q from 'q'; +import Promise from 'bluebird'; /** * Create a new room, and switch to it. @@ -42,7 +42,7 @@ function createRoom(opts) { const client = MatrixClientPeg.get(); if (client.isGuest()) { dis.dispatch({action: 'view_set_mxid'}); - return q(null); + return Promise.resolve(null); } const defaultPreset = opts.dmUserId ? 'trusted_private_chat' : 'private_chat'; @@ -92,7 +92,7 @@ function createRoom(opts) { if (opts.dmUserId) { return Rooms.setDMRoom(roomId, opts.dmUserId); } else { - return q(); + return Promise.resolve(); } }).then(function() { // NB createRoom doesn't block on the client seeing the echo that the diff --git a/src/languageHandler.js b/src/languageHandler.js index 1f0e6326e0..e956d4f8bd 100644 --- a/src/languageHandler.js +++ b/src/languageHandler.js @@ -17,7 +17,7 @@ limitations under the License. import request from 'browser-request'; import counterpart from 'counterpart'; -import q from 'q'; +import Promise from 'bluebird'; import React from 'react'; import UserSettingsStore from './UserSettingsStore'; @@ -231,7 +231,7 @@ export function getCurrentLanguage() { } function getLangsJson() { - const deferred = q.defer(); + const deferred = Promise.defer(); request( { method: "GET", url: i18nFolder + 'languages.json' }, @@ -247,7 +247,7 @@ function getLangsJson() { } function getLanguage(langPath) { - const deferred = q.defer(); + const deferred = Promise.defer(); let response_return = {}; request( diff --git a/src/utils/DecryptFile.js b/src/utils/DecryptFile.js index 8b5f014f2c..04496e4204 100644 --- a/src/utils/DecryptFile.js +++ b/src/utils/DecryptFile.js @@ -20,7 +20,7 @@ import encrypt from 'browser-encrypt-attachment'; import 'isomorphic-fetch'; // Grab the client so that we can turn mxc:// URLs into https:// URLS. import MatrixClientPeg from '../MatrixClientPeg'; -import q from 'q'; +import Promise from 'bluebird'; /** @@ -28,7 +28,7 @@ import q from 'q'; * @return {Promise} A promise that resolves with the data:// URI. */ export function readBlobAsDataUri(file) { - var deferred = q.defer(); + var deferred = Promise.defer(); var reader = new FileReader(); reader.onload = function(e) { deferred.resolve(e.target.result); @@ -53,7 +53,7 @@ export function readBlobAsDataUri(file) { export function decryptFile(file) { const url = MatrixClientPeg.get().mxcUrlToHttp(file.url); // Download the encrypted file as an array buffer. - return q(fetch(url)).then(function(response) { + return Promise.resolve(fetch(url)).then(function(response) { return response.arrayBuffer(); }).then(function(responseData) { // Decrypt the array buffer using the information taken from diff --git a/src/utils/MultiInviter.js b/src/utils/MultiInviter.js index 68a0800ed7..c26cc6b52e 100644 --- a/src/utils/MultiInviter.js +++ b/src/utils/MultiInviter.js @@ -15,7 +15,7 @@ limitations under the License. */ import {getAddressType, inviteToRoom} from '../Invite'; -import q from 'q'; +import Promise from 'bluebird'; /** * Invites multiple addresses to a room, handling rate limiting from the server @@ -55,7 +55,7 @@ export default class MultiInviter { this.errorTexts[addr] = 'Unrecognised address'; } } - this.deferred = q.defer(); + this.deferred = Promise.defer(); this._inviteMore(0); return this.deferred.promise; diff --git a/test/components/structures/ScrollPanel-test.js b/test/components/structures/ScrollPanel-test.js index a783f424e7..e7d3d7b0e6 100644 --- a/test/components/structures/ScrollPanel-test.js +++ b/test/components/structures/ScrollPanel-test.js @@ -18,7 +18,7 @@ var React = require('react'); var ReactDOM = require("react-dom"); var ReactTestUtils = require('react-addons-test-utils'); var expect = require('expect'); -var q = require('q'); +import Promise from 'bluebird'; var sdk = require('matrix-react-sdk'); @@ -58,7 +58,7 @@ var Tester = React.createClass({ if (handler) { res = handler(); } else { - res = q(false); + res = Promise.resolve(false); } if (defer) { @@ -74,7 +74,7 @@ var Tester = React.createClass({ /* returns a promise which will resolve when the fill happens */ awaitFill: function(dir) { console.log("ScrollPanel Tester: awaiting " + dir + " fill"); - var defer = q.defer(); + var defer = Promise.defer(); this._fillDefers[dir] = defer; return defer.promise; }, @@ -94,7 +94,7 @@ var Tester = React.createClass({ /* returns a promise which will resolve when a scroll event happens */ awaitScroll: function() { console.log("Awaiting scroll"); - this._scrollDefer = q.defer(); + this._scrollDefer = Promise.defer(); return this._scrollDefer.promise; }, @@ -168,7 +168,7 @@ describe('ScrollPanel', function() { const sp = tester.scrollPanel(); let retriesRemaining = 1; const awaitReady = function() { - return q().then(() => { + return Promise.resolve().then(() => { if (sp._pendingFillRequests.b === false && sp._pendingFillRequests.f === false ) { @@ -195,7 +195,7 @@ describe('ScrollPanel', function() { it('should handle scrollEvent strangeness', function() { const events = []; - return q().then(() => { + return Promise.resolve().then(() => { // initialise with a load of events for (let i = 0; i < 20; i++) { events.push(i+80); @@ -227,7 +227,7 @@ describe('ScrollPanel', function() { it('should not get stuck in #528 workaround', function(done) { var events = []; - q().then(() => { + Promise.resolve().then(() => { // initialise with a bunch of events for (var i = 0; i < 40; i++) { events.push(i); diff --git a/test/components/structures/TimelinePanel-test.js b/test/components/structures/TimelinePanel-test.js index 748e37bee3..98ec65b8e8 100644 --- a/test/components/structures/TimelinePanel-test.js +++ b/test/components/structures/TimelinePanel-test.js @@ -18,7 +18,7 @@ var React = require('react'); var ReactDOM = require('react-dom'); var ReactTestUtils = require('react-addons-test-utils'); var expect = require('expect'); -var q = require('q'); +import Promise from 'bluebird'; var sinon = require('sinon'); var jssdk = require('matrix-js-sdk'); @@ -145,20 +145,20 @@ describe('TimelinePanel', function() { // panel isn't paginating var awaitPaginationCompletion = function() { if(!panel.state.forwardPaginating) - return q(); + return Promise.resolve(); else - return q.delay(0).then(awaitPaginationCompletion); + return Promise.delay(0).then(awaitPaginationCompletion); }; // helper function which will return a promise which resolves when // the TimelinePanel fires a scroll event var awaitScroll = function() { - scrollDefer = q.defer(); + scrollDefer = Promise.defer(); return scrollDefer.promise; }; // let the first round of pagination finish off - q.delay(5).then(() => { + Promise.delay(5).then(() => { expect(panel.state.canBackPaginate).toBe(false); expect(scryEventTiles(panel).length).toEqual(N_EVENTS); @@ -214,7 +214,7 @@ describe('TimelinePanel', function() { client.paginateEventTimeline = sinon.spy((tl, opts) => { console.log("paginate:", opts); expect(opts.backwards).toBe(true); - return q(true); + return Promise.resolve(true); }); var rendered = ReactDOM.render( @@ -279,7 +279,7 @@ describe('TimelinePanel', function() { // helper function which will return a promise which resolves when // the TimelinePanel fires a scroll event var awaitScroll = function() { - scrollDefer = q.defer(); + scrollDefer = Promise.defer(); return scrollDefer.promise.then(() => { console.log("got scroll event; scrollTop now " + diff --git a/test/components/views/dialogs/InteractiveAuthDialog-test.js b/test/components/views/dialogs/InteractiveAuthDialog-test.js index ecfaba4e2c..f606793132 100644 --- a/test/components/views/dialogs/InteractiveAuthDialog-test.js +++ b/test/components/views/dialogs/InteractiveAuthDialog-test.js @@ -15,7 +15,7 @@ limitations under the License. */ import expect from 'expect'; -import q from 'q'; +import Promise from 'bluebird'; import React from 'react'; import ReactDOM from 'react-dom'; import ReactTestUtils from 'react-addons-test-utils'; @@ -50,7 +50,7 @@ describe('InteractiveAuthDialog', function () { it('Should successfully complete a password flow', function() { const onFinished = sinon.spy(); - const doRequest = sinon.stub().returns(q({a:1})); + const doRequest = sinon.stub().returns(Promise.resolve({a:1})); // tell the stub matrixclient to return a real userid var client = MatrixClientPeg.get(); @@ -110,7 +110,7 @@ describe('InteractiveAuthDialog', function () { ); // let the request complete - return q.delay(1); + return Promise.delay(1); }).then(() => { expect(onFinished.callCount).toEqual(1); expect(onFinished.calledWithExactly(true, {a:1})).toBe(true); diff --git a/test/components/views/rooms/MessageComposerInput-test.js b/test/components/views/rooms/MessageComposerInput-test.js index 6d4b4e69cc..fe379afcff 100644 --- a/test/components/views/rooms/MessageComposerInput-test.js +++ b/test/components/views/rooms/MessageComposerInput-test.js @@ -3,7 +3,7 @@ import ReactTestUtils from 'react-addons-test-utils'; import ReactDOM from 'react-dom'; import expect, {createSpy} from 'expect'; import sinon from 'sinon'; -import Q from 'q'; +import Promise from 'bluebird'; import * as testUtils from '../../../test-utils'; import sdk from 'matrix-react-sdk'; import UserSettingsStore from '../../../../src/UserSettingsStore'; @@ -47,7 +47,7 @@ describe('MessageComposerInput', () => { // warnings // (please can we make the components not setState() after // they are unmounted?) - Q.delay(10).done(() => { + Promise.delay(10).done(() => { if (parentDiv) { ReactDOM.unmountComponentAtNode(parentDiv); parentDiv.remove(); diff --git a/test/stores/RoomViewStore-test.js b/test/stores/RoomViewStore-test.js index adcae90e9b..be598de8da 100644 --- a/test/stores/RoomViewStore-test.js +++ b/test/stores/RoomViewStore-test.js @@ -7,7 +7,7 @@ import RoomViewStore from '../../src/stores/RoomViewStore'; import peg from '../../src/MatrixClientPeg'; import * as testUtils from '../test-utils'; -import q from 'q'; +import Promise from 'bluebird'; const dispatch = testUtils.getDispatchForStore(RoomViewStore); @@ -39,7 +39,7 @@ describe('RoomViewStore', function() { }); it('can be used to view a room by alias and join', function(done) { - peg.get().getRoomIdForAlias.returns(q({room_id: "!randomcharacters:aser.ver"})); + peg.get().getRoomIdForAlias.returns(Promise.resolve({room_id: "!randomcharacters:aser.ver"})); peg.get().joinRoom = (roomAddress) => { expect(roomAddress).toBe("#somealias2:aser.ver"); done(); diff --git a/test/test-utils.js b/test/test-utils.js index bc6b484bb5..23f16a2e4c 100644 --- a/test/test-utils.js +++ b/test/test-utils.js @@ -1,7 +1,7 @@ "use strict"; import sinon from 'sinon'; -import q from 'q'; +import Promise from 'bluebird'; import peg from '../src/MatrixClientPeg'; import dis from '../src/dispatcher'; @@ -75,12 +75,12 @@ export function createTestClient() { on: sinon.stub(), removeListener: sinon.stub(), isRoomEncrypted: sinon.stub().returns(false), - peekInRoom: sinon.stub().returns(q(mkStubRoom())), + peekInRoom: sinon.stub().returns(Promise.resolve(mkStubRoom())), - paginateEventTimeline: sinon.stub().returns(q()), - sendReadReceipt: sinon.stub().returns(q()), - getRoomIdForAlias: sinon.stub().returns(q()), - getProfileInfo: sinon.stub().returns(q({})), + paginateEventTimeline: sinon.stub().returns(Promise.resolve()), + sendReadReceipt: sinon.stub().returns(Promise.resolve()), + getRoomIdForAlias: sinon.stub().returns(Promise.resolve()), + getProfileInfo: sinon.stub().returns(Promise.resolve({})), getAccountData: (type) => { return mkEvent({ type, @@ -89,9 +89,9 @@ export function createTestClient() { }); }, setAccountData: sinon.stub(), - sendTyping: sinon.stub().returns(q({})), - sendTextMessage: () => q({}), - sendHtmlMessage: () => q({}), + sendTyping: sinon.stub().returns(Promise.resolve({})), + sendTextMessage: () => Promise.resolve({}), + sendHtmlMessage: () => Promise.resolve({}), getSyncState: () => "SYNCING", generateClientSecret: () => "t35tcl1Ent5ECr3T", isGuest: () => false, @@ -101,13 +101,13 @@ export function createTestClient() { export function createTestRtsClient(teamMap, sidMap) { return { getTeamsConfig() { - return q(Object.keys(teamMap).map((token) => teamMap[token])); + return Promise.resolve(Object.keys(teamMap).map((token) => teamMap[token])); }, trackReferral(referrer, emailSid, clientSecret) { - return q({team_token: sidMap[emailSid]}); + return Promise.resolve({team_token: sidMap[emailSid]}); }, getTeam(teamToken) { - return q(teamMap[teamToken]); + return Promise.resolve(teamMap[teamToken]); }, }; }