Merge remote-tracking branch 'origin/develop' into dbkr/groupview_edit

This commit is contained in:
David Baker 2017-07-17 17:23:02 +01:00
commit 7041106bf2
44 changed files with 363 additions and 203 deletions

View file

@ -1,4 +1,4 @@
{
"presets": ["react", "es2015", "es2016"],
"plugins": ["transform-class-properties", "transform-object-rest-spread", "transform-async-to-generator", "transform-runtime", "add-module-exports"]
"plugins": ["transform-class-properties", "transform-object-rest-spread", "transform-async-to-bluebird", "transform-runtime", "add-module-exports"]
}

View file

@ -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",
@ -85,7 +85,7 @@
"babel-eslint": "^6.1.2",
"babel-loader": "^6.2.5",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-transform-async-to-generator": "^6.16.0",
"babel-plugin-transform-async-to-bluebird": "^1.1.1",
"babel-plugin-transform-class-properties": "^6.16.0",
"babel-plugin-transform-object-rest-spread": "^6.16.0",
"babel-plugin-transform-runtime": "^6.15.0",

View file

@ -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);
@ -229,11 +229,13 @@ function readFileAsArrayBuffer(file) {
* @param {MatrixClient} matrixClient The matrix client to upload the file with.
* @param {String} roomId The ID of the room being uploaded to.
* @param {File} file The file to upload.
* @param {Function?} progressHandler optional callback to be called when a chunk of
* data is uploaded.
* @return {Promise} A promise that resolves with an object.
* If the file is unencrypted then the object will have a "url" key.
* If the file is encrypted then the object will have a "file" key.
*/
function uploadFile(matrixClient, roomId, file) {
function uploadFile(matrixClient, roomId, file, progressHandler) {
if (matrixClient.isRoomEncrypted(roomId)) {
// If the room is encrypted then encrypt the file before uploading it.
// First read the file into memory.
@ -245,7 +247,9 @@ function uploadFile(matrixClient, roomId, file) {
const encryptInfo = encryptResult.info;
// Pass the encrypted data as a Blob to the uploader.
const blob = new Blob([encryptResult.data]);
return matrixClient.uploadContent(blob).then(function(url) {
return matrixClient.uploadContent(blob, {
progressHandler: progressHandler,
}).then(function(url) {
// If the attachment is encrypted then bundle the URL along
// with the information needed to decrypt the attachment and
// add it under a file key.
@ -257,7 +261,9 @@ function uploadFile(matrixClient, roomId, file) {
});
});
} else {
const basePromise = matrixClient.uploadContent(file);
const basePromise = matrixClient.uploadContent(file, {
progressHandler: progressHandler,
});
const promise1 = basePromise.then(function(url) {
// If the attachment isn't encrypted then include the URL directly.
return {"url": url};
@ -288,7 +294,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=>{
@ -326,23 +332,24 @@ class ContentMessages {
dis.dispatch({action: 'upload_started'});
var error;
function onProgress(ev) {
upload.total = ev.total;
upload.loaded = ev.loaded;
dis.dispatch({action: 'upload_progress', upload: upload});
}
return def.promise.then(function() {
// XXX: upload.promise must be the promise that
// is returned by uploadFile as it has an abort()
// method hacked onto it.
upload.promise = uploadFile(
matrixClient, roomId, file
matrixClient, roomId, file, onProgress,
);
return upload.promise.then(function(result) {
content.file = result.file;
content.url = result.url;
});
}).progress(function(ev) {
if (ev) {
upload.total = ev.total;
upload.loaded = ev.loaded;
dis.dispatch({action: 'upload_progress', upload: upload});
}
}).then(function(url) {
return matrixClient.sendMessage(roomId, content);
}, function(err) {

View file

@ -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');

View file

@ -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,

View file

@ -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) {

View file

@ -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');

View file

@ -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({

View file

@ -491,7 +491,7 @@ function canSendEvent(event, roomId) {
}
if (!canSend) {
sendError(event, _t('You do not have permission in this room.'));
sendError(event, _t('You do not have permission to do that in this room.'));
return;
}

View file

@ -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
}

View file

@ -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,
@ -52,21 +52,24 @@ export async function getCompletions(query: string, selection: SelectionRange, f
otherwise, we run into a condition where new completions are displayed
while the user is interacting with the list, which makes it difficult
to predict whether an action will actually do what is intended
It ends up containing a list of Q promise states, which are objects with
state (== "fulfilled" || "rejected") and value. */
const completionsList = await Q.allSettled(
PROVIDERS.map(provider => {
return Q(provider.getCompletions(query, selection, force))
.timeout(PROVIDER_COMPLETION_TIMEOUT);
*/
const completionsList = await Promise.all(
// Array of inspections of promises that might timeout. Instead of allowing a
// single timeout to reject the Promise.all, reflect each one and once they've all
// settled, filter for the fulfilled ones
PROVIDERS.map((provider) => {
return provider
.getCompletions(query, selection, force)
.timeout(PROVIDER_COMPLETION_TIMEOUT)
.reflect();
}),
);
return completionsList
.filter(completion => completion.state === "fulfilled")
.map((completionsState, i) => {
return completionsList.filter(
(inspection) => inspection.isFulfilled(),
).map((completionsState, i) => {
return {
completions: completionsState.value,
completions: completionsState.value(),
provider: PROVIDERS[i],
/* the currently matched "command" the completer tried to complete

View file

@ -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

View file

@ -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();
});
},

View file

@ -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) {

View file

@ -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);

View file

@ -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');
@ -93,6 +93,10 @@ const SETTINGS_LABELS = [
id: 'enableSyntaxHighlightLanguageDetection',
label: 'Enable automatic language detection for syntax highlighting',
},
{
id: 'MessageComposerInput.autoReplaceEmoji',
label: 'Automatically replace plain text Emoji',
},
/*
{
id: 'useFixedWidthFont',
@ -199,7 +203,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 +301,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 +316,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 +568,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.
q.allSettled(promises).then(() => {
});
});
Promise.all(promises).then(() => {
this.setState({
rejectingInvites: false,
});
}).done();
});
},
_onExportE2eKeysClicked: function() {

View file

@ -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;

View file

@ -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) => {

View file

@ -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';

View file

@ -21,7 +21,9 @@ import React from 'react';
import MatrixClientPeg from '../../../MatrixClientPeg';
import ScalarAuthClient from '../../../ScalarAuthClient';
import SdkConfig from '../../../SdkConfig';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';
import sdk from '../../../index';
const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:'];
@ -33,6 +35,7 @@ export default React.createClass({
url: React.PropTypes.string.isRequired,
name: React.PropTypes.string.isRequired,
room: React.PropTypes.object.isRequired,
type: React.PropTypes.string.isRequired,
},
getDefaultProps: function() {
@ -86,8 +89,13 @@ export default React.createClass({
});
},
_onEditClick: function() {
console.log("Edit widget %s", this.props.id);
_onEditClick: function(e) {
console.log("Edit widget ID ", this.props.id);
const IntegrationsManager = sdk.getComponent("views.settings.IntegrationsManager");
const src = this._scalarClient.getScalarInterfaceUrlForRoom(this.props.room.roomId, 'type_' + this.props.type);
Modal.createDialog(IntegrationsManager, {
src: src,
}, "mx_IntegrationsManager");
},
_onDeleteClick: function() {
@ -120,10 +128,10 @@ export default React.createClass({
<div> Loading... </div>
);
} else {
// Note that there is advice saying allow-scripts shouldn;t be used with allow-same-origin
// Note that there is advice saying allow-scripts shouldn't be used with allow-same-origin
// because that would allow the iframe to prgramatically remove the sandbox attribute, but
// this would only be for content hosted on the same origin as the riot client: anything
// hosted on the same origin as the client will get the same access access as if you clicked
// hosted on the same origin as the client will get the same access as if you clicked
// a link to it.
const sandboxFlags = "allow-forms allow-popups allow-popups-to-escape-sandbox "+
"allow-same-origin allow-scripts";
@ -140,18 +148,22 @@ export default React.createClass({
</div>
);
}
// editing is done in scalar
const showEditButton = Boolean(this._scalarClient);
return (
<div className={this.props.fullWidth ? "mx_AppTileFullWidth" : "mx_AppTile"} id={this.props.id}>
<div className="mx_AppTileMenuBar">
{this.formatAppTileName()}
<span className="mx_AppTileMenuBarWidgets">
{/* Edit widget */}
{/* <img
{showEditButton && <img
src="img/edit.svg"
className="mx_filterFlipColor mx_AppTileMenuBarWidget mx_AppTileMenuBarWidgetPadding"
width="8" height="8" alt="Edit"
onClick={this._onEditClick}
/> */}
/>}
{/* Delete widget */}
<img src="img/cancel.svg"

View file

@ -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(); },
};

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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) {

View file

@ -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");

View file

@ -169,6 +169,7 @@ module.exports = React.createClass({
id={app.id}
url={app.url}
name={app.name}
type={app.type}
fullWidth={arr.length<2 ? true : false}
room={this.props.room}
userId={this.props.userId}

View file

@ -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,

View file

@ -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");

View file

@ -41,7 +41,6 @@ export default class MessageComposer extends React.Component {
this.onToggleMarkdownClicked = this.onToggleMarkdownClicked.bind(this);
this.onInputStateChanged = this.onInputStateChanged.bind(this);
this.onEvent = this.onEvent.bind(this);
this.onPageUnload = this.onPageUnload.bind(this);
this.state = {
autocompleteQuery: '',
@ -62,21 +61,12 @@ export default class MessageComposer extends React.Component {
// marked as encrypted.
// XXX: fragile as all hell - fixme somehow, perhaps with a dedicated Room.encryption event or something.
MatrixClientPeg.get().on("event", this.onEvent);
window.addEventListener('beforeunload', this.onPageUnload);
}
componentWillUnmount() {
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("event", this.onEvent);
}
window.removeEventListener('beforeunload', this.onPageUnload);
}
onPageUnload(event) {
if (this.messageComposerInput) {
this.messageComposerInput.sentHistory.saveLastTextEntry();
}
}
onEvent(event) {

View file

@ -16,16 +16,17 @@ limitations under the License.
import React from 'react';
import type SyntheticKeyboardEvent from 'react/lib/SyntheticKeyboardEvent';
import {Editor, EditorState, RichUtils, CompositeDecorator,
convertFromRaw, convertToRaw, Modifier, EditorChangeType,
getDefaultKeyBinding, KeyBindingUtil, ContentState, ContentBlock, SelectionState} from 'draft-js';
import {Editor, EditorState, RichUtils, CompositeDecorator, Modifier,
getDefaultKeyBinding, KeyBindingUtil, ContentState, ContentBlock, SelectionState,
Entity} from 'draft-js';
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';
import {RoomMember} from 'matrix-js-sdk';
import SlashCommands from '../../../SlashCommands';
import KeyCode from '../../../KeyCode';
import Modal from '../../../Modal';
@ -43,6 +44,14 @@ import Markdown from '../../../Markdown';
import ComposerHistoryManager from '../../../ComposerHistoryManager';
import MessageComposerStore from '../../../stores/MessageComposerStore';
import {MATRIXTO_URL_PATTERN} from '../../../linkify-matrix';
const REGEX_MATRIXTO = new RegExp(MATRIXTO_URL_PATTERN);
import {asciiRegexp, shortnameToUnicode, emojioneList, asciiList, mapUnicodeToShort} from 'emojione';
const EMOJI_SHORTNAMES = Object.keys(emojioneList);
const EMOJI_UNICODE_TO_SHORTNAME = mapUnicodeToShort();
const REGEX_EMOJI_WHITESPACE = new RegExp('(' + asciiRegexp + ')\\s$');
const TYPING_USER_TIMEOUT = 10000, TYPING_SERVER_TIMEOUT = 30000;
const ZWS_CODE = 8203;
@ -156,15 +165,72 @@ export default class MessageComposerInput extends React.Component {
this.client = MatrixClientPeg.get();
}
findLinkEntities(contentBlock, callback) {
contentBlock.findEntityRanges(
(character) => {
const entityKey = character.getEntity();
return (
entityKey !== null &&
Entity.get(entityKey).getType() === 'LINK'
);
}, callback,
);
}
/*
* "Does the right thing" to create an EditorState, based on:
* - whether we've got rich text mode enabled
* - contentState was passed in
*/
createEditorState(richText: boolean, contentState: ?ContentState): EditorState {
let decorators = richText ? RichText.getScopedRTDecorators(this.props) :
RichText.getScopedMDDecorators(this.props),
compositeDecorator = new CompositeDecorator(decorators);
const decorators = richText ? RichText.getScopedRTDecorators(this.props) :
RichText.getScopedMDDecorators(this.props);
decorators.push({
strategy: this.findLinkEntities.bind(this),
component: (props) => {
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
const RoomAvatar = sdk.getComponent('avatars.RoomAvatar');
const {url} = Entity.get(props.entityKey).getData();
const matrixToMatch = REGEX_MATRIXTO.exec(url);
const isUserPill = matrixToMatch[2] === '@';
const isRoomPill = matrixToMatch[2] === '#' || matrixToMatch[2] === '!';
const classes = classNames({
"mx_UserPill": isUserPill,
"mx_RoomPill": isRoomPill,
});
let avatar = null;
if (isUserPill) {
// If this user is not a member of this room, default to the empty
// member. This could be improved by doing an async profile lookup.
const member = this.props.room.getMember(matrixToMatch[1]) ||
new RoomMember(null, matrixToMatch[1]);
avatar = member ? <MemberAvatar member={member} width={16} height={16}/> : null;
} else if (isRoomPill) {
const room = matrixToMatch[2] === '#' ?
MatrixClientPeg.get().getRooms().find((r) => {
return r.getCanonicalAlias() === matrixToMatch[1];
}) : MatrixClientPeg.get().getRoom(matrixToMatch[1]);
avatar = room ? <RoomAvatar room={room} width={16} height={16}/> : null;
}
if (isUserPill || isRoomPill) {
return (
<span className={classes}>
{avatar}
{props.children}
</span>
);
}
return (
<a href={url}>
{props.children}
</a>
);
},
});
const compositeDecorator = new CompositeDecorator(decorators);
let editorState = null;
if (contentState) {
@ -319,6 +385,60 @@ export default class MessageComposerInput extends React.Component {
onEditorContentChanged = (editorState: EditorState) => {
editorState = RichText.attachImmutableEntitiesToEmoji(editorState);
const currentBlock = editorState.getSelection().getStartKey();
const currentSelection = editorState.getSelection();
const currentStartOffset = editorState.getSelection().getStartOffset();
const block = editorState.getCurrentContent().getBlockForKey(currentBlock);
const text = block.getText();
const entityBeforeCurrentOffset = block.getEntityAt(currentStartOffset - 1);
const entityAtCurrentOffset = block.getEntityAt(currentStartOffset);
// If the cursor is on the boundary between an entity and a non-entity and the
// text before the cursor has whitespace at the end, set the entity state of the
// character before the cursor (the whitespace) to null. This allows the user to
// stop editing the link.
if (entityBeforeCurrentOffset && !entityAtCurrentOffset &&
/\s$/.test(text.slice(0, currentStartOffset))) {
editorState = RichUtils.toggleLink(
editorState,
currentSelection.merge({
anchorOffset: currentStartOffset - 1,
focusOffset: currentStartOffset,
}),
null,
);
// Reset selection
editorState = EditorState.forceSelection(editorState, currentSelection);
}
// Automatic replacement of plaintext emoji to Unicode emoji
if (UserSettingsStore.getSyncedSetting('MessageComposerInput.autoReplaceEmoji', false)) {
// The first matched group includes just the matched plaintext emoji
const emojiMatch = REGEX_EMOJI_WHITESPACE.exec(text.slice(0, currentStartOffset));
if(emojiMatch) {
// plaintext -> hex unicode
const emojiUc = asciiList[emojiMatch[1]];
// hex unicode -> shortname -> actual unicode
const unicodeEmoji = shortnameToUnicode(EMOJI_UNICODE_TO_SHORTNAME[emojiUc]);
const newContentState = Modifier.replaceText(
editorState.getCurrentContent(),
currentSelection.merge({
anchorOffset: currentStartOffset - emojiMatch[0].length,
focusOffset: currentStartOffset,
}),
unicodeEmoji,
);
editorState = EditorState.push(
editorState,
newContentState,
'insert-characters',
);
editorState = EditorState.forceSelection(editorState, newContentState.getSelectionAfter());
}
}
/* Since a modification was made, set originalEditorState to null, since newState is now our original */
this.setState({
editorState,
@ -517,10 +637,13 @@ export default class MessageComposerInput extends React.Component {
}
const currentBlockType = RichUtils.getCurrentBlockType(this.state.editorState);
// If we're in any of these three types of blocks, shift enter should insert soft newlines
// And just enter should end the block
// XXX: Empirically enter does not end these blocks
if(['blockquote', 'unordered-list-item', 'ordered-list-item'].includes(currentBlockType)) {
if(
['code-block', 'blockquote', 'unordered-list-item', 'ordered-list-item']
.includes(currentBlockType)
) {
// By returning false, we allow the default draft-js key binding to occur,
// which in this case invokes "split-block". This creates a new block of the
// same type, allowing the user to delete it with backspace.
return false;
}
@ -581,6 +704,15 @@ export default class MessageComposerInput extends React.Component {
}
});
}
if (!shouldSendHTML) {
const hasLink = blocks.some((block) => {
return block.getCharacterList().filter((c) => {
const entityKey = c.getEntity();
return entityKey && Entity.get(entityKey).getType() === 'LINK';
}).size > 0;
});
shouldSendHTML = hasLink;
}
if (shouldSendHTML) {
contentHTML = HtmlUtils.processHtmlForSending(
RichText.contentStateToHTML(contentState),

View file

@ -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 (!p.isFulfilled()) {
promises.push(p);
}
@ -294,7 +310,7 @@ module.exports = React.createClass({
// encryption
p = this.saveEnableEncryption();
if (!q.isFulfilled(p)) {
if (!p.isFulfilled()) {
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(

View file

@ -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, {

View file

@ -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

View file

@ -956,5 +956,6 @@
"Featured Rooms:": "Featured Rooms:",
"Error whilst fetching joined groups": "Error whilst fetching joined groups",
"Featured Users:": "Featured Users:",
"Edit Group": "Edit Group"
"Edit Group": "Edit Group",
"Automatically replace plain text Emoji": "Automatically replace plain text Emoji"
}

View file

@ -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(

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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 " +

View file

@ -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);

View file

@ -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();

View file

@ -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();

View file

@ -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]);
},
};
}