diff --git a/.gitignore b/.gitignore index 7cbd6fc2..f5a3b1bd 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ lib .DS_Store key.pem cert.pem -build +vector/components.css diff --git a/README.md b/README.md index c834e013..529e7cdf 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,10 @@ about them: 2. `cd matrix-react-sdk` 3. `git checkout develop` 4. `npm install` -5. `npm start` (to start the dev rebuilder) -6. `cd ../vector-web` -7. Link the react sdk package into the example: +5. `npm run build` +6. `npm start` (to start the dev rebuilder) +7. `cd ../vector-web` +8. Link the react sdk package into the example: `npm link path/to/your/react/sdk` Similarly, you may need to `npm link path/to/your/js/sdk` in your `matrix-react-sdk` @@ -53,6 +54,34 @@ about "Cannot resolve module 'source-map-loader'" due to shortcomings in webpack Deployment ========== -Just run `npm build` and then mount the `vector` directory on your webserver to +Just run `npm run build` and then mount the `vector` directory on your webserver to actually serve up the app, which is entirely static content. +Enabling encryption +=================== + +End-to-end encryption in Vector and Matrix is not yet considered ready for +day-to-day use; it is experimental and should be considered only as a +proof-of-concept. See https://matrix.org/jira/browse/SPEC-162 for an overview +of the current progress. + +To build a version of vector with support for end-to-end encryption, install +the olm module with `npm i https://matrix.org/packages/npm/olm/olm-0.1.0.tgz` +before running `npm start`. The olm library will be detected and used if +available. + +To enable encryption for a room, type + +``` +/encrypt on +``` + +in the message bar in that room. Vector will then generate a set of keys, and +encrypt all outgoing messages in that room. (Note that other people in that +room will send messages in the clear unless they also `/encrypt on`.) + +Note that historical encrypted messages cannot currently be decoded - history +is therefore lost when the page is reloaded. + +There is currently no visual indication of whether encryption is enabled for a +room, or whether a particular message was encrypted. diff --git a/package.json b/package.json index fb7558ad..88df7833 100644 --- a/package.json +++ b/package.json @@ -9,46 +9,51 @@ }, "license": "Apache-2.0", "style": "bundle.css", + "matrix-react-parent": "matrix-react-sdk", "scripts": { - "reskindex": "reskindex vector -h src/skins/vector/header", + "reskindex": "reskindex -h src/header", "build:modernizr": "modernizr -c .modernizr.json -d src/vector/modernizr.js", - "build:css": "catw \"src/skins/vector/css/**/*.css\" -o vector/bundle.css -c uglifycss --no-watch", + "build:css": "catw \"src/skins/vector/css/**/*.css\" -o vector/components.css --no-watch", "build:compile": "babel --source-maps -d lib src", "build:bundle": "NODE_ENV=production webpack -p lib/vector/index.js vector/bundle.js", "build": "npm run build:css && npm run build:compile && npm run build:bundle", "start:js": "webpack -w src/vector/index.js vector/bundle.js", - "start:skins:css": "catw \"src/skins/vector/css/**/*.css\" -o vector/bundle.css", + "start:skins:css": "catw \"src/skins/vector/css/**/*.css\" -o vector/components.css", "//cache": "Note the -c 1 below due to https://code.google.com/p/chromium/issues/detail?id=508270", "start": "parallelshell \"npm run start:js\" \"npm run start:skins:css\" \"http-server -c 1 vector\"", - "clean": "rimraf lib vector/bundle.css vector/bundle.js vector/bundle.js.map", + "clean": "rimraf lib vector/bundle.css vector/bundle.js vector/bundle.js.map vector/webpack.css*", "prepublish": "npm run build:css && npm run build:compile" }, "dependencies": { "classnames": "^2.1.2", + "extract-text-webpack-plugin": "^0.9.1", "filesize": "^3.1.2", "flux": "~2.0.3", + "gemini-scrollbar": "^1.3.0", + "gfm.css": "^1.1.1", + "highlight.js": "^9.0.0", "linkifyjs": "^2.0.0-beta.4", - "matrix-js-sdk": "^0.3.0", - "matrix-react-sdk": "^0.0.2", + "matrix-js-sdk": "https://github.com/matrix-org/matrix-js-sdk.git#develop", + "matrix-react-sdk": "https://github.com/matrix-org/matrix-react-sdk.git#develop", "modernizr": "^3.1.0", "q": "^1.4.1", "react": "^0.14.2", "react-dnd": "^2.0.2", "react-dnd-html5-backend": "^2.0.0", "react-dom": "^0.14.2", - "react-gemini-scrollbar": "^2.0.1", - "sanitize-html": "^1.0.0" + "react-gemini-scrollbar": "^2.0.1" }, "devDependencies": { "babel": "^5.8.23", "babel-core": "^5.8.25", "babel-loader": "^5.3.2", "catw": "^1.0.1", + "css-raw-loader": "^0.1.1", "http-server": "^0.8.4", "json-loader": "^0.5.3", "parallelshell": "^1.2.0", "rimraf": "^2.4.3", "source-map-loader": "^0.1.5", - "uglifycss": "0.0.15" + "webpack": "^1.12.6" } } diff --git a/src/Avatar.js b/src/Avatar.js deleted file mode 100644 index afc5e9dd..00000000 --- a/src/Avatar.js +++ /dev/null @@ -1,53 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); - -module.exports = { - avatarUrlForMember: function(member, width, height, resizeMethod) { - var url = member.getAvatarUrl( - MatrixClientPeg.get().getHomeserverUrl(), - width, - height, - resizeMethod - ); - if (!url) { - // member can be null here currently since on invites, the JS SDK - // does not have enough info to build a RoomMember object for - // the inviter. - url = this.defaultAvatarUrlForString(member ? member.userId : ''); - } - return url; - }, - - defaultAvatarUrlForString: function(s) { - var total = 0; - for (var i = 0; i < s.length; ++i) { - total += s.charCodeAt(i); - } - switch (total % 3) { - case 0: - return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNrszQENADAIACB9QjNbxSKP4eagAFnTseHFErFYLBaLxWKxWCwWi8Vi8cX4CzAABSwCRWJw31gAAAAASUVORK5CYII="; - case 1: - return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNrszQENADAIACB9chOaxgCP4eagAFk9seHFErFYLBaLxWKxWCwWi8Vi8cX4CzAAtKMCks/JG8MAAAAASUVORK5CYII="; - case 2: - return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNrszQENADAIACB9YzNayQCP4eagADldseHFErFYLBaLxWKxWCwWi8Vi8cX4CzAAyiACeHwPiu4AAAAASUVORK5CYII="; - } - } -} - diff --git a/src/ContextualMenu.js b/src/ContextualMenu.js deleted file mode 100644 index 3327aa94..00000000 --- a/src/ContextualMenu.js +++ /dev/null @@ -1,82 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - - -'use strict'; - -var React = require('react'); -var ReactDOM = require('react-dom'); - -// Shamelessly ripped off Modal.js. There's probably a better way -// of doing reusable widgets like dialog boxes & menus where we go and -// pass in a custom control as the actual body. - -module.exports = { - ContextualMenuContainerId: "mx_ContextualMenu_Container", - - getOrCreateContainer: function() { - var container = document.getElementById(this.ContextualMenuContainerId); - - if (!container) { - container = document.createElement("div"); - container.id = this.ContextualMenuContainerId; - document.body.appendChild(container); - } - - return container; - }, - - createMenu: function (Element, props) { - var self = this; - - var closeMenu = function() { - React.unmountComponentAtNode(self.getOrCreateContainer()); - - if (props && props.onFinished) props.onFinished.apply(null, arguments); - }; - - var position = { - top: props.top - 20, - }; - - var chevron = null; - if (props.left) { - chevron = - position.left = props.left + 8; - } else { - chevron = - position.right = props.right + 8; - } - - var className = 'mx_ContextualMenu_wrapper'; - - // FIXME: If a menu uses getDefaultProps it clobbers the onFinished - // property set here so you can't close the menu from a button click! - var menu = ( -
-
- {chevron} - -
-
-
- ); - - ReactDOM.render(menu, this.getOrCreateContainer()); - - return {close: closeMenu}; - }, -}; diff --git a/src/DateUtils.js b/src/DateUtils.js deleted file mode 100644 index fe363586..00000000 --- a/src/DateUtils.js +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; -var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; - -module.exports = { - formatDate: function(date) { - // date.toLocaleTimeString is completely system dependent. - // just go 24h for now - function pad(n) { - return (n < 10 ? '0' : '') + n; - } - - var now = new Date(); - if (date.toDateString() === now.toDateString()) { - return pad(date.getHours()) + ':' + pad(date.getMinutes()); - } - else if (now.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) { - return days[date.getDay()] + " " + pad(date.getHours()) + ':' + pad(date.getMinutes()); - } - else if (now.getFullYear() === date.getFullYear()) { - return days[date.getDay()] + ", " + months[date.getMonth()] + " " + (date.getDay()+1) + " " + pad(date.getHours()) + ':' + pad(date.getMinutes()); - } - else { - return days[date.getDay()] + ", " + months[date.getMonth()] + " " + (date.getDay()+1) + " " + date.getFullYear() + " " + pad(date.getHours()) + ':' + pad(date.getMinutes()); - } - } -} - diff --git a/src/Resend.js b/src/Resend.js deleted file mode 100644 index 5d7d7815..00000000 --- a/src/Resend.js +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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 MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); -var dis = require('matrix-react-sdk/lib/dispatcher'); - -module.exports = { - resend: function(event) { - MatrixClientPeg.get().resendEvent( - event, MatrixClientPeg.get().getRoom(event.getRoomId()) - ).done(function() { - dis.dispatch({ - action: 'message_sent', - event: event - }); - }, function() { - dis.dispatch({ - action: 'message_send_failed', - event: event - }); - }); - dis.dispatch({ - action: 'message_resend_started', - event: event - }); - }, -}; \ No newline at end of file diff --git a/src/modules/VectorConferenceHandler.js b/src/VectorConferenceHandler.js similarity index 93% rename from src/modules/VectorConferenceHandler.js rename to src/VectorConferenceHandler.js index 637e34f9..7628e0f5 100644 --- a/src/modules/VectorConferenceHandler.js +++ b/src/VectorConferenceHandler.js @@ -85,15 +85,15 @@ ConferenceCall.prototype._getConferenceUserRoom = function() { }; /** - * Check if this room member is in fact a conference bot. - * @param {RoomMember} The room member to check + * Check if this user ID is in fact a conference bot. + * @param {string} userId The user ID to check. * @return {boolean} True if it is a conference bot. */ -module.exports.isConferenceUser = function(roomMember) { - if (roomMember.userId.indexOf("@" + USER_PREFIX) !== 0) { +module.exports.isConferenceUser = function(userId) { + if (userId.indexOf("@" + USER_PREFIX) !== 0) { return false; } - var base64part = roomMember.userId.split(":")[0].substring(1 + USER_PREFIX.length); + var base64part = userId.split(":")[0].substring(1 + USER_PREFIX.length); if (base64part) { var decoded = new Buffer(base64part, "base64").toString(); // ! $STUFF : $STUFF diff --git a/src/component-index.js b/src/component-index.js new file mode 100644 index 00000000..e6ff997e --- /dev/null +++ b/src/component-index.js @@ -0,0 +1,47 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +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. +*/ + +/* + * THIS FILE IS AUTO-GENERATED + * You can edit it you like, but your changes will be overwritten, + * so you'd just be trying to swim upstream like a salmon. + * You are not a salmon. + */ + +module.exports.components = require('matrix-react-sdk/lib/component-index').components; + +module.exports.components['structures.BottomLeftMenu'] = require('./components/structures/BottomLeftMenu'); +module.exports.components['structures.CompatibilityPage'] = require('./components/structures/CompatibilityPage'); +module.exports.components['structures.LeftPanel'] = require('./components/structures/LeftPanel'); +module.exports.components['structures.RightPanel'] = require('./components/structures/RightPanel'); +module.exports.components['structures.RoomDirectory'] = require('./components/structures/RoomDirectory'); +module.exports.components['structures.RoomSubList'] = require('./components/structures/RoomSubList'); +module.exports.components['structures.ViewSource'] = require('./components/structures/ViewSource'); +module.exports.components['views.elements.ImageView'] = require('./components/views/elements/ImageView'); +module.exports.components['views.elements.Spinner'] = require('./components/views/elements/Spinner'); +module.exports.components['views.globals.MatrixToolbar'] = require('./components/views/globals/MatrixToolbar'); +module.exports.components['views.login.CustomServerDialog'] = require('./components/views/login/VectorCustomServerDialog'); +module.exports.components['views.login.LoginFooter'] = require('./components/views/login/VectorLoginFooter'); +module.exports.components['views.login.LoginHeader'] = require('./components/views/login/VectorLoginHeader'); +module.exports.components['views.messages.DateSeparator'] = require('./components/views/messages/DateSeparator'); +module.exports.components['views.messages.MessageTimestamp'] = require('./components/views/messages/MessageTimestamp'); +module.exports.components['views.messages.SenderProfile'] = require('./components/views/messages/SenderProfile'); +module.exports.components['views.rooms.BottomLeftMenuTile'] = require('./components/views/rooms/BottomLeftMenuTile'); +module.exports.components['views.rooms.MessageContextMenu'] = require('./components/views/rooms/MessageContextMenu'); +module.exports.components['views.rooms.RoomDNDView'] = require('./components/views/rooms/RoomDNDView'); +module.exports.components['views.rooms.RoomDropTarget'] = require('./components/views/rooms/RoomDropTarget'); +module.exports.components['views.rooms.RoomTooltip'] = require('./components/views/rooms/RoomTooltip'); +module.exports.components['views.rooms.SearchBar'] = require('./components/views/rooms/SearchBar'); diff --git a/src/skins/vector/views/molecules/BottomLeftMenu.js b/src/components/structures/BottomLeftMenu.js similarity index 92% rename from src/skins/vector/views/molecules/BottomLeftMenu.js rename to src/components/structures/BottomLeftMenu.js index 2020d29d..f942efd5 100644 --- a/src/skins/vector/views/molecules/BottomLeftMenu.js +++ b/src/components/structures/BottomLeftMenu.js @@ -40,13 +40,13 @@ module.exports = React.createClass({ return
{name}
} else if (this.state.hover) { - var RoomTooltip = sdk.getComponent("molecules.RoomTooltip"); + var RoomTooltip = sdk.getComponent("rooms.RoomTooltip"); return ; } }, render: function() { - var BottomLeftMenuTile = sdk.getComponent('molecules.BottomLeftMenuTile'); + var BottomLeftMenuTile = sdk.getComponent('rooms.BottomLeftMenuTile'); return (
diff --git a/src/skins/vector/views/pages/CompatibilityPage.js b/src/components/structures/CompatibilityPage.js similarity index 100% rename from src/skins/vector/views/pages/CompatibilityPage.js rename to src/components/structures/CompatibilityPage.js diff --git a/src/skins/vector/views/organisms/LeftPanel.js b/src/components/structures/LeftPanel.js similarity index 81% rename from src/skins/vector/views/organisms/LeftPanel.js rename to src/components/structures/LeftPanel.js index 96d48e0e..aaab8084 100644 --- a/src/skins/vector/views/organisms/LeftPanel.js +++ b/src/components/structures/LeftPanel.js @@ -22,6 +22,7 @@ var HTML5Backend = require('react-dnd-html5-backend'); var sdk = require('matrix-react-sdk') var dis = require('matrix-react-sdk/lib/dispatcher'); +var VectorConferenceHandler = require('../../VectorConferenceHandler'); var CallHandler = require("matrix-react-sdk/lib/CallHandler"); var LeftPanel = React.createClass({ @@ -84,9 +85,9 @@ var LeftPanel = React.createClass({ }, render: function() { - var RoomList = sdk.getComponent('organisms.RoomList'); - var BottomLeftMenu = sdk.getComponent('molecules.BottomLeftMenu'); - var IncomingCallBox = sdk.getComponent('molecules.voip.IncomingCallBox'); + var RoomList = sdk.getComponent('rooms.RoomList'); + var BottomLeftMenu = sdk.getComponent('structures.BottomLeftMenu'); + var IncomingCallBox = sdk.getComponent('voip.IncomingCallBox'); var collapseButton; var classes = "mx_LeftPanel"; @@ -100,8 +101,12 @@ var LeftPanel = React.createClass({ var callPreview; if (this.state.showCallElement) { - var CallView = sdk.getComponent('molecules.voip.CallView'); - callPreview = + var CallView = sdk.getComponent('voip.CallView'); + callPreview = ( + + ); } return ( @@ -109,7 +114,10 @@ var LeftPanel = React.createClass({ { collapseButton } { callPreview } - + ); diff --git a/src/skins/vector/views/organisms/RightPanel.js b/src/components/structures/RightPanel.js similarity index 90% rename from src/skins/vector/views/organisms/RightPanel.js rename to src/components/structures/RightPanel.js index feebcfeb..f4f0a8f3 100644 --- a/src/skins/vector/views/organisms/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -68,6 +68,11 @@ module.exports = React.createClass({ if (this.state.phase == this.Phase.MemberList && member.roomId === this.props.roomId) { this.forceUpdate(); } + else if (this.state.phase === this.Phase.MemberInfo && member.roomId === this.props.roomId && + member.userId === this.state.member.userId) { + // refresh the member info (e.g. new power level) + this.forceUpdate(); + } }, onAction: function(payload) { @@ -94,7 +99,7 @@ module.exports = React.createClass({ }, render: function() { - var MemberList = sdk.getComponent('organisms.MemberList'); + var MemberList = sdk.getComponent('rooms.MemberList'); var buttonGroup; var panel; @@ -122,12 +127,12 @@ module.exports = React.createClass({ buttonGroup =
- Members + Members { membersBadge } { membersHighlight }
- Files + Files { filesHighlight }
; @@ -137,7 +142,7 @@ module.exports = React.createClass({ panel = } else if(this.state.phase == this.Phase.MemberInfo) { - var MemberInfo = sdk.getComponent('molecules.MemberInfo'); + var MemberInfo = sdk.getComponent('rooms.MemberInfo'); panel = } } diff --git a/src/skins/vector/views/organisms/RoomDirectory.js b/src/components/structures/RoomDirectory.js similarity index 94% rename from src/skins/vector/views/organisms/RoomDirectory.js rename to src/components/structures/RoomDirectory.js index 28135bfe..c1a29779 100644 --- a/src/skins/vector/views/organisms/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -40,7 +40,7 @@ module.exports = React.createClass({ if (err) { self.setState({ loading: false }); console.error("Failed to get publicRooms: %s", JSON.stringify(err)); - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); + var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { title: "Failed to get public room list", description: err.message @@ -67,7 +67,7 @@ module.exports = React.createClass({ }); }, function(err) { console.error("Failed to join room: %s", JSON.stringify(err)); - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); + var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { title: "Failed to join room", description: err.message @@ -119,7 +119,7 @@ module.exports = React.createClass({ render: function() { if (this.state.loading) { - var Loader = sdk.getComponent("atoms.Spinner"); + var Loader = sdk.getComponent("elements.Spinner"); return (
@@ -127,7 +127,7 @@ module.exports = React.createClass({ ); } - var RoomHeader = sdk.getComponent('molecules.RoomHeader'); + var RoomHeader = sdk.getComponent('rooms.RoomHeader'); return (
diff --git a/src/skins/vector/views/organisms/RoomSubList.js b/src/components/structures/RoomSubList.js similarity index 92% rename from src/skins/vector/views/organisms/RoomSubList.js rename to src/components/structures/RoomSubList.js index 35210b49..f7efb425 100644 --- a/src/skins/vector/views/organisms/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -20,6 +20,7 @@ var React = require('react'); var DropTarget = require('react-dnd').DropTarget; var sdk = require('matrix-react-sdk') var dis = require('matrix-react-sdk/lib/dispatcher'); +var UnreadStatus = require('matrix-react-sdk/lib/UnreadStatus'); // turn this on for drop & drag console debugging galore var debug = false; @@ -88,10 +89,20 @@ var RoomSubList = React.createClass({ }, tsOfNewestEvent: function(room) { - if (room.timeline.length) { - return room.timeline[room.timeline.length - 1].getTs(); + for (var i = room.timeline.length - 1; i >= 0; --i) { + var ev = room.timeline[i]; + // logic copied from RoomList.js for when we do/don't highlight + if (UnreadStatus.eventTriggersUnreadCount(ev)) { + return ev.getTs(); + } } - else { + + // we might only have events that don't trigger the unread indicator, + // in which case use the oldest event even if normally it wouldn't count. + // This is better than just assuming the last event was forever ago. + if (room.timeline.length) { + return room.timeline[0].getTs(); + } else { return Number.MAX_SAFE_INTEGER; } }, @@ -215,7 +226,7 @@ var RoomSubList = React.createClass({ makeRoomTiles: function() { var self = this; - var RoomTile = sdk.getComponent("molecules.RoomTile"); + var RoomTile = sdk.getComponent("rooms.RoomTile"); return this.state.sortedList.map(function(room) { var selected = room.roomId == self.props.selectedRoom; // XXX: is it evil to pass in self as a prop to RoomTile? @@ -235,7 +246,7 @@ var RoomSubList = React.createClass({ render: function() { var connectDropTarget = this.props.connectDropTarget; - var RoomDropTarget = sdk.getComponent('molecules.RoomDropTarget'); + var RoomDropTarget = sdk.getComponent('rooms.RoomDropTarget'); var label = this.props.collapsed ? null : this.props.label; @@ -265,7 +276,7 @@ var RoomSubList = React.createClass({ return connectDropTarget(

{ this.props.collapsed ? '' : this.props.label } - +

{ subList }
diff --git a/src/skins/vector/views/organisms/ViewSource.js b/src/components/structures/ViewSource.js similarity index 100% rename from src/skins/vector/views/organisms/ViewSource.js rename to src/components/structures/ViewSource.js diff --git a/src/skins/vector/views/atoms/ImageView.js b/src/components/views/elements/ImageView.js similarity index 91% rename from src/skins/vector/views/atoms/ImageView.js rename to src/components/views/elements/ImageView.js index a842f7c8..741524be 100644 --- a/src/skins/vector/views/atoms/ImageView.js +++ b/src/components/views/elements/ImageView.js @@ -20,7 +20,7 @@ var React = require('react'); var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); -var DateUtils = require('../../../../DateUtils'); +var DateUtils = require('matrix-react-sdk/lib/DateUtils'); var filesize = require('filesize'); module.exports = React.createClass({ @@ -30,7 +30,8 @@ module.exports = React.createClass({ onFinished: React.PropTypes.func.isRequired }, - // XXX: keyboard shortcuts for managing dialogs should be done by the modal dialog base class somehow, surely... + // XXX: keyboard shortcuts for managing dialogs should be done by the modal + // dialog base class somehow, surely... componentDidMount: function() { document.addEventListener("keydown", this.onKeyDown); }, @@ -54,7 +55,7 @@ module.exports = React.createClass({ ).done(function() { if (self.props.onFinished) self.props.onFinished(); }, function(e) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); + var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); // display error message stating you couldn't delete this. var code = e.errcode || e.statusCode; Modal.createDialog(ErrorDialog, { @@ -104,6 +105,11 @@ module.exports = React.createClass({ res = ", " + style.width + "x" + style.height + "px"; } + var size; + if (this.props.mxEvent.getContent().info && this.props.mxEvent.getContent().info.size) { + size = filesize(this.props.mxEvent.getContent().info.size); + } + return (
@@ -123,7 +129,7 @@ module.exports = React.createClass({
Download this file
- ({ filesize(this.props.mxEvent.getContent().info.size) }{ res }) + { size } { res }
diff --git a/src/skins/vector/views/atoms/Spinner.js b/src/components/views/elements/Spinner.js similarity index 100% rename from src/skins/vector/views/atoms/Spinner.js rename to src/components/views/elements/Spinner.js diff --git a/src/skins/vector/views/molecules/MatrixToolbar.js b/src/components/views/globals/MatrixToolbar.js similarity index 83% rename from src/skins/vector/views/molecules/MatrixToolbar.js rename to src/components/views/globals/MatrixToolbar.js index 5b613f56..7b953c4a 100644 --- a/src/skins/vector/views/molecules/MatrixToolbar.js +++ b/src/components/views/globals/MatrixToolbar.js @@ -17,30 +17,28 @@ limitations under the License. 'use strict'; var React = require('react'); - +var Notifier = require("matrix-react-sdk/lib/Notifier"); var sdk = require('matrix-react-sdk') module.exports = React.createClass({ displayName: 'MatrixToolbar', hideToolbar: function() { - var Notifier = sdk.getComponent('organisms.Notifier'); Notifier.setToolbarHidden(true); }, onClick: function() { - var Notifier = sdk.getComponent('organisms.Notifier'); Notifier.setEnabled(true); }, render: function() { return (
- /!\ + /!\
You are not receiving desktop notifications. Enable them now
-
+
); } diff --git a/src/skins/vector/views/organisms/ErrorDialog.js b/src/components/views/login/VectorCustomServerDialog.js similarity index 53% rename from src/skins/vector/views/organisms/ErrorDialog.js rename to src/components/views/login/VectorCustomServerDialog.js index 992ea050..22c188cc 100644 --- a/src/skins/vector/views/organisms/ErrorDialog.js +++ b/src/components/views/login/VectorCustomServerDialog.js @@ -14,38 +14,37 @@ See the License for the specific language governing permissions and limitations under the License. */ -'use strict'; - -/* - * Usage: - * Modal.createDialog(ErrorDialog, { - * title: "some text", (default: "Error") - * description: "some more text", - * button: "Button Text", - * onClose: someFunction, - * focus: true|false (default: true) - * }); - */ - -var React = require('react'); -var ErrorDialogController = require('matrix-react-sdk/lib/controllers/organisms/ErrorDialog') +var React = require("react"); module.exports = React.createClass({ - displayName: 'ErrorDialog', - mixins: [ErrorDialogController], + displayName: 'VectorCustomServerDialog', + statics: { + replaces: 'CustomServerDialog', + }, render: function() { return (
- {this.props.title} + Custom Server Options
- {this.props.description} + + You can use the custom server options to log into other Matrix + servers by specifying a different Home server URL. +
+ This allows you to use Vector with an existing Matrix account on + a different Home server. +
+
+ You can also set a custom Identity server but this will affect + people's ability to find you if you use a server in a group other + than the main Matrix.org group. +
-
diff --git a/src/skins/vector/views/molecules/EventAsTextTile.js b/src/components/views/login/VectorLoginFooter.js similarity index 60% rename from src/skins/vector/views/molecules/EventAsTextTile.js rename to src/components/views/login/VectorLoginFooter.js index ec644a4e..2b2f1ae8 100644 --- a/src/skins/vector/views/molecules/EventAsTextTile.js +++ b/src/components/views/login/VectorLoginFooter.js @@ -18,26 +18,20 @@ limitations under the License. var React = require('react'); -var TextForEvent = require('matrix-react-sdk/lib/TextForEvent'); - module.exports = React.createClass({ - displayName: 'EventAsTextTile', - + displayName: 'VectorLoginFooter', statics: { - needsSenderProfile: function() { - return false; - } + replaces: 'LoginFooter', }, render: function() { - var text = TextForEvent.textForEvent(this.props.mxEvent); - if (text == null || text.length == 0) return null; - return ( -
- {TextForEvent.textForEvent(this.props.mxEvent)} +
+ blog  ·   + twitter  ·   + github  ·   + powered by Matrix
); - }, + } }); - diff --git a/src/skins/vector/views/atoms/voip/VideoFeed.js b/src/components/views/login/VectorLoginHeader.js similarity index 75% rename from src/skins/vector/views/atoms/voip/VideoFeed.js rename to src/components/views/login/VectorLoginHeader.js index 9cf28d1b..61b04267 100644 --- a/src/skins/vector/views/atoms/voip/VideoFeed.js +++ b/src/components/views/login/VectorLoginHeader.js @@ -19,13 +19,16 @@ limitations under the License. var React = require('react'); module.exports = React.createClass({ - displayName: 'VideoFeed', + displayName: 'VectorLoginHeader', + statics: { + replaces: 'LoginHeader', + }, render: function() { return ( - +
+ vector +
); - }, + } }); - diff --git a/src/skins/vector/views/molecules/DateSeparator.js b/src/components/views/messages/DateSeparator.js similarity index 100% rename from src/skins/vector/views/molecules/DateSeparator.js rename to src/components/views/messages/DateSeparator.js diff --git a/src/skins/vector/views/atoms/MessageTimestamp.js b/src/components/views/messages/MessageTimestamp.js similarity index 93% rename from src/skins/vector/views/atoms/MessageTimestamp.js rename to src/components/views/messages/MessageTimestamp.js index 5795e556..b4b7546e 100644 --- a/src/skins/vector/views/atoms/MessageTimestamp.js +++ b/src/components/views/messages/MessageTimestamp.js @@ -17,7 +17,7 @@ limitations under the License. 'use strict'; var React = require('react'); -var DateUtils = require('../../../../DateUtils'); +var DateUtils = require('matrix-react-sdk/lib/DateUtils'); module.exports = React.createClass({ displayName: 'MessageTimestamp', diff --git a/src/skins/vector/views/molecules/MEmoteTile.js b/src/components/views/messages/SenderProfile.js similarity index 72% rename from src/skins/vector/views/molecules/MEmoteTile.js rename to src/components/views/messages/SenderProfile.js index de2d9365..ef0173d9 100644 --- a/src/skins/vector/views/molecules/MEmoteTile.js +++ b/src/components/views/messages/SenderProfile.js @@ -18,19 +18,20 @@ limitations under the License. var React = require('react'); -var MEmoteTileController = require('matrix-react-sdk/lib/controllers/molecules/MEmoteTile') - module.exports = React.createClass({ - displayName: 'MEmoteTile', - mixins: [MEmoteTileController], + displayName: 'SenderProfile', render: function() { var mxEvent = this.props.mxEvent; - var content = mxEvent.getContent(); var name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); + + var msgtype = mxEvent.getContent().msgtype; + if (msgtype && msgtype == 'm.emote') { + name = ''; // emote message must include the name so don't duplicate it + } return ( - - * {name} {content.body} + + {name} { this.props.aux } ); }, diff --git a/src/skins/vector/views/molecules/BottomLeftMenuTile.js b/src/components/views/rooms/BottomLeftMenuTile.js similarity index 95% rename from src/skins/vector/views/molecules/BottomLeftMenuTile.js rename to src/components/views/rooms/BottomLeftMenuTile.js index 8c28058d..2535490f 100644 --- a/src/skins/vector/views/molecules/BottomLeftMenuTile.js +++ b/src/components/views/rooms/BottomLeftMenuTile.js @@ -41,7 +41,7 @@ module.exports = React.createClass({ label =
{ this.props.label }
; } else if (this.state.hover) { - var RoomTooltip = sdk.getComponent("molecules.RoomTooltip"); + var RoomTooltip = sdk.getComponent("rooms.RoomTooltip"); label = ; } diff --git a/src/skins/vector/views/molecules/MessageContextMenu.js b/src/components/views/rooms/MessageContextMenu.js similarity index 76% rename from src/skins/vector/views/molecules/MessageContextMenu.js rename to src/components/views/rooms/MessageContextMenu.js index b36d4ccb..4950cd88 100644 --- a/src/skins/vector/views/molecules/MessageContextMenu.js +++ b/src/components/views/rooms/MessageContextMenu.js @@ -22,7 +22,7 @@ var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); var dis = require('matrix-react-sdk/lib/dispatcher'); var sdk = require('matrix-react-sdk') var Modal = require('matrix-react-sdk/lib/Modal'); -var Resend = require("../../../../Resend"); +var Resend = require("matrix-react-sdk/lib/Resend"); module.exports = React.createClass({ displayName: 'MessageContextMenu', @@ -33,7 +33,7 @@ module.exports = React.createClass({ }, onViewSourceClick: function() { - var ViewSource = sdk.getComponent('organisms.ViewSource'); + var ViewSource = sdk.getComponent('structures.ViewSource'); Modal.createDialog(ViewSource, { mxEvent: this.props.mxEvent }); @@ -46,7 +46,7 @@ module.exports = React.createClass({ ).done(function() { // message should disappear by itself }, function(e) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); + var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); // display error message stating you couldn't delete this. var code = e.errcode || e.statusCode; Modal.createDialog(ErrorDialog, { @@ -57,25 +57,42 @@ module.exports = React.createClass({ if (this.props.onFinished) this.props.onFinished(); }, + onCancelSendClick: function() { + Resend.removeFromQueue(this.props.mxEvent); + if (this.props.onFinished) this.props.onFinished(); + }, + render: function() { + var eventStatus = this.props.mxEvent.status; var resendButton; var viewSourceButton; var redactButton; + var cancelButton; - if (this.props.mxEvent.status == 'not_sent') { + if (eventStatus === 'not_sent') { resendButton = (
Resend
); } - else { + + if (!eventStatus) { // sent redactButton = (
Redact
); } + + if (eventStatus === "queued" || eventStatus === "not_sent") { + cancelButton = ( +
+ Cancel Sending +
+ ); + } + viewSourceButton = (
View Source @@ -86,6 +103,7 @@ module.exports = React.createClass({
{resendButton} {redactButton} + {cancelButton} {viewSourceButton}
); diff --git a/src/skins/vector/views/molecules/RoomTile.js b/src/components/views/rooms/RoomDNDView.js similarity index 64% rename from src/skins/vector/views/molecules/RoomTile.js rename to src/components/views/rooms/RoomDNDView.js index 31dead45..9b01629d 100644 --- a/src/skins/vector/views/molecules/RoomTile.js +++ b/src/components/views/rooms/RoomDNDView.js @@ -19,13 +19,11 @@ limitations under the License. var React = require('react'); var DragSource = require('react-dnd').DragSource; var DropTarget = require('react-dnd').DropTarget; -var classNames = require('classnames'); - -var RoomTileController = require('matrix-react-sdk/lib/controllers/molecules/RoomTile') +var dis = require("matrix-react-sdk/lib/dispatcher"); var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); - -var sdk = require('matrix-react-sdk') +var sdk = require('matrix-react-sdk'); +var RoomTile = require('matrix-react-sdk/lib/components/views/rooms/RoomTile'); /** * Specifies the drag source contract. @@ -69,7 +67,7 @@ var roomTileSource = { if (monitor.didDrop() && item.targetList.props.editable) { // if we moved lists, remove the old tag - if (item.targetList !== item.originalList) { + if (item.targetList !== item.originalList && item.originalList.props.tagName) { // commented out attempts to set a spinner on our target component as component is actually // the original source component being dragged, not our target. To fix we just need to // move all of this to endDrop in the target instead. FIXME later. @@ -78,7 +76,7 @@ var roomTileSource = { MatrixClientPeg.get().deleteRoomTag(item.room.roomId, item.originalList.props.tagName).finally(function() { //component.state.set({ spinner: component.state.spinner-- }); }).fail(function(err) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); + var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { title: "Failed to remove tag " + item.originalList.props.tagName + " from room", description: err.toString() @@ -97,7 +95,7 @@ var roomTileSource = { MatrixClientPeg.get().setRoomTag(item.room.roomId, item.targetList.props.tagName, newOrder).finally(function() { //component.state.set({ spinner: component.state.spinner-- }); }).fail(function(err) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); + var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { title: "Failed to add tag " + item.targetList.props.tagName + " to room", description: err.toString() @@ -183,117 +181,6 @@ var roomTileTarget = { }, }; -var RoomTile = React.createClass({ - displayName: 'RoomTile', - mixins: [RoomTileController], - - propTypes: { - connectDragSource: React.PropTypes.func.isRequired, - connectDropTarget: React.PropTypes.func.isRequired, - isDragging: React.PropTypes.bool.isRequired, - room: React.PropTypes.object.isRequired, - collapsed: React.PropTypes.bool.isRequired, - selected: React.PropTypes.bool.isRequired, - unread: React.PropTypes.bool.isRequired, - highlight: React.PropTypes.bool.isRequired, - isInvite: React.PropTypes.bool.isRequired, - roomSubList: React.PropTypes.object.isRequired, - }, - - getInitialState: function() { - return( { hover : false }); - }, - - onMouseEnter: function() { - this.setState( { hover : true }); - }, - - onMouseLeave: function() { - this.setState( { hover : false }); - }, - - render: function() { - // if (this.props.clientOffset) { - // //console.log("room " + this.props.room.roomId + " has dropTarget clientOffset " + this.props.clientOffset.x + "," + this.props.clientOffset.y); - // } - -/* - if (this.props.room._dragging) { - var RoomDropTarget = sdk.getComponent("molecules.RoomDropTarget"); - return ; - } -*/ - - var myUserId = MatrixClientPeg.get().credentials.userId; - var me = this.props.room.currentState.members[myUserId]; - var classes = classNames({ - 'mx_RoomTile': true, - 'mx_RoomTile_selected': this.props.selected, - 'mx_RoomTile_unread': this.props.unread, - 'mx_RoomTile_highlight': this.props.highlight, - 'mx_RoomTile_invited': (me && me.membership == 'invite'), - }); - - var name; - if (this.props.isInvite) { - name = this.props.room.getMember(myUserId).events.member.getSender(); - } - else { - // XXX: We should never display raw room IDs, but sometimes the room name js sdk gives is undefined - name = this.props.room.name || this.props.room.roomId; - } - - name = name.replace(":", ":\u200b"); // add a zero-width space to allow linewrapping after the colon - var badge; - if (this.props.highlight) { - badge =
; - } - /* - if (this.props.highlight) { - badge =
!
; - } - else if (this.props.unread) { - badge =
1
; - } - var nameCell; - if (badge) { - nameCell =
{name}
{badge}
; - } - else { - nameCell =
{name}
; - } - */ - - var label; - if (!this.props.collapsed) { - var className = 'mx_RoomTile_name' + (this.props.isInvite ? ' mx_RoomTile_invite' : ''); - label =
{name}
; - } - else if (this.state.hover) { - var RoomTooltip = sdk.getComponent("molecules.RoomTooltip"); - label = ; - } - - var RoomAvatar = sdk.getComponent('atoms.RoomAvatar'); - - // These props are injected by React DnD, - // as defined by your `collect` function above: - var isDragging = this.props.isDragging; - var connectDragSource = this.props.connectDragSource; - var connectDropTarget = this.props.connectDropTarget; - - return connectDragSource(connectDropTarget( -
-
- - { badge } -
- { label } -
- )); - } -}); - // Export the wrapped version, inlining the 'collect' functions // to more closely resemble the ES7 module.exports = @@ -313,4 +200,6 @@ DragSource('RoomTile', roomTileSource, function(connect, monitor) { // You can ask the monitor about the current drag state: isDragging: monitor.isDragging() }; -})(RoomTile)); \ No newline at end of file +})(RoomTile)); + +module.exports.replaces = 'RoomTile'; diff --git a/src/skins/vector/views/molecules/RoomDropTarget.js b/src/components/views/rooms/RoomDropTarget.js similarity index 100% rename from src/skins/vector/views/molecules/RoomDropTarget.js rename to src/components/views/rooms/RoomDropTarget.js diff --git a/src/skins/vector/views/molecules/RoomTooltip.js b/src/components/views/rooms/RoomTooltip.js similarity index 100% rename from src/skins/vector/views/molecules/RoomTooltip.js rename to src/components/views/rooms/RoomTooltip.js diff --git a/src/skins/vector/views/molecules/SearchBar.js b/src/components/views/rooms/SearchBar.js similarity index 57% rename from src/skins/vector/views/molecules/SearchBar.js rename to src/components/views/rooms/SearchBar.js index 585b9a6d..e66f1236 100644 --- a/src/skins/vector/views/molecules/SearchBar.js +++ b/src/components/views/rooms/SearchBar.js @@ -19,6 +19,7 @@ limitations under the License. var React = require('react'); var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); var sdk = require('matrix-react-sdk'); +var classNames = require('classnames'); module.exports = React.createClass({ displayName: 'SearchBar', @@ -39,17 +40,29 @@ module.exports = React.createClass({ onSearchChange: function(e) { if (e.keyCode === 13) { // on enter... - this.props.onSearch(this.refs.search_term.value, this.state.scope); + this.onSearch(); } + if (e.keyCode === 27) { // escape... + this.props.onCancelClick(); + } + }, + + onSearch: function() { + this.props.onSearch(this.refs.search_term.value, this.state.scope); }, render: function() { + var searchButtonClasses = classNames({ mx_SearchBar_searchButton : true, mx_SearchBar_searching: this.props.searchInProgress }); + var thisRoomClasses = classNames({ mx_SearchBar_button : true, mx_SearchBar_unselected : this.state.scope !== 'Room' }); + var allRoomsClasses = classNames({ mx_SearchBar_button : true, mx_SearchBar_unselected : this.state.scope !== 'All' }); + return (
-
This Room
-
All Rooms
- +
Search
+
This Room
+
All Rooms
+
); } diff --git a/src/controllers/molecules/voip/CallView.js b/src/controllers/molecules/voip/CallView.js deleted file mode 100644 index ab712148..00000000 --- a/src/controllers/molecules/voip/CallView.js +++ /dev/null @@ -1,97 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; -var dis = require("matrix-react-sdk/lib/dispatcher"); -var CallHandler = require("matrix-react-sdk/lib/CallHandler"); -var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg"); - -var VectorConferenceHandler = require('../../../modules/VectorConferenceHandler'); - -/* - * State vars: - * this.state.call = MatrixCall|null - * - * Props: - * this.props.room = Room (JS SDK) - * - * Internal state: - * this._trackedRoom = (either from props.room or programatically set) - */ - -module.exports = { - - componentDidMount: function() { - this.dispatcherRef = dis.register(this.onAction); - this._trackedRoom = null; - if (this.props.room) { - this._trackedRoom = this.props.room; - this.showCall(this._trackedRoom.roomId); - } - else { - var call = CallHandler.getAnyActiveCall(); - if (call) { - console.log( - "Global CallView is now tracking active call in room %s", - call.roomId - ); - this._trackedRoom = MatrixClientPeg.get().getRoom(call.roomId); - this.showCall(call.roomId); - } - } - }, - - componentWillUnmount: function() { - dis.unregister(this.dispatcherRef); - }, - - onAction: function(payload) { - // don't filter out payloads for room IDs other than props.room because - // we may be interested in the conf 1:1 room - if (payload.action !== 'call_state' || !payload.room_id) { - return; - } - this.showCall(payload.room_id); - }, - - showCall: function(roomId) { - var call = ( - CallHandler.getCallForRoom(roomId) || - VectorConferenceHandler.getConferenceCallForRoom(roomId) - ); - if (call) { - call.setLocalVideoElement(this.getVideoView().getLocalVideoElement()); - call.setRemoteVideoElement(this.getVideoView().getRemoteVideoElement()); - // give a separate element for audio stream playback - both for voice calls - // and for the voice stream of screen captures - call.setRemoteAudioElement(this.getVideoView().getRemoteAudioElement()); - } - if (call && call.type === "video" && call.state !== 'ended') { - // if this call is a conf call, don't display local video as the - // conference will have us in it - this.getVideoView().getLocalVideoElement().style.display = ( - call.confUserId ? "none" : "initial" - ); - this.getVideoView().getRemoteVideoElement().style.display = "initial"; - } - else { - this.getVideoView().getLocalVideoElement().style.display = "none"; - this.getVideoView().getRemoteVideoElement().style.display = "none"; - dis.dispatch({action: 'video_fullscreen', fullscreen: false}); - } - } -}; - diff --git a/src/controllers/organisms/RoomList.js b/src/controllers/organisms/RoomList.js deleted file mode 100644 index 37d4a4e4..00000000 --- a/src/controllers/organisms/RoomList.js +++ /dev/null @@ -1,201 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require("react"); -var ReactDOM = require("react-dom"); - -var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg"); -var RoomListSorter = require("matrix-react-sdk/lib/RoomListSorter"); -var dis = require("matrix-react-sdk/lib/dispatcher"); - -var sdk = require('matrix-react-sdk'); -var VectorConferenceHandler = require("../../modules/VectorConferenceHandler"); - -var HIDE_CONFERENCE_CHANS = true; - -module.exports = { - getInitialState: function() { - return { - activityMap: null, - lists: {}, - } - }, - - componentWillMount: function() { - var cli = MatrixClientPeg.get(); - cli.on("Room", this.onRoom); - cli.on("Room.timeline", this.onRoomTimeline); - cli.on("Room.name", this.onRoomName); - cli.on("Room.tags", this.onRoomTags); - cli.on("RoomState.events", this.onRoomStateEvents); - cli.on("RoomMember.name", this.onRoomMemberName); - - var s = this.getRoomLists(); - s.activityMap = {}; - this.setState(s); - }, - - componentDidMount: function() { - this.dispatcherRef = dis.register(this.onAction); - }, - - onAction: function(payload) { - switch (payload.action) { - case 'view_tooltip': - this.tooltip = payload.tooltip; - this._repositionTooltip(); - if (this.tooltip) this.tooltip.style.display = 'block'; - break - } - }, - - componentWillUnmount: function() { - dis.unregister(this.dispatcherRef); - if (MatrixClientPeg.get()) { - MatrixClientPeg.get().removeListener("Room", this.onRoom); - MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline); - MatrixClientPeg.get().removeListener("Room.name", this.onRoomName); - MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents); - } - }, - - componentWillReceiveProps: function(newProps) { - this.state.activityMap[newProps.selectedRoom] = undefined; - this.setState({ - activityMap: this.state.activityMap - }); - }, - - onRoom: function(room) { - this.refreshRoomList(); - }, - - onRoomTimeline: function(ev, room, toStartOfTimeline) { - if (toStartOfTimeline) return; - - var newState = this.getRoomLists(); - if ( - room.roomId != this.props.selectedRoom && - ev.getSender() != MatrixClientPeg.get().credentials.userId) - { - var hl = 1; - - var actions = MatrixClientPeg.get().getPushActionsForEvent(ev); - if (actions && actions.tweaks && actions.tweaks.highlight) { - hl = 2; - } - // obviously this won't deep copy but this shouldn't be necessary - var amap = this.state.activityMap; - amap[room.roomId] = Math.max(amap[room.roomId] || 0, hl); - - newState.activityMap = amap; - } - this.setState(newState); - }, - - onRoomName: function(room) { - this.refreshRoomList(); - }, - - onRoomTags: function(event, room) { - this.refreshRoomList(); - }, - - onRoomStateEvents: function(ev, state) { - setTimeout(this.refreshRoomList, 0); - }, - - onRoomMemberName: function(ev, member) { - setTimeout(this.refreshRoomList, 0); - }, - - refreshRoomList: function() { - // TODO: rather than bluntly regenerating and re-sorting everything - // every time we see any kind of room change from the JS SDK - // we could do incremental updates on our copy of the state - // based on the room which has actually changed. This would stop - // us re-rendering all the sublists every time anything changes anywhere - // in the state of the client. - this.setState(this.getRoomLists()); - }, - - getRoomLists: function() { - var s = { lists: {} }; - - s.lists["m.invite"] = []; - s.lists["m.favourite"] = []; - s.lists["m.recent"] = []; - s.lists["m.lowpriority"] = []; - s.lists["m.archived"] = []; - - MatrixClientPeg.get().getRooms().forEach(function(room) { - var me = room.getMember(MatrixClientPeg.get().credentials.userId); - - if (me && me.membership == "invite") { - s.lists["m.invite"].push(room); - } - else { - var shouldShowRoom = ( - me && (me.membership == "join") - ); - - // hiding conf rooms only ever toggles shouldShowRoom to false - if (shouldShowRoom && HIDE_CONFERENCE_CHANS) { - // we want to hide the 1:1 conf<->user room and not the group chat - var joinedMembers = room.getJoinedMembers(); - if (joinedMembers.length === 2) { - var otherMember = joinedMembers.filter(function(m) { - return m.userId !== me.userId - })[0]; - if (VectorConferenceHandler.isConferenceUser(otherMember)) { - // console.log("Hiding conference 1:1 room %s", room.roomId); - shouldShowRoom = false; - } - } - } - - if (shouldShowRoom) { - var tagNames = Object.keys(room.tags); - if (tagNames.length) { - for (var i = 0; i < tagNames.length; i++) { - var tagName = tagNames[i]; - s.lists[tagName] = s.lists[tagName] || []; - s.lists[tagNames[i]].push(room); - } - } - else { - s.lists["m.recent"].push(room); - } - } - } - }); - - //console.log("calculated new roomLists; m.recent = " + s.lists["m.recent"]); - - // we actually apply the sorting to this when receiving the prop in RoomSubLists. - - return s; - }, - - _repositionTooltip: function(e) { - if (this.tooltip && this.tooltip.parentElement) { - var scroll = ReactDOM.findDOMNode(this); - this.tooltip.style.top = (scroll.parentElement.offsetTop + this.tooltip.parentElement.offsetTop - scroll.children[2].scrollTop) + "px"; - } - }, -}; diff --git a/src/controllers/organisms/RoomView.js b/src/controllers/organisms/RoomView.js deleted file mode 100644 index e603198a..00000000 --- a/src/controllers/organisms/RoomView.js +++ /dev/null @@ -1,628 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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 Matrix = require("matrix-js-sdk"); -var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg"); -var React = require("react"); -var ReactDOM = require("react-dom"); -var q = require("q"); -var ContentMessages = require("matrix-react-sdk/lib//ContentMessages"); -var WhoIsTyping = require("matrix-react-sdk/lib/WhoIsTyping"); -var Modal = require("matrix-react-sdk/lib/Modal"); -var sdk = require('matrix-react-sdk/lib/index'); -var CallHandler = require('matrix-react-sdk/lib/CallHandler'); -var VectorConferenceHandler = require('../../modules/VectorConferenceHandler'); -var Resend = require("../../Resend"); - -var dis = require("matrix-react-sdk/lib/dispatcher"); - -var PAGINATE_SIZE = 20; -var INITIAL_SIZE = 20; - -module.exports = { - getInitialState: function() { - var room = this.props.roomId ? MatrixClientPeg.get().getRoom(this.props.roomId) : null; - return { - room: room, - messageCap: INITIAL_SIZE, - editingRoomSettings: false, - uploadingRoomSettings: false, - numUnreadMessages: 0, - draggingFile: false, - searching: false, - searchResults: null, - syncState: MatrixClientPeg.get().getSyncState(), - hasUnsentMessages: this._hasUnsentMessages(room) - } - }, - - componentWillMount: function() { - this.dispatcherRef = dis.register(this.onAction); - MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline); - MatrixClientPeg.get().on("Room.name", this.onRoomName); - MatrixClientPeg.get().on("RoomMember.typing", this.onRoomMemberTyping); - MatrixClientPeg.get().on("RoomState.members", this.onRoomStateMember); - MatrixClientPeg.get().on("sync", this.onSyncStateChange); - this.atBottom = true; - }, - - componentWillUnmount: function() { - if (this.refs.messagePanel) { - var messagePanel = ReactDOM.findDOMNode(this.refs.messagePanel); - messagePanel.removeEventListener('drop', this.onDrop); - messagePanel.removeEventListener('dragover', this.onDragOver); - messagePanel.removeEventListener('dragleave', this.onDragLeaveOrEnd); - messagePanel.removeEventListener('dragend', this.onDragLeaveOrEnd); - } - dis.unregister(this.dispatcherRef); - if (MatrixClientPeg.get()) { - MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline); - MatrixClientPeg.get().removeListener("Room.name", this.onRoomName); - MatrixClientPeg.get().removeListener("RoomMember.typing", this.onRoomMemberTyping); - MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember); - MatrixClientPeg.get().removeListener("sync", this.onSyncStateChange); - } - }, - - onAction: function(payload) { - switch (payload.action) { - case 'message_send_failed': - case 'message_sent': - this.setState({ - hasUnsentMessages: this._hasUnsentMessages(this.state.room) - }); - case 'message_resend_started': - this.setState({ - room: MatrixClientPeg.get().getRoom(this.props.roomId) - }); - this.forceUpdate(); - break; - case 'notifier_enabled': - this.forceUpdate(); - break; - case 'call_state': - if (CallHandler.getCallForRoom(this.props.roomId)) { - // Call state has changed so we may be loading video elements - // which will obscure the message log. - // scroll to bottom - var scrollNode = this._getScrollNode(); - if (scrollNode) { - scrollNode.scrollTop = scrollNode.scrollHeight; - } - } - - // possibly remove the conf call notification if we're now in - // the conf - this._updateConfCallNotification(); - break; - } - }, - - _getScrollNode: function() { - var panel = ReactDOM.findDOMNode(this.refs.messagePanel); - if (!panel) return null; - - if (panel.classList.contains('gm-prevented')) { - return panel; - } else { - return panel.children[2]; // XXX: Fragile! - } - }, - - onSyncStateChange: function(state) { - this.setState({ - syncState: state - }); - }, - - // MatrixRoom still showing the messages from the old room? - // Set the key to the room_id. Sadly you can no longer get at - // the key from inside the component, or we'd check this in code. - /*componentWillReceiveProps: function(props) { - },*/ - - onRoomTimeline: function(ev, room, toStartOfTimeline) { - if (!this.isMounted()) return; - - // ignore anything that comes in whilst paginating: we get one - // event for each new matrix event so this would cause a huge - // number of UI updates. Just update the UI when the paginate - // call returns. - if (this.state.paginating) return; - - // no point handling anything while we're waiting for the join to finish: - // we'll only be showing a spinner. - if (this.state.joining) return; - if (room.roomId != this.props.roomId) return; - - var scrollNode = this._getScrollNode(); - if (scrollNode) { - this.atBottom = ( - scrollNode.scrollHeight - scrollNode.scrollTop <= - (scrollNode.clientHeight + 150) // 150? - ); - } - - var currentUnread = this.state.numUnreadMessages; - if (!toStartOfTimeline && - (ev.getSender() !== MatrixClientPeg.get().credentials.userId)) { - // update unread count when scrolled up - if (this.atBottom) { - currentUnread = 0; - } - else { - currentUnread += 1; - } - } - - - this.setState({ - room: MatrixClientPeg.get().getRoom(this.props.roomId), - numUnreadMessages: currentUnread - }); - - if (toStartOfTimeline && !this.state.paginating) { - this.fillSpace(); - } - }, - - onRoomName: function(room) { - if (room.roomId == this.props.roomId) { - this.setState({ - room: room - }); - } - }, - - onRoomMemberTyping: function(ev, member) { - this.forceUpdate(); - }, - - onRoomStateMember: function(ev, state, member) { - if (member.roomId !== this.props.roomId || - member.userId !== VectorConferenceHandler.getConferenceUserIdForRoom(member.roomId)) { - return; - } - this._updateConfCallNotification(); - }, - - _hasUnsentMessages: function(room) { - return this._getUnsentMessages(room).length > 0; - }, - - _getUnsentMessages: function(room) { - if (!room) { return []; } - // TODO: It would be nice if the JS SDK provided nicer constant-time - // constructs rather than O(N) (N=num msgs) on this. - return room.timeline.filter(function(ev) { - return ev.status === Matrix.EventStatus.NOT_SENT; - }); - }, - - _updateConfCallNotification: function() { - var room = MatrixClientPeg.get().getRoom(this.props.roomId); - if (!room) return; - var confMember = room.getMember( - VectorConferenceHandler.getConferenceUserIdForRoom(this.props.roomId) - ); - - if (!confMember) { - return; - } - var confCall = VectorConferenceHandler.getConferenceCallForRoom(confMember.roomId); - - // A conf call notification should be displayed if there is an ongoing - // conf call but this cilent isn't a part of it. - this.setState({ - displayConfCallNotification: ( - (!confCall || confCall.call_state === "ended") && - confMember.membership === "join" - ) - }); - }, - - componentDidMount: function() { - if (this.refs.messagePanel) { - var messagePanel = ReactDOM.findDOMNode(this.refs.messagePanel); - - messagePanel.addEventListener('drop', this.onDrop); - messagePanel.addEventListener('dragover', this.onDragOver); - messagePanel.addEventListener('dragleave', this.onDragLeaveOrEnd); - messagePanel.addEventListener('dragend', this.onDragLeaveOrEnd); - - var messageWrapperScroll = this._getScrollNode(); - - messageWrapperScroll.scrollTop = messageWrapperScroll.scrollHeight; - - this.fillSpace(); - } - - this._updateConfCallNotification(); - }, - - componentDidUpdate: function() { - if (!this.refs.messagePanel) return; - - var messageWrapperScroll = this._getScrollNode(); - - if (this.state.paginating && !this.waiting_for_paginate) { - var heightGained = messageWrapperScroll.scrollHeight - this.oldScrollHeight; - messageWrapperScroll.scrollTop += heightGained; - this.oldScrollHeight = undefined; - if (!this.fillSpace()) { - this.setState({paginating: false}); - } - } else if (this.atBottom) { - messageWrapperScroll.scrollTop = messageWrapperScroll.scrollHeight; - if (this.state.numUnreadMessages !== 0) { - this.setState({numUnreadMessages: 0}); - } - } - }, - - fillSpace: function() { - if (!this.refs.messagePanel) return; - var messageWrapperScroll = this._getScrollNode(); - if (messageWrapperScroll.scrollTop < messageWrapperScroll.clientHeight && this.state.room.oldState.paginationToken) { - this.setState({paginating: true}); - - this.oldScrollHeight = messageWrapperScroll.scrollHeight; - - if (this.state.messageCap < this.state.room.timeline.length) { - this.waiting_for_paginate = false; - var cap = Math.min(this.state.messageCap + PAGINATE_SIZE, this.state.room.timeline.length); - this.setState({messageCap: cap, paginating: true}); - } else { - this.waiting_for_paginate = true; - var cap = this.state.messageCap + PAGINATE_SIZE; - this.setState({messageCap: cap, paginating: true}); - var self = this; - MatrixClientPeg.get().scrollback(this.state.room, PAGINATE_SIZE).finally(function() { - self.waiting_for_paginate = false; - if (self.isMounted()) { - self.setState({ - room: MatrixClientPeg.get().getRoom(self.props.roomId) - }); - } - // wait and set paginating to false when the component updates - }); - } - - return true; - } - return false; - }, - - onResendAllClick: function() { - var eventsToResend = this._getUnsentMessages(this.state.room); - eventsToResend.forEach(function(event) { - Resend.resend(event); - }); - }, - - onJoinButtonClicked: function(ev) { - var self = this; - MatrixClientPeg.get().joinRoom(this.props.roomId).then(function() { - self.setState({ - joining: false, - room: MatrixClientPeg.get().getRoom(self.props.roomId) - }); - }, function(error) { - self.setState({ - joining: false, - joinError: error - }); - }); - this.setState({ - joining: true - }); - }, - - onMessageListScroll: function(ev) { - if (this.refs.messagePanel) { - var messageWrapperScroll = this._getScrollNode(); - var wasAtBottom = this.atBottom; - this.atBottom = messageWrapperScroll.scrollHeight - messageWrapperScroll.scrollTop <= messageWrapperScroll.clientHeight + 1; - if (this.atBottom && !wasAtBottom) { - this.forceUpdate(); // remove unread msg count - } - } - if (!this.state.paginating) this.fillSpace(); - }, - - onDragOver: function(ev) { - ev.stopPropagation(); - ev.preventDefault(); - - ev.dataTransfer.dropEffect = 'none'; - - var items = ev.dataTransfer.items; - if (items.length == 1) { - if (items[0].kind == 'file') { - this.setState({ draggingFile : true }); - ev.dataTransfer.dropEffect = 'copy'; - } - } - }, - - onDrop: function(ev) { - ev.stopPropagation(); - ev.preventDefault(); - this.setState({ draggingFile : false }); - var files = ev.dataTransfer.files; - if (files.length == 1) { - this.uploadFile(files[0]); - } - }, - - onDragLeaveOrEnd: function(ev) { - ev.stopPropagation(); - ev.preventDefault(); - this.setState({ draggingFile : false }); - }, - - uploadFile: function(file) { - this.setState({ - upload: { - fileName: file.name, - uploadedBytes: 0, - totalBytes: file.size - } - }); - var self = this; - ContentMessages.sendContentToRoom( - file, this.props.roomId, MatrixClientPeg.get() - ).progress(function(ev) { - //console.log("Upload: "+ev.loaded+" / "+ev.total); - self.setState({ - upload: { - fileName: file.name, - uploadedBytes: ev.loaded, - totalBytes: ev.total - } - }); - }).finally(function() { - self.setState({ - upload: undefined - }); - }).done(undefined, function(error) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); - Modal.createDialog(ErrorDialog, { - title: "Failed to upload file", - description: error.toString() - }); - }); - }, - - getWhoIsTypingString: function() { - return WhoIsTyping.whoIsTypingString(this.state.room); - }, - - onSearch: function(term, scope) { - var filter; - if (scope === "Room") { // FIXME: should be enum - filter = { - // XXX: it's unintuitive that the filter for searching doesn't have the same shape as the v2 filter API :( - rooms: [ - this.props.roomId - ] - }; - } - - var self = this; - MatrixClientPeg.get().search({ - body: { - search_categories: { - room_events: { - search_term: term, - filter: filter, - order_by: "recent", - event_context: { - before_limit: 1, - after_limit: 1, - } - } - } - } - }).then(function(data) { - self.setState({ - searchTerm: term, - searchResults: data, - }); - }, function(error) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); - Modal.createDialog(ErrorDialog, { - title: "Search failed", - description: error.toString() - }); - }); - }, - - getEventTiles: function() { - var DateSeparator = sdk.getComponent('molecules.DateSeparator'); - - var ret = []; - var count = 0; - - var EventTile = sdk.getComponent('molecules.EventTile'); - - if (this.state.searchResults) { - // XXX: this dance is foul, due to the results API not returning sorted results - var results = this.state.searchResults.search_categories.room_events.results; - var eventIds = Object.keys(results); - // XXX: todo: merge overlapping results somehow? - // XXX: why doesn't searching on name work? - var resultList = eventIds.map(function(key) { return results[key]; }); // .sort(function(a, b) { b.rank - a.rank }); - for (var i = 0; i < resultList.length; i++) { - var ts1 = resultList[i].result.origin_server_ts; - ret.push(
  • ); // Rank: {resultList[i].rank} - var mxEv = new Matrix.MatrixEvent(resultList[i].result); - if (resultList[i].context.events_before[0]) { - var mxEv2 = new Matrix.MatrixEvent(resultList[i].context.events_before[0]); - if (EventTile.haveTileForEvent(mxEv2)) { - ret.push(
  • ); - } - } - if (EventTile.haveTileForEvent(mxEv)) { - ret.push(
  • ); - } - if (resultList[i].context.events_after[0]) { - var mxEv2 = new Matrix.MatrixEvent(resultList[i].context.events_after[0]); - if (EventTile.haveTileForEvent(mxEv2)) { - ret.push(
  • ); - } - } - } - return ret; - } - - for (var i = this.state.room.timeline.length-1; i >= 0 && count < this.state.messageCap; --i) { - var mxEv = this.state.room.timeline[i]; - - if (!EventTile.haveTileForEvent(mxEv)) { - continue; - } - - var continuation = false; - var last = false; - var dateSeparator = null; - if (i == this.state.room.timeline.length - 1) { - last = true; - } - if (i > 0 && count < this.state.messageCap - 1) { - if (this.state.room.timeline[i].sender && - this.state.room.timeline[i - 1].sender && - (this.state.room.timeline[i].sender.userId === - this.state.room.timeline[i - 1].sender.userId) && - (this.state.room.timeline[i].getType() == - this.state.room.timeline[i - 1].getType()) - ) - { - continuation = true; - } - - var ts0 = this.state.room.timeline[i - 1].getTs(); - var ts1 = this.state.room.timeline[i].getTs(); - if (new Date(ts0).toDateString() !== new Date(ts1).toDateString()) { - dateSeparator = ; - continuation = false; - } - } - - if (i === 1) { // n.b. 1, not 0, as the 0th event is an m.room.create and so doesn't show on the timeline - var ts1 = this.state.room.timeline[i].getTs(); - dateSeparator =
  • ; - continuation = false; - } - - ret.unshift( -
  • - ); - if (dateSeparator) { - ret.unshift(dateSeparator); - } - ++count; - } - return ret; - }, - - uploadNewState: function(new_name, new_topic, new_join_rule, new_history_visibility, new_power_levels) { - var old_name = this.state.room.name; - - var old_topic = this.state.room.currentState.getStateEvents('m.room.topic', ''); - if (old_topic) { - old_topic = old_topic.getContent().topic; - } else { - old_topic = ""; - } - - var old_join_rule = this.state.room.currentState.getStateEvents('m.room.join_rules', ''); - if (old_join_rule) { - old_join_rule = old_join_rule.getContent().join_rule; - } else { - old_join_rule = "invite"; - } - - var old_history_visibility = this.state.room.currentState.getStateEvents('m.room.history_visibility', ''); - if (old_history_visibility) { - old_history_visibility = old_history_visibility.getContent().history_visibility; - } else { - old_history_visibility = "shared"; - } - - var deferreds = []; - - if (old_name != new_name && new_name != undefined && new_name) { - deferreds.push( - MatrixClientPeg.get().setRoomName(this.state.room.roomId, new_name) - ); - } - - if (old_topic != new_topic && new_topic != undefined) { - deferreds.push( - MatrixClientPeg.get().setRoomTopic(this.state.room.roomId, new_topic) - ); - } - - if (old_join_rule != new_join_rule && new_join_rule != undefined) { - deferreds.push( - MatrixClientPeg.get().sendStateEvent( - this.state.room.roomId, "m.room.join_rules", { - join_rule: new_join_rule, - }, "" - ) - ); - } - - if (old_history_visibility != new_history_visibility && new_history_visibility != undefined) { - deferreds.push( - MatrixClientPeg.get().sendStateEvent( - this.state.room.roomId, "m.room.history_visibility", { - history_visibility: new_history_visibility, - }, "" - ) - ); - } - - if (new_power_levels) { - deferreds.push( - MatrixClientPeg.get().sendStateEvent( - this.state.room.roomId, "m.room.power_levels", new_power_levels, "" - ) - ); - } - - if (deferreds.length) { - var self = this; - q.all(deferreds).fail(function(err) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); - Modal.createDialog(ErrorDialog, { - title: "Failed to set state", - description: err.toString() - }); - }).finally(function() { - self.setState({ - uploadingRoomSettings: false, - }); - }); - } else { - this.setState({ - editingRoomSettings: false, - uploadingRoomSettings: false, - }); - } - } -}; diff --git a/src/controllers/templates/Register.js b/src/controllers/templates/Register.js deleted file mode 100644 index 5f88d590..00000000 --- a/src/controllers/templates/Register.js +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var extend = require('matrix-react-sdk/lib/extend'); -var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); -var BaseRegisterController = require('matrix-react-sdk/lib/controllers/templates/Register.js'); - -var RegisterController = {}; -extend(RegisterController, BaseRegisterController); - -RegisterController.onRegistered = function(user_id, access_token) { - MatrixClientPeg.replaceUsingAccessToken( - this.state.hs_url, this.state.is_url, user_id, access_token - ); - - this.setState({ - step: 'profile', - busy: true - }); - - var self = this; - var cli = MatrixClientPeg.get(); - cli.getProfileInfo(cli.credentials.userId).done(function(result) { - self.setState({ - avatarUrl: result.avatar_url, - busy: false - }); - }, - function(err) { - console.err(err); - self.setState({ - busy: false - }); - }); -}; - -RegisterController.onAccountReady = function() { - if (this.props.onLoggedIn) { - this.props.onLoggedIn(); - } -}; - -module.exports = RegisterController; diff --git a/src/skins/vector/header b/src/header similarity index 100% rename from src/skins/vector/header rename to src/header diff --git a/src/skins/vector/css/MOVE_ME/UploadBar.css b/src/skins/vector/css/MOVE_ME/UploadBar.css new file mode 100644 index 00000000..bff271a3 --- /dev/null +++ b/src/skins/vector/css/MOVE_ME/UploadBar.css @@ -0,0 +1,44 @@ +.mx_UploadBar { + position: relative; +} + +.mx_UploadBar_uploadProgressOuter { + height: 4px; + margin-left: 63px; + margin-top: -1px; +} + +.mx_UploadBar_uploadProgressInner { + background-color: #76cfa6; + height: 4px; +} + +.mx_UploadBar_uploadFilename { + margin-top: 5px; + margin-left: 65px; + opacity: 0.5; + color: #4a4a4a; +} + +.mx_UploadBar_uploadIcon { + float: left; + margin-top: 1px; + margin-left: 14px; +} + +.mx_UploadBar_uploadCancel { + float: right; + margin-top: 5px; + margin-right: 10px; + position: relative; + opacity: 0.6; + cursor: pointer; + z-index: 1; +} + +.mx_UploadBar_uploadBytes { + float: right; + margin-top: 5px; + margin-right: 30px; + color: #76cfa6; +} diff --git a/src/skins/vector/css/atoms/ImageView.css b/src/skins/vector/css/atoms/ImageView.css index 22ef343b..9dd34f80 100644 --- a/src/skins/vector/css/atoms/ImageView.css +++ b/src/skins/vector/css/atoms/ImageView.css @@ -87,13 +87,13 @@ limitations under the License. } .mx_ImageView_name { - font-size: 20px; + font-size: 18px; margin-bottom: 6px; pointer-events: all; } .mx_ImageView_metadata { - font-size: 16px; + font-size: 15px; opacity: 0.5; pointer-events: all; } @@ -105,13 +105,13 @@ limitations under the License. margin-bottom: 6px; border-radius: 5px; background-color: #454545; - font-size: 16px; + font-size: 14px; padding: 9px; border: 1px solid #fff; } .mx_ImageView_size { - font-size: 12px; + font-size: 11px; } .mx_ImageView_link { @@ -121,7 +121,7 @@ limitations under the License. .mx_ImageView_button { pointer-events: all; - font-size: 16px; + font-size: 15px; opacity: 0.5; margin-top: 18px; cursor: pointer; diff --git a/src/skins/vector/css/atoms/MemberAvatar.css b/src/skins/vector/css/atoms/MemberAvatar.css index 34ef1393..3da56172 100644 --- a/src/skins/vector/css/atoms/MemberAvatar.css +++ b/src/skins/vector/css/atoms/MemberAvatar.css @@ -20,11 +20,14 @@ limitations under the License. .mx_MemberAvatar_initial { position: absolute; + z-index: 1; color: #fff; text-align: center; speak: none; + pointer-events: none; } .mx_MemberAvatar_image { - border-radius: 20px; + border-radius: 20px; + vertical-align: top; } diff --git a/src/skins/vector/css/atoms/RoomAvatar.css b/src/skins/vector/css/atoms/RoomAvatar.css index 01425190..f005b251 100644 --- a/src/skins/vector/css/atoms/RoomAvatar.css +++ b/src/skins/vector/css/atoms/RoomAvatar.css @@ -15,6 +15,7 @@ limitations under the License. */ .mx_RoomAvatar { + vertical-align: middle; } .mx_RoomAvatar_initial { @@ -23,4 +24,5 @@ limitations under the License. text-align: center; font-weight: normal ! important; speak: none; + pointer-events: none; } \ No newline at end of file diff --git a/src/skins/vector/css/common.css b/src/skins/vector/css/common.css index 121fbca7..2b6e02ed 100644 --- a/src/skins/vector/css/common.css +++ b/src/skins/vector/css/common.css @@ -22,8 +22,13 @@ html { } body { - font-family: 'Myriad Pro', Helvetica, Arial, Sans-Serif; - font-size: 16px; + /* Open Sans lacks combining diacritics, so these will fall through + to the next font. Helevetica's diacritics however do not combine + nicely with Open Sans (on OSX, at least) and result in a huge + horizontal mess. Arial empirically gets it right, hence prioritising + Arial here. */ + font-family: 'Open Sans', Arial, Helvetica, Sans-Serif; + font-size: 15px; color: #454545; border: 0px; margin: 0px; @@ -36,7 +41,7 @@ div.error { h2 { color: #454545; font-weight: 400; - font-size: 20px; + font-size: 18px; margin-top: 16px; margin-bottom: 16px; } @@ -47,6 +52,12 @@ a:visited { color: #76cfa6; } +input[type=text]:focus, textarea:focus, .mx_RoomSettings textarea:focus { + border: 1px solid #76CFA6; + outline: none; + box-shadow: none; +} + /* XXX: critical hack to GeminiScrollbar to allow them to work in FF 42 and Chrome 48. Stop the scrollbar view from pushing out the container's overall sizing, which causes flexbox to adapt to the new size and cause the view to keep growing. @@ -99,19 +110,9 @@ a:visited { margin: 0 auto; } -.mx_Dialog_background { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: #000; - opacity: 0.2; - z-index: 4000; -} - .mx_Dialog_wrapper { position: fixed; + z-index: 4000; top: 0; left: 0; width: 100%; @@ -134,12 +135,22 @@ a:visited { text-align: center; z-index: 4010; font-weight: 300; - font-size: 16px; + font-size: 15px; position: relative; border-radius: 8px; max-width: 80%; } +.mx_Dialog_background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: #000; + opacity: 0.2; +} + .mx_Dialog_lightbox .mx_Dialog_background { opacity: 0.85; } @@ -167,7 +178,7 @@ a:visited { height: 36px; border-radius: 36px; font-weight: 400; - font-size: 16px; + font-size: 15px; color: #fff; background-color: #76cfa6; margin-left: 8px; @@ -182,6 +193,6 @@ a:visited { padding: 12px; border-bottom: 1px solid #a4a4a4; font-weight: bold; - font-size: 20px; + font-size: 18px; line-height: 1.4; } diff --git a/src/skins/vector/css/gemini-scrollbar.css b/src/skins/vector/css/gemini-scrollbar.css deleted file mode 120000 index 4e3c83ba..00000000 --- a/src/skins/vector/css/gemini-scrollbar.css +++ /dev/null @@ -1 +0,0 @@ -../../../../node_modules/react-gemini-scrollbar/node_modules/gemini-scrollbar/gemini-scrollbar.css \ No newline at end of file diff --git a/src/skins/vector/css/molecules/EventAsTextTile.css b/src/skins/vector/css/molecules/EventAsTextTile.css index d18fdc80..da953522 100644 --- a/src/skins/vector/css/molecules/EventAsTextTile.css +++ b/src/skins/vector/css/molecules/EventAsTextTile.css @@ -16,4 +16,5 @@ limitations under the License. .mx_EventAsTextTile { opacity: 0.5; + overflow-y: hidden; } diff --git a/src/skins/vector/css/molecules/EventTile.css b/src/skins/vector/css/molecules/EventTile.css index d99bd4e1..e3956bdb 100644 --- a/src/skins/vector/css/molecules/EventTile.css +++ b/src/skins/vector/css/molecules/EventTile.css @@ -25,8 +25,10 @@ limitations under the License. padding-left: 18px; padding-right: 12px; margin-left: -73px; - margin-top: -4px; + margin-top: -2px; float: left; + position: relative; + top: 0px; } .mx_EventTile_avatar img { @@ -41,15 +43,15 @@ limitations under the License. .mx_EventTile .mx_SenderProfile { color: #454545; opacity: 0.5; - font-size: 14px; + font-size: 13px; margin-bottom: 4px; display: block; + overflow-y: hidden; } .mx_EventTile .mx_MessageTimestamp { color: #acacac; - font-size: 12px; - float: right; + font-size: 11px; } .mx_EventTile_line { @@ -64,8 +66,39 @@ limitations under the License. .mx_MessageTile_content { display: block; margin-right: 100px; + overflow-y: hidden; } +/* Various markdown overrides */ + +.mx_MessageTile_content .markdown-body { + font-family: inherit ! important; + white-space: normal ! important; + line-height: inherit ! important; + color: inherit; + font-size: 15px; +} + +.mx_MessageTile_content .markdown-body h1, +.mx_MessageTile_content .markdown-body h2, +.mx_MessageTile_content .markdown-body h3, +.mx_MessageTile_content .markdown-body h4, +.mx_MessageTile_content .markdown-body h5, +.mx_MessageTile_content .markdown-body h6 +{ + font-family: inherit ! important; +} + +.mx_MessageTile_content .markdown-body a { + color: #76cfa6; +} + +.mx_MessageTile_content .markdown-body .hljs { + display: inherit ! important; +} + +/* end of overrides */ + .mx_MessageTile_searchHighlight { background-color: #76cfa6; color: #fff; @@ -78,10 +111,12 @@ limitations under the License. } .mx_EventTile_notSent { - color: #ddd; + color: #f44; } -.mx_EventTile_highlight { +.mx_EventTile_highlight, +.mx_EventTile_highlight .markdown-body + { color: #FF0064; } @@ -91,10 +126,18 @@ limitations under the License. .mx_EventTile_msgOption { float: right; + text-align: right; + z-index: 1; + position: relative; + width: 90px; + margin-right: 10px; + margin-top: -6px; } .mx_MessageTimestamp { + display: block; visibility: hidden; + text-align: right; } .mx_EventTile_last .mx_MessageTimestamp { @@ -107,9 +150,8 @@ limitations under the License. .mx_EventTile_editButton { position: absolute; - right: 1px; - top: 15px; - visibility: hidden; + display: inline-block; + visibility: hidden; } .mx_EventTile:hover .mx_EventTile_editButton { @@ -123,3 +165,21 @@ limitations under the License. .mx_EventTile.menu .mx_MessageTimestamp { visibility: visible; } + +.mx_EventTile_readAvatars { + position: relative; + display: inline-block; + width: 14px; + height: 14px; +} + +.mx_EventTile_readAvatars .mx_MemberAvatar { + position: absolute; + display: inline-block; +} + +.mx_EventTile_readAvatarRemainder { + color: #acacac; + font-size: 11px; + position: absolute; +} diff --git a/src/skins/vector/css/molecules/MNoticeTile.css b/src/skins/vector/css/molecules/MNoticeTile.css index 0a0db62e..9fe5376a 100644 --- a/src/skins/vector/css/molecules/MNoticeTile.css +++ b/src/skins/vector/css/molecules/MNoticeTile.css @@ -15,5 +15,6 @@ limitations under the License. */ .mx_MNoticeTile { + white-space: pre-wrap; opacity: 0.6; } diff --git a/src/skins/vector/css/molecules/MemberInfo.css b/src/skins/vector/css/molecules/MemberInfo.css index 6471a86c..1c4ab385 100644 --- a/src/skins/vector/css/molecules/MemberInfo.css +++ b/src/skins/vector/css/molecules/MemberInfo.css @@ -37,8 +37,10 @@ limitations under the License. } .mx_MemberInfo_profileField { - opacity: 0.6; - font-size: 14px; + font-color: #999999; + font-size: 13px; + position: relative; + background-color: #fff; } .mx_MemberInfo_buttons { @@ -49,7 +51,7 @@ limitations under the License. cursor: pointer; width: 100px; text-align: center; - font-size: 12px; + font-size: 11px; background-color: #888; color: #fff; font-weight: bold; diff --git a/src/skins/vector/css/molecules/MemberTile.css b/src/skins/vector/css/molecules/MemberTile.css index cfeaeaee..874710d9 100644 --- a/src/skins/vector/css/molecules/MemberTile.css +++ b/src/skins/vector/css/molecules/MemberTile.css @@ -25,8 +25,8 @@ limitations under the License. display: table-cell; padding-left: 3px; padding-right: 12px; - padding-top: 2px; - padding-bottom: 0px; + padding-top: 4px; + padding-bottom: 4px; vertical-align: middle; width: 36px; height: 36px; @@ -55,13 +55,13 @@ limitations under the License. } .mx_MemberTile_userId { - font-size: 14px; + font-size: 13px; overflow: hidden; text-overflow: ellipsis; } .mx_MemberTile_presence { - font-size: 12px; + font-size: 11px; opacity: 0.5; } @@ -98,10 +98,6 @@ limitations under the License. opacity: 0.25; } -.mx_MemberTile_zalgo { - font-family: Helvetica, Arial, Sans-Serif; -} - .mx_MemberTile:hover .mx_MessageTimestamp { display: block; } diff --git a/src/skins/vector/css/molecules/MessageComposer.css b/src/skins/vector/css/molecules/MessageComposer.css index fbbeef64..4d566851 100644 --- a/src/skins/vector/css/molecules/MessageComposer.css +++ b/src/skins/vector/css/molecules/MessageComposer.css @@ -59,7 +59,7 @@ limitations under the License. box-shadow: none; /* needed for FF */ - font-family: 'Myriad Pro', Helvetica, Arial, Sans-Serif; + font-family: 'Open Sans', Arial, Helvetica, Sans-Serif; } /* hack for FF as vertical alignment of custom placeholder text is broken */ @@ -72,7 +72,9 @@ limitations under the License. } .mx_MessageComposer_upload, -.mx_MessageComposer_call { +.mx_MessageComposer_hangup, +.mx_MessageComposer_voicecall, +.mx_MessageComposer_videocall { display: table-cell; vertical-align: middle; padding-left: 10px; @@ -80,7 +82,12 @@ limitations under the License. cursor: pointer; } -.mx_MessageComposer_call { +.mx_MessageComposer_videocall { + padding-right: 10px; + padding-top: 4px; +} + +.mx_MessageComposer_voicecall { padding-right: 10px; padding-top: 4px; } diff --git a/src/skins/vector/css/molecules/RoomDropTarget.css b/src/skins/vector/css/molecules/RoomDropTarget.css index 4eea49e1..2e655c73 100644 --- a/src/skins/vector/css/molecules/RoomDropTarget.css +++ b/src/skins/vector/css/molecules/RoomDropTarget.css @@ -15,7 +15,7 @@ limitations under the License. */ .mx_RoomDropTarget { - font-size: 14px; + font-size: 13px; margin-left: 10px; margin-right: 15px; padding-top: 5px; diff --git a/src/skins/vector/css/molecules/RoomHeader.css b/src/skins/vector/css/molecules/RoomHeader.css index e033d735..b1469e35 100644 --- a/src/skins/vector/css/molecules/RoomHeader.css +++ b/src/skins/vector/css/molecules/RoomHeader.css @@ -23,6 +23,9 @@ limitations under the License. height: 83px; border-bottom: 1px solid #eeeeee; + -webkit-align-items: center; + align-items: center; + display: -webkit-box; display: -moz-box; display: -ms-flexbox; @@ -31,8 +34,6 @@ limitations under the License. } .mx_RoomHeader_leftRow { - height: 48px; - margin-top: 18px; margin-left: -2px; -webkit-box-ordinal-group: 1; @@ -47,7 +48,6 @@ limitations under the License. .mx_RoomHeader_textButton { height: 48px; - margin-top: 18px; background-color: #76cfa6; border-radius: 48px; margin-right: 8px; @@ -72,7 +72,7 @@ limitations under the License. } .mx_RoomHeader_rightRow { - margin-top: 32px; + margin-top: 4px; background-color: #fff; -webkit-box-ordinal-group: 3; @@ -84,14 +84,14 @@ limitations under the License. .mx_RoomHeader_info { display: table-cell; - height: 48px; + /* height: 48px; */ vertical-align: middle; } .mx_RoomHeader_simpleHeader { line-height: 83px; color: #454545; - font-size: 24px; + font-size: 22px; font-weight: bold; overflow: hidden; margin-left: 63px; @@ -110,11 +110,13 @@ limitations under the License. cursor: pointer; vertical-align: middle; height: 28px; + overflow: hidden; color: #454545; font-weight: bold; - font-size: 24px; + font-size: 22px; padding-left: 19px; padding-right: 16px; + /* why isn't text-overflow working? */ text-overflow: ellipsis; } @@ -122,6 +124,13 @@ limitations under the License. display: inline-block; } +.mx_RoomHeader_searchStatus { + display: inline-block; + font-weight: normal; + overflow-y: hidden; + opacity: 0.6; +} + .mx_RoomHeader_settingsButton { display: inline-block; visibility: hidden; @@ -130,14 +139,24 @@ limitations under the License. left: 4px; } -.mx_RoomHeader_name:hover { +.mx_RoomHeader_leftRow:hover .mx_RoomHeader_name { color: #76cfa6; } -.mx_RoomHeader_name:hover .mx_RoomHeader_settingsButton { +.mx_RoomHeader_leftRow:hover .mx_RoomHeader_settingsButton { visibility: visible; } +.mx_RoomHeader_leaveButton { + visibility: hidden; + margin-top: -1px; +} + +.mx_RoomHeader_wrapper:hover .mx_RoomHeader_leaveButton { + visibility: visible; +} + + .mx_RoomHeader_nameEditing { padding-left: 8px; padding-right: 16px; @@ -149,7 +168,7 @@ limitations under the License. width: 260px; border: 1px solid #c7c7c7; font-weight: 300; - font-size: 14px; + font-size: 13px; padding: 9px; } @@ -160,7 +179,7 @@ limitations under the License. .mx_RoomHeader_topic { vertical-align: bottom; float: left; - max-height: 38px; + max-height: 42px; color: #454545; font-weight: 300; padding-left: 19px; diff --git a/src/skins/vector/css/molecules/RoomSettings.css b/src/skins/vector/css/molecules/RoomSettings.css index a669c5b2..dabdd55f 100644 --- a/src/skins/vector/css/molecules/RoomSettings.css +++ b/src/skins/vector/css/molecules/RoomSettings.css @@ -39,7 +39,7 @@ limitations under the License. border-radius: 3px; border: 1px solid #c7c7c7; font-weight: 300; - font-size: 14px; + font-size: 13px; padding: 9px; margin-top: 6px; } @@ -59,7 +59,7 @@ limitations under the License. height: 36px; border-radius: 36px; font-weight: 400; - font-size: 16px; + font-size: 15px; color: #fff; background-color: #76cfa6; width: auto; diff --git a/src/skins/vector/css/molecules/RoomTile.css b/src/skins/vector/css/molecules/RoomTile.css index 37d2e1b6..ef907d25 100644 --- a/src/skins/vector/css/molecules/RoomTile.css +++ b/src/skins/vector/css/molecules/RoomTile.css @@ -18,19 +18,19 @@ limitations under the License. cursor: pointer; /* This fixes wrapping of long room names, but breaks drag & drop previews */ /* display: table-row; */ - font-size: 14px; + font-size: 13px; } .mx_RoomTile_avatar { display: table-cell; padding-right: 8px; - padding-top: 4px; - padding-bottom: 2px; + padding-top: 6px; + padding-bottom: 6px; padding-left: 18px; - vertical-align: middle; width: 24px; height: 24px; position: relative; + vertical-align: middle; } .mx_RoomTile_avatar img { @@ -48,7 +48,8 @@ limitations under the License. } .mx_RoomTile_invite { - color: rgba(69, 69, 69, 0.5); +/* color: rgba(69, 69, 69, 0.5); +*/ } .collapsed .mx_RoomTile_name { @@ -112,6 +113,10 @@ limitations under the License. color: #76cfa6 ! important; } +.mx_RoomTile_highlight .mx_RoomTile_name { + color: #ff0064 ! important; +} + .mx_RoomTile.mx_RoomTile_selected .mx_RoomTile_name { background: url('img/selected.png'); background-repeat: no-repeat; diff --git a/src/skins/vector/css/molecules/SearchBar.css b/src/skins/vector/css/molecules/SearchBar.css index b116674b..3698c852 100644 --- a/src/skins/vector/css/molecules/SearchBar.css +++ b/src/skins/vector/css/molecules/SearchBar.css @@ -21,24 +21,43 @@ limitations under the License. align-items: center; } -.mx_SearchBar input { +.mx_SearchBar_input { display: inline block; - border-radius: 3px; + border-radius: 3px 0px 0px 3px; border: 1px solid #f0f0f0; - font-size: 16px; + font-size: 15px; padding: 9px; padding-left: 11px; - margin-right: 17px; width: auto; flex: 1 1 0; } +.mx_SearchBar_searchButton { + cursor: pointer; + margin-right: 10px; + width: 37px; + height: 37px; + border-radius: 0px 3px 3px 0px; + background-color: #76CFA6; +} + +@keyframes pulsate { + 0% { opacity: 1.0; } + 50% { opacity: 0.25; } + 100% { opacity: 1.0; } +} + +.mx_SearchBar_searching img { + animation: pulsate 0.75s ease-out; + animation-iteration-count: infinite; +} + .mx_SearchBar_button { display: inline; border: 0px; border-radius: 36px; font-weight: 400; - font-size: 16px; + font-size: 15px; color: #fff; background-color: #76cfa6; width: auto; diff --git a/src/skins/vector/css/molecules/SenderProfile.css b/src/skins/vector/css/molecules/SenderProfile.css index 45db913e..fd88ee27 100644 --- a/src/skins/vector/css/molecules/SenderProfile.css +++ b/src/skins/vector/css/molecules/SenderProfile.css @@ -13,8 +13,3 @@ 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. */ - -.mx_SenderProfile_zalgo { - font-family: Helvetica, Arial, Sans-Serif; - display: table-row ! important; -} diff --git a/src/skins/vector/css/molecules/ServerConfig.css b/src/skins/vector/css/molecules/ServerConfig.css index db0572c8..58bdcfdf 100644 --- a/src/skins/vector/css/molecules/ServerConfig.css +++ b/src/skins/vector/css/molecules/ServerConfig.css @@ -25,7 +25,7 @@ limitations under the License. .mx_ServerConfig_help:link { opacity: 0.8; - font-size: 14px; + font-size: 13px; font-weight: 300; color: #4a4a4a; } \ No newline at end of file diff --git a/src/skins/vector/css/organisms/CreateRoom.css b/src/skins/vector/css/organisms/CreateRoom.css index 578c79e6..feb8bbff 100644 --- a/src/skins/vector/css/organisms/CreateRoom.css +++ b/src/skins/vector/css/organisms/CreateRoom.css @@ -26,7 +26,7 @@ limitations under the License. border-radius: 3px; border: 1px solid #c7c7c7; font-weight: 300; - font-size: 14px; + font-size: 13px; padding: 9px; margin-top: 6px; } diff --git a/src/skins/vector/css/organisms/LeftPanel.css b/src/skins/vector/css/organisms/LeftPanel.css index 37de0f0e..7451d167 100644 --- a/src/skins/vector/css/organisms/LeftPanel.css +++ b/src/skins/vector/css/organisms/LeftPanel.css @@ -69,11 +69,12 @@ limitations under the License. } .mx_LeftPanel .mx_BottomLeftMenu .mx_BottomLeftMenu_options { - margin-top: 17px; + margin-top: 15px; width: 100%; } .mx_LeftPanel .mx_BottomLeftMenu img { border-radius: 0px; background-color: transparent; + vertical-align: middle; } \ No newline at end of file diff --git a/src/skins/vector/css/organisms/MemberList.css b/src/skins/vector/css/organisms/MemberList.css index df699e64..ce936d2c 100644 --- a/src/skins/vector/css/organisms/MemberList.css +++ b/src/skins/vector/css/organisms/MemberList.css @@ -45,13 +45,13 @@ limitations under the License. } .mx_MemberList_invite { - font-family: 'Myriad Pro', Helvetica, Arial, Sans-Serif; + font-family: 'Open Sans', Arial, Helvetica, Sans-Serif; border-radius: 3px; border: 1px solid #f0f0f0; padding: 9px; color: #454545; margin-left: 3px; - font-size: 16px; + font-size: 15px; margin-bottom: 8px; width: 180px; } @@ -69,7 +69,7 @@ limitations under the License. text-transform: uppercase; color: #3d3b39; font-weight: 600; - font-size: 14px; + font-size: 13px; padding-left: 3px; padding-right: 12px; margin-top: 8px; diff --git a/src/skins/vector/css/organisms/RightPanel.css b/src/skins/vector/css/organisms/RightPanel.css index bf473a44..645a6263 100644 --- a/src/skins/vector/css/organisms/RightPanel.css +++ b/src/skins/vector/css/organisms/RightPanel.css @@ -66,7 +66,7 @@ limitations under the License. .mx_RightPanel_headerButton_badge { position: absolute; - top: 5px; + top: 4px; left: 28px; font-size: 12px; background-color: #76cfa6; @@ -75,7 +75,7 @@ limitations under the License. border-radius: 20px; padding-left: 4px; padding-right: 4px; - padding-top: 2px; + padding-top: 0px; } .mx_RightPanel .mx_MemberList, diff --git a/src/skins/vector/css/organisms/RoomDirectory.css b/src/skins/vector/css/organisms/RoomDirectory.css index f53f0556..61fcfa6e 100644 --- a/src/skins/vector/css/organisms/RoomDirectory.css +++ b/src/skins/vector/css/organisms/RoomDirectory.css @@ -50,7 +50,7 @@ limitations under the License. border-radius: 3px; border: 1px solid #c7c7c7; font-weight: 300; - font-size: 14px; + font-size: 13px; padding: 9px; margin-top: 12px; margin-bottom: 12px; @@ -70,7 +70,7 @@ limitations under the License. .mx_RoomDirectory_table th { font-weight: 400; - font-size: 12px; + font-size: 11px; } .mx_RoomDirectory_table tbody { @@ -79,7 +79,6 @@ limitations under the License. .mx_RoomDirectory_table td { font-weight: 300; - font-size: 16px; overflow-x: hidden; text-overflow: ellipsis; } @@ -90,7 +89,7 @@ limitations under the License. .mx_RoomDirectory_table .mx_RoomDirectory_topic { font-weight: 400; - font-size: 12px; + font-size: 11px; } .mx_RoomDirectory_table td, diff --git a/src/skins/vector/css/organisms/RoomList.css b/src/skins/vector/css/organisms/RoomList.css index 7f5e2272..bb81686c 100644 --- a/src/skins/vector/css/organisms/RoomList.css +++ b/src/skins/vector/css/organisms/RoomList.css @@ -25,3 +25,10 @@ limitations under the License. padding-left: 12px; padding-right: 12px; } + +/* Evil hacky override until Chrome fixes drop and drag table cells + and we can correctly fix horizontal wrapping in the sidebar again */ +.mx_RoomList_scrollbar .gm-scroll-view { + overflow-x: hidden ! important; + overflow-y: scroll ! important; +} diff --git a/src/skins/vector/css/organisms/RoomSubList.css b/src/skins/vector/css/organisms/RoomSubList.css index 57d23a38..b143c998 100644 --- a/src/skins/vector/css/organisms/RoomSubList.css +++ b/src/skins/vector/css/organisms/RoomSubList.css @@ -29,7 +29,7 @@ limitations under the License. text-transform: uppercase; color: #3d3b39; font-weight: 600; - font-size: 14px; + font-size: 13px; padding-left: 12px; padding-right: 12px; margin-top: 8px; diff --git a/src/skins/vector/css/organisms/RoomView.css b/src/skins/vector/css/organisms/RoomView.css index 94fff290..2358bc09 100644 --- a/src/skins/vector/css/organisms/RoomView.css +++ b/src/skins/vector/css/organisms/RoomView.css @@ -170,10 +170,35 @@ limitations under the License. .mx_RoomView_statusAreaBox_line { border-top: 1px solid #eee; - margin-left: 63px; height: 1px; } +.mx_RoomView_inCall .mx_RoomView_statusAreaBox_line { + border-top: 1px hidden; +} + +.mx_RoomView_inCall .mx_MessageComposer_wrapper { + border-top: 2px hidden; +} + +.mx_RoomView_inCall .mx_RoomView_statusAreaBox { + background-color: #76CFA6; + color: #fff; + position: relative; +} + +.mx_RoomView_voipChevron { + position: absolute; + bottom: -10px; + right: 11px; +} + +.mx_RoomView_voipButton { + float: right; + margin-right: 13px; + cursor: pointer; +} + .mx_RoomView_unreadMessagesBar { color: #ff0064; cursor: pointer; @@ -186,6 +211,16 @@ limitations under the License. vertical-align: middle; } +.mx_RoomView_callBar { + margin-top: 5px; +} + +.mx_RoomView_callBar img { + padding-left: 13px; + padding-right: 30px; + vertical-align: middle; +} + .mx_RoomView_connectionLostBar { margin-top: 19px; height: 58px; @@ -204,7 +239,7 @@ limitations under the License. .mx_RoomView_connectionLostBar_desc { color: #454545; - font-size: 14px; + font-size: 13px; opacity: 0.5; } @@ -215,8 +250,8 @@ limitations under the License. } .mx_RoomView_typingBar { - margin-top: 10px; - margin-left: 63px; + margin-top: 6px; + margin-left: 65px; color: #4a4a4a; opacity: 0.5; } @@ -228,6 +263,11 @@ limitations under the License. float: left; } +.mx_RoomView_typingText { + overflow-y: hidden; + display: block; +} + .mx_RoomView .mx_MessageComposer { -webkit-box-ordinal-group: 5; -moz-box-ordinal-group: 5; @@ -241,43 +281,6 @@ limitations under the License. margin-right: 2px; } -.mx_RoomView_uploadProgressOuter { - height: 4px; - margin-left: 63px; - margin-top: -1px; -} - -.mx_RoomView_uploadProgressInner { - background-color: #76cfa6; - height: 4px; -} - -.mx_RoomView_uploadFilename { - margin-top: 5px; - margin-left: 65px; - opacity: 0.5; - color: #4a4a4a; -} - -.mx_RoomView_uploadIcon { - float: left; - margin-top: 1px; - margin-left: 14px; -} - -.mx_RoomView_uploadCancel { - float: right; - margin-top: 5px; - margin-right: 10px; -} - -.mx_RoomView_uploadBytes { - float: right; - margin-top: 5px; - margin-right: 30px; - color: #76cfa6; -} - .mx_RoomView_ongoingConfCallNotification { width: 100%; text-align: center; diff --git a/src/skins/vector/css/pages/MatrixChat.css b/src/skins/vector/css/pages/MatrixChat.css index b95f6a41..2190e496 100644 --- a/src/skins/vector/css/pages/MatrixChat.css +++ b/src/skins/vector/css/pages/MatrixChat.css @@ -14,6 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. */ +.mx_MatrixChat_splash { + position: relative; + height: 100%; +} + +.mx_MatrixChat_splashButtons { + text-align: center; + width: 100%; + position: absolute; + bottom: 30px; +} + .mx_MatrixChat_wrapper { display: -webkit-box; display: -moz-box; diff --git a/src/skins/vector/css/templates/Login.css b/src/skins/vector/css/templates/Login.css index 11fba43f..d1b28b1e 100644 --- a/src/skins/vector/css/templates/Login.css +++ b/src/skins/vector/css/templates/Login.css @@ -55,7 +55,7 @@ limitations under the License. border-radius: 3px; border: 1px solid #c7c7c7; font-weight: 300; - font-size: 14px; + font-size: 13px; padding: 9px; margin-bottom: 14px; } @@ -68,12 +68,12 @@ limitations under the License. height: 40px; border: 0px; background-color: #76cfa6; - font-size: 16px; + font-size: 15px; color: #fff; } .mx_Login_label { - font-size: 14px; + font-size: 13px; opacity: 0.8; } @@ -85,7 +85,7 @@ limitations under the License. display: block; text-align: center; width: 100%; - font-size: 14px; + font-size: 13px; opacity: 0.8; } @@ -97,7 +97,7 @@ limitations under the License. display: block; text-align: center; width: 100%; - font-size: 14px; + font-size: 13px; opacity: 0.8; } diff --git a/src/skins/vector/fonts/OpenSans.css b/src/skins/vector/fonts/OpenSans.css new file mode 100644 index 00000000..05be90d5 --- /dev/null +++ b/src/skins/vector/fonts/OpenSans.css @@ -0,0 +1,12 @@ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans'), local('OpenSans'), url(u-WUoqrET9fUeobQW7jkRaCWcynf_cDxXwCLxiixG1c.ttf) format('truetype'); +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), url(k3k702ZOKiLJc3WVjuplzNqQynqKV_9Plp7mupa0S4g.ttf) format('truetype'); +} diff --git a/src/skins/vector/fonts/k3k702ZOKiLJc3WVjuplzNqQynqKV_9Plp7mupa0S4g.ttf b/src/skins/vector/fonts/k3k702ZOKiLJc3WVjuplzNqQynqKV_9Plp7mupa0S4g.ttf new file mode 100644 index 00000000..bffc5fcf Binary files /dev/null and b/src/skins/vector/fonts/k3k702ZOKiLJc3WVjuplzNqQynqKV_9Plp7mupa0S4g.ttf differ diff --git a/src/skins/vector/fonts/u-WUoqrET9fUeobQW7jkRaCWcynf_cDxXwCLxiixG1c.ttf b/src/skins/vector/fonts/u-WUoqrET9fUeobQW7jkRaCWcynf_cDxXwCLxiixG1c.ttf new file mode 100644 index 00000000..89ce23b4 Binary files /dev/null and b/src/skins/vector/fonts/u-WUoqrET9fUeobQW7jkRaCWcynf_cDxXwCLxiixG1c.ttf differ diff --git a/src/skins/vector/img/call.svg b/src/skins/vector/img/call.svg new file mode 100644 index 00000000..f528f9a2 --- /dev/null +++ b/src/skins/vector/img/call.svg @@ -0,0 +1,17 @@ + + + + icons_video + Created with bin/sketchtool. + + + + + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/cancel.svg b/src/skins/vector/img/cancel.svg new file mode 100644 index 00000000..e3206002 --- /dev/null +++ b/src/skins/vector/img/cancel.svg @@ -0,0 +1,10 @@ + + + + Slice 1 + Created with Sketch. + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/files.svg b/src/skins/vector/img/files.svg new file mode 100644 index 00000000..20aba851 --- /dev/null +++ b/src/skins/vector/img/files.svg @@ -0,0 +1,18 @@ + + + + icons_browse_files + Created with bin/sketchtool. + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/fullscreen.svg b/src/skins/vector/img/fullscreen.svg new file mode 100644 index 00000000..e333abb6 --- /dev/null +++ b/src/skins/vector/img/fullscreen.svg @@ -0,0 +1,23 @@ + + + + Zoom + Created with Sketch. + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/hangup.svg b/src/skins/vector/img/hangup.svg new file mode 100644 index 00000000..be038d2b --- /dev/null +++ b/src/skins/vector/img/hangup.svg @@ -0,0 +1,15 @@ + + + + Fill 72 + Path 98 + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/leave.svg b/src/skins/vector/img/leave.svg new file mode 100644 index 00000000..84856073 --- /dev/null +++ b/src/skins/vector/img/leave.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/skins/vector/img/list-close.svg b/src/skins/vector/img/list-close.svg new file mode 100644 index 00000000..eb60864e --- /dev/null +++ b/src/skins/vector/img/list-close.svg @@ -0,0 +1,10 @@ + + + + Slice 1 + Created with Sketch. + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/list-open.svg b/src/skins/vector/img/list-open.svg new file mode 100644 index 00000000..a682ec90 --- /dev/null +++ b/src/skins/vector/img/list-open.svg @@ -0,0 +1,10 @@ + + + + Slice 1 + Created with Sketch. + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/members.svg b/src/skins/vector/img/members.svg new file mode 100644 index 00000000..0f115966 --- /dev/null +++ b/src/skins/vector/img/members.svg @@ -0,0 +1,14 @@ + + + + icons_people + Created with bin/sketchtool. + + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/search-button.svg b/src/skins/vector/img/search-button.svg new file mode 100644 index 00000000..f4808842 --- /dev/null +++ b/src/skins/vector/img/search-button.svg @@ -0,0 +1,15 @@ + + + + icon_search + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/search.svg b/src/skins/vector/img/search.svg new file mode 100644 index 00000000..bd4cd920 --- /dev/null +++ b/src/skins/vector/img/search.svg @@ -0,0 +1,17 @@ + + + + icons_search + Created with bin/sketchtool. + + + + + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/settings.svg b/src/skins/vector/img/settings.svg new file mode 100644 index 00000000..4190c7b8 --- /dev/null +++ b/src/skins/vector/img/settings.svg @@ -0,0 +1,12 @@ + + + + icon_settings_small + Created with bin/sketchtool. + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/sound-indicator.svg b/src/skins/vector/img/sound-indicator.svg new file mode 100644 index 00000000..9b8de53d --- /dev/null +++ b/src/skins/vector/img/sound-indicator.svg @@ -0,0 +1,17 @@ + + + + sound_indicator + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/tab.svg b/src/skins/vector/img/tab.svg new file mode 100644 index 00000000..eae92dcf --- /dev/null +++ b/src/skins/vector/img/tab.svg @@ -0,0 +1,16 @@ + + + + icon_eol + Created with bin/sketchtool. + + + + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/upload-big.svg b/src/skins/vector/img/upload-big.svg new file mode 100644 index 00000000..6099c2e9 --- /dev/null +++ b/src/skins/vector/img/upload-big.svg @@ -0,0 +1,19 @@ + + + + icons_upload_drop + Created with bin/sketchtool. + + + + + + + + + + + + + + diff --git a/src/skins/vector/img/upload-original.svg b/src/skins/vector/img/upload-original.svg new file mode 100644 index 00000000..962fc49d --- /dev/null +++ b/src/skins/vector/img/upload-original.svg @@ -0,0 +1,19 @@ + + + + icons_upload + Created with bin/sketchtool. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/upload.svg b/src/skins/vector/img/upload.svg new file mode 100644 index 00000000..039014a2 --- /dev/null +++ b/src/skins/vector/img/upload.svg @@ -0,0 +1,19 @@ + + + + icons_upload + Created with bin/sketchtool. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/video-mute.svg b/src/skins/vector/img/video-mute.svg new file mode 100644 index 00000000..6de60ba3 --- /dev/null +++ b/src/skins/vector/img/video-mute.svg @@ -0,0 +1,17 @@ + + + + icons_video copy + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/video-unmute.svg b/src/skins/vector/img/video-unmute.svg new file mode 100644 index 00000000..a6c6c3b6 --- /dev/null +++ b/src/skins/vector/img/video-unmute.svg @@ -0,0 +1,18 @@ + + + + icons_video copy + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/voice-mute.svg b/src/skins/vector/img/voice-mute.svg new file mode 100644 index 00000000..33664107 --- /dev/null +++ b/src/skins/vector/img/voice-mute.svg @@ -0,0 +1,14 @@ + + + + Audio + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/voice-unmute.svg b/src/skins/vector/img/voice-unmute.svg new file mode 100644 index 00000000..0d7e6f42 --- /dev/null +++ b/src/skins/vector/img/voice-unmute.svg @@ -0,0 +1,15 @@ + + + + Audio + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/voice.png b/src/skins/vector/img/voice.png new file mode 100644 index 00000000..5ba765b0 Binary files /dev/null and b/src/skins/vector/img/voice.png differ diff --git a/src/skins/vector/img/voice.svg b/src/skins/vector/img/voice.svg new file mode 100644 index 00000000..ff87270b --- /dev/null +++ b/src/skins/vector/img/voice.svg @@ -0,0 +1,13 @@ + + + + icon_voice + Created with Sketch. + + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/voip-chevron.svg b/src/skins/vector/img/voip-chevron.svg new file mode 100644 index 00000000..5f7cbe71 --- /dev/null +++ b/src/skins/vector/img/voip-chevron.svg @@ -0,0 +1,12 @@ + + + + Triangle 1 + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/skins/vector/img/voip-mute.png b/src/skins/vector/img/voip-mute.png new file mode 100644 index 00000000..a16d1001 Binary files /dev/null and b/src/skins/vector/img/voip-mute.png differ diff --git a/src/skins/vector/img/warning.svg b/src/skins/vector/img/warning.svg new file mode 100644 index 00000000..b9a96a88 --- /dev/null +++ b/src/skins/vector/img/warning.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/skins/vector/skindex.js b/src/skins/vector/skindex.js deleted file mode 100644 index cf279c87..00000000 --- a/src/skins/vector/skindex.js +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -/* - * THIS FILE IS AUTO-GENERATED - * You can edit it you like, but your changes will be overwritten, - * so you'd just be trying to swim upstream like a salmon. - * You are not a salmon. - */ - -var skin = {}; - -skin['atoms.EditableText'] = require('./views/atoms/EditableText'); -skin['atoms.EnableNotificationsButton'] = require('./views/atoms/EnableNotificationsButton'); -skin['atoms.ImageView'] = require('./views/atoms/ImageView'); -skin['atoms.LogoutButton'] = require('./views/atoms/LogoutButton'); -skin['atoms.MemberAvatar'] = require('./views/atoms/MemberAvatar'); -skin['atoms.MessageTimestamp'] = require('./views/atoms/MessageTimestamp'); -skin['atoms.RoomAvatar'] = require('./views/atoms/RoomAvatar'); -skin['atoms.Spinner'] = require('./views/atoms/Spinner'); -skin['atoms.create_room.CreateRoomButton'] = require('./views/atoms/create_room/CreateRoomButton'); -skin['atoms.create_room.Presets'] = require('./views/atoms/create_room/Presets'); -skin['atoms.create_room.RoomAlias'] = require('./views/atoms/create_room/RoomAlias'); -skin['atoms.voip.VideoFeed'] = require('./views/atoms/voip/VideoFeed'); -skin['molecules.BottomLeftMenu'] = require('./views/molecules/BottomLeftMenu'); -skin['molecules.BottomLeftMenuTile'] = require('./views/molecules/BottomLeftMenuTile'); -skin['molecules.ChangeAvatar'] = require('./views/molecules/ChangeAvatar'); -skin['molecules.ChangeDisplayName'] = require('./views/molecules/ChangeDisplayName'); -skin['molecules.ChangePassword'] = require('./views/molecules/ChangePassword'); -skin['molecules.DateSeparator'] = require('./views/molecules/DateSeparator'); -skin['molecules.EventAsTextTile'] = require('./views/molecules/EventAsTextTile'); -skin['molecules.EventTile'] = require('./views/molecules/EventTile'); -skin['molecules.MEmoteTile'] = require('./views/molecules/MEmoteTile'); -skin['molecules.MFileTile'] = require('./views/molecules/MFileTile'); -skin['molecules.MImageTile'] = require('./views/molecules/MImageTile'); -skin['molecules.MNoticeTile'] = require('./views/molecules/MNoticeTile'); -skin['molecules.MRoomMemberTile'] = require('./views/molecules/MRoomMemberTile'); -skin['molecules.MTextTile'] = require('./views/molecules/MTextTile'); -skin['molecules.MatrixToolbar'] = require('./views/molecules/MatrixToolbar'); -skin['molecules.MemberInfo'] = require('./views/molecules/MemberInfo'); -skin['molecules.MemberTile'] = require('./views/molecules/MemberTile'); -skin['molecules.MessageComposer'] = require('./views/molecules/MessageComposer'); -skin['molecules.MessageContextMenu'] = require('./views/molecules/MessageContextMenu'); -skin['molecules.MessageTile'] = require('./views/molecules/MessageTile'); -skin['molecules.ProgressBar'] = require('./views/molecules/ProgressBar'); -skin['molecules.RoomCreate'] = require('./views/molecules/RoomCreate'); -skin['molecules.RoomDropTarget'] = require('./views/molecules/RoomDropTarget'); -skin['molecules.RoomHeader'] = require('./views/molecules/RoomHeader'); -skin['molecules.RoomSettings'] = require('./views/molecules/RoomSettings'); -skin['molecules.RoomTile'] = require('./views/molecules/RoomTile'); -skin['molecules.RoomTooltip'] = require('./views/molecules/RoomTooltip'); -skin['molecules.SearchBar'] = require('./views/molecules/SearchBar'); -skin['molecules.SenderProfile'] = require('./views/molecules/SenderProfile'); -skin['molecules.ServerConfig'] = require('./views/molecules/ServerConfig'); -skin['molecules.UnknownMessageTile'] = require('./views/molecules/UnknownMessageTile'); -skin['molecules.UserSelector'] = require('./views/molecules/UserSelector'); -skin['molecules.voip.CallView'] = require('./views/molecules/voip/CallView'); -skin['molecules.voip.IncomingCallBox'] = require('./views/molecules/voip/IncomingCallBox'); -skin['molecules.voip.VideoView'] = require('./views/molecules/voip/VideoView'); -skin['organisms.CasLogin'] = require('./views/organisms/CasLogin'); -skin['organisms.CreateRoom'] = require('./views/organisms/CreateRoom'); -skin['organisms.ErrorDialog'] = require('./views/organisms/ErrorDialog'); -skin['organisms.LeftPanel'] = require('./views/organisms/LeftPanel'); -skin['organisms.LogoutPrompt'] = require('./views/organisms/LogoutPrompt'); -skin['organisms.MemberList'] = require('./views/organisms/MemberList'); -skin['organisms.Notifier'] = require('./views/organisms/Notifier'); -skin['organisms.QuestionDialog'] = require('./views/organisms/QuestionDialog'); -skin['organisms.RightPanel'] = require('./views/organisms/RightPanel'); -skin['organisms.RoomDirectory'] = require('./views/organisms/RoomDirectory'); -skin['organisms.RoomList'] = require('./views/organisms/RoomList'); -skin['organisms.RoomSubList'] = require('./views/organisms/RoomSubList'); -skin['organisms.RoomView'] = require('./views/organisms/RoomView'); -skin['organisms.UserSettings'] = require('./views/organisms/UserSettings'); -skin['organisms.ViewSource'] = require('./views/organisms/ViewSource'); -skin['pages.CompatibilityPage'] = require('./views/pages/CompatibilityPage'); -skin['pages.MatrixChat'] = require('./views/pages/MatrixChat'); -skin['templates.Login'] = require('./views/templates/Login'); -skin['templates.Register'] = require('./views/templates/Register'); - -module.exports = skin; \ No newline at end of file diff --git a/src/skins/vector/skinfo.json b/src/skins/vector/skinfo.json deleted file mode 100644 index 287ff9e2..00000000 --- a/src/skins/vector/skinfo.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "baseSkin": "" -} diff --git a/src/skins/vector/views/atoms/EditableText.js b/src/skins/vector/views/atoms/EditableText.js deleted file mode 100644 index 1848b029..00000000 --- a/src/skins/vector/views/atoms/EditableText.js +++ /dev/null @@ -1,76 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); - -var EditableTextController = require('matrix-react-sdk/lib/controllers/atoms/EditableText') - -module.exports = React.createClass({ - displayName: 'EditableText', - mixins: [EditableTextController], - - onKeyUp: function(ev) { - if (ev.key == "Enter") { - this.onFinish(ev); - } else if (ev.key == "Escape") { - this.cancelEdit(); - } - }, - - onClickDiv: function() { - this.setState({ - phase: this.Phases.Edit, - }) - }, - - onFocus: function(ev) { - ev.target.setSelectionRange(0, ev.target.value.length); - }, - - onFinish: function(ev) { - if (ev.target.value) { - this.setValue(ev.target.value, ev.key === "Enter"); - } else { - this.cancelEdit(); - } - }, - - render: function() { - var editable_el; - - if (this.state.phase == this.Phases.Display) { - if (this.state.value) { - editable_el =
    {this.state.value}
    ; - } else { - editable_el =
    {this.props.label}
    ; - } - } else if (this.state.phase == this.Phases.Edit) { - editable_el = ( -
    - -
    - ); - } - - return ( -
    - {editable_el} -
    - ); - } -}); diff --git a/src/skins/vector/views/atoms/EnableNotificationsButton.js b/src/skins/vector/views/atoms/EnableNotificationsButton.js deleted file mode 100644 index edef9edc..00000000 --- a/src/skins/vector/views/atoms/EnableNotificationsButton.js +++ /dev/null @@ -1,38 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); - -var EnableNotificationsButtonController = require('matrix-react-sdk/lib/controllers/atoms/EnableNotificationsButton') - -module.exports = React.createClass({ - displayName: 'EnableNotificationsButton', - mixins: [EnableNotificationsButtonController], - - render: function() { - if (this.enabled()) { - return ( - - ); - } else { - return ( - - ); - } - } -}); diff --git a/src/skins/vector/views/atoms/LogoutButton.js b/src/skins/vector/views/atoms/LogoutButton.js deleted file mode 100644 index 619160f6..00000000 --- a/src/skins/vector/views/atoms/LogoutButton.js +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); - -var LogoutButtonController = require('matrix-react-sdk/lib/controllers/atoms/LogoutButton') - -module.exports = React.createClass({ - displayName: 'LogoutButton', - mixins: [LogoutButtonController], - - render: function() { - return ( - - ); - } -}); diff --git a/src/skins/vector/views/atoms/MemberAvatar.js b/src/skins/vector/views/atoms/MemberAvatar.js deleted file mode 100644 index c8606cd7..00000000 --- a/src/skins/vector/views/atoms/MemberAvatar.js +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); -var Avatar = require('../../../../Avatar'); - -var MemberAvatarController = require('matrix-react-sdk/lib/controllers/atoms/MemberAvatar') - -module.exports = React.createClass({ - displayName: 'MemberAvatar', - mixins: [MemberAvatarController], - - avatarUrlForMember: function(member) { - return Avatar.avatarUrlForMember( - member, - this.props.member, - this.props.width, - this.props.height, - this.props.resizeMethod - ); - }, - - skinnedDefaultAvatarUrl: function(member, width, height, resizeMethod) { - return Avatar.defaultAvatarUrlForString(member.userId); - }, - - render: function() { - // XXX: recalculates default avatar url constantly - if (this.state.imageUrl === this.defaultAvatarUrl(this.props.member)) { - var initial; - if (this.props.member.name[0]) - initial = this.props.member.name[0].toUpperCase(); - if (initial === '@' && this.props.member.name[1]) - initial = this.props.member.name[1].toUpperCase(); - - return ( - - - - - ); - } - return ( - - ); - } -}); diff --git a/src/skins/vector/views/atoms/RoomAvatar.js b/src/skins/vector/views/atoms/RoomAvatar.js deleted file mode 100644 index bdd28bad..00000000 --- a/src/skins/vector/views/atoms/RoomAvatar.js +++ /dev/null @@ -1,75 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); - -var RoomAvatarController = require('matrix-react-sdk/lib/controllers/atoms/RoomAvatar') - -module.exports = React.createClass({ - displayName: 'RoomAvatar', - mixins: [RoomAvatarController], - - getUrlList: function() { - return [ - this.roomAvatarUrl(), - this.getOneToOneAvatar(), - this.getFallbackAvatar() - ]; - }, - - getFallbackAvatar: function() { - var images = [ '76cfa6', '50e2c2', 'f4c371' ]; - var total = 0; - for (var i = 0; i < this.props.room.roomId.length; ++i) { - total += this.props.room.roomId.charCodeAt(i); - } - return 'img/' + images[total % images.length] + '.png'; - }, - - render: function() { - var style = { - width: this.props.width, - height: this.props.height, - }; - - // XXX: recalculates fallback avatar constantly - if (this.state.imageUrl === this.getFallbackAvatar()) { - var initial; - if (this.props.room.name[0]) - initial = this.props.room.name[0].toUpperCase(); - if ((initial === '@' || initial === '#') && this.props.room.name[1]) - initial = this.props.room.name[1].toUpperCase(); - - return ( - - - - - ); - } - else { - return - } - - } -}); diff --git a/src/skins/vector/views/atoms/create_room/CreateRoomButton.js b/src/skins/vector/views/atoms/create_room/CreateRoomButton.js deleted file mode 100644 index 2fc9d057..00000000 --- a/src/skins/vector/views/atoms/create_room/CreateRoomButton.js +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); - -var CreateRoomButtonController = require('matrix-react-sdk/lib/controllers/atoms/create_room/CreateRoomButton') - -module.exports = React.createClass({ - displayName: 'CreateRoomButton', - mixins: [CreateRoomButtonController], - - render: function() { - return ( - - ); - } -}); diff --git a/src/skins/vector/views/atoms/create_room/Presets.js b/src/skins/vector/views/atoms/create_room/Presets.js deleted file mode 100644 index a098a7d7..00000000 --- a/src/skins/vector/views/atoms/create_room/Presets.js +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); - -var PresetsController = require('matrix-react-sdk/lib/controllers/atoms/create_room/Presets') - -module.exports = React.createClass({ - displayName: 'CreateRoomPresets', - mixins: [PresetsController], - - onValueChanged: function(ev) { - this.props.onChange(ev.target.value) - }, - - render: function() { - return ( - - ); - } -}); diff --git a/src/skins/vector/views/atoms/create_room/RoomAlias.js b/src/skins/vector/views/atoms/create_room/RoomAlias.js deleted file mode 100644 index 0a8cadc8..00000000 --- a/src/skins/vector/views/atoms/create_room/RoomAlias.js +++ /dev/null @@ -1,79 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); - -var RoomAliasController = require('matrix-react-sdk/lib/controllers/atoms/create_room/RoomAlias') - -module.exports = React.createClass({ - displayName: 'RoomAlias', - mixins: [RoomAliasController], - - onValueChanged: function(ev) { - this.props.onChange(ev.target.value); - }, - - onFocus: function(ev) { - var target = ev.target; - var curr_val = ev.target.value; - - if (this.props.homeserver) { - if (curr_val == "") { - setTimeout(function() { - target.value = "#:" + this.props.homeserver; - target.setSelectionRange(1, 1); - }, 0); - } else { - var suffix = ":" + this.props.homeserver; - setTimeout(function() { - target.setSelectionRange( - curr_val.startsWith("#") ? 1 : 0, - curr_val.endsWith(suffix) ? (target.value.length - suffix.length) : target.value.length - ); - }, 0); - } - } - }, - - onBlur: function(ev) { - var curr_val = ev.target.value; - - if (this.props.homeserver) { - if (curr_val == "#:" + this.props.homeserver) { - ev.target.value = ""; - return; - } - - if (curr_val != "") { - var new_val = ev.target.value; - var suffix = ":" + this.props.homeserver; - if (!curr_val.startsWith("#")) new_val = "#" + new_val; - if (!curr_val.endsWith(suffix)) new_val = new_val + suffix; - ev.target.value = new_val; - } - } - }, - - render: function() { - return ( - - ); - } -}); diff --git a/src/skins/vector/views/molecules/ChangeAvatar.js b/src/skins/vector/views/molecules/ChangeAvatar.js deleted file mode 100644 index 7afac77f..00000000 --- a/src/skins/vector/views/molecules/ChangeAvatar.js +++ /dev/null @@ -1,76 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); - -var sdk = require('matrix-react-sdk') -var ChangeAvatarController = require('matrix-react-sdk/lib/controllers/molecules/ChangeAvatar') - -module.exports = React.createClass({ - displayName: 'ChangeAvatar', - mixins: [ChangeAvatarController], - - onFileSelected: function(ev) { - this.avatarSet = true; - this.setAvatarFromFile(ev.target.files[0]); - }, - - onError: function(error) { - this.setState({ - errorText: "Failed to upload profile picture!" - }); - }, - - render: function() { - var RoomAvatar = sdk.getComponent('atoms.RoomAvatar'); - var avatarImg; - // Having just set an avatar we just display that since it will take a little - // time to propagate through to the RoomAvatar. - if (this.props.room && !this.avatarSet) { - avatarImg = ; - } else { - var style = { - maxWidth: 320, - maxHeight: 240, - }; - avatarImg = ; - } - - switch (this.state.phase) { - case this.Phases.Display: - case this.Phases.Error: - return ( -
    -
    - {avatarImg} -
    -
    - Upload new: - - {this.state.errorText} -
    -
    - ); - case this.Phases.Uploading: - var Loader = sdk.getComponent("atoms.Spinner"); - return ( - - ); - } - } -}); diff --git a/src/skins/vector/views/molecules/ChangeDisplayName.js b/src/skins/vector/views/molecules/ChangeDisplayName.js deleted file mode 100644 index a10ba2a7..00000000 --- a/src/skins/vector/views/molecules/ChangeDisplayName.js +++ /dev/null @@ -1,55 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); -var sdk = require('matrix-react-sdk'); - -var ChangeDisplayNameController = require("matrix-react-sdk/lib/controllers/molecules/ChangeDisplayName"); - -module.exports = React.createClass({ - displayName: 'ChangeDisplayName', - mixins: [ChangeDisplayNameController], - - edit: function() { - this.refs.displayname_edit.edit() - }, - - onValueChanged: function(new_value, shouldSubmit) { - if (shouldSubmit) { - this.changeDisplayname(new_value); - } - }, - - render: function() { - if (this.state.busy) { - var Loader = sdk.getComponent("atoms.Spinner"); - return ( - - ); - } else if (this.state.errorString) { - return ( -
    {this.state.errorString}
    - ); - } else { - var EditableText = sdk.getComponent('atoms.EditableText'); - return ( - - ); - } - } -}); diff --git a/src/skins/vector/views/molecules/ChangePassword.js b/src/skins/vector/views/molecules/ChangePassword.js deleted file mode 100644 index b1d8f28e..00000000 --- a/src/skins/vector/views/molecules/ChangePassword.js +++ /dev/null @@ -1,84 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); - -var ChangePasswordController = require('matrix-react-sdk/lib/controllers/molecules/ChangePassword') - -module.exports = React.createClass({ - displayName: 'ChangePassword', - mixins: [ChangePasswordController], - - onClickChange: function() { - var old_password = this.refs.old_input.value; - var new_password = this.refs.new_input.value; - var confirm_password = this.refs.confirm_input.value; - if (new_password != confirm_password) { - this.setState({ - state: this.Phases.Error, - errorString: "Passwords don't match" - }); - } else if (new_password == '' || old_password == '') { - this.setState({ - state: this.Phases.Error, - errorString: "Passwords can't be empty" - }); - } else { - this.changePassword(old_password, new_password); - } - }, - - render: function() { - switch (this.state.phase) { - case this.Phases.Edit: - case this.Phases.Error: - return ( -
    -
    -
    {this.state.errorString}
    -
    -
    -
    -
    -
    - - -
    -
    - ); - case this.Phases.Uploading: - var Loader = sdk.getComponent("atoms.Spinner"); - return ( -
    - -
    - ); - case this.Phases.Success: - return ( -
    -
    - Success! -
    -
    - -
    -
    - ) - } - } -}); diff --git a/src/skins/vector/views/molecules/EventTile.js b/src/skins/vector/views/molecules/EventTile.js deleted file mode 100644 index c5cb8195..00000000 --- a/src/skins/vector/views/molecules/EventTile.js +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); -var classNames = require("classnames"); - -var sdk = require('matrix-react-sdk') - -var EventTileController = require('matrix-react-sdk/lib/controllers/molecules/EventTile') -var ContextualMenu = require('../../../../ContextualMenu'); - -var TextForEvent = require('matrix-react-sdk/lib/TextForEvent'); - -var eventTileTypes = { - 'm.room.message': 'molecules.MessageTile', - 'm.room.member' : 'molecules.EventAsTextTile', - 'm.call.invite' : 'molecules.EventAsTextTile', - 'm.call.answer' : 'molecules.EventAsTextTile', - 'm.call.hangup' : 'molecules.EventAsTextTile', - 'm.room.name' : 'molecules.EventAsTextTile', - 'm.room.topic' : 'molecules.EventAsTextTile', -}; - -module.exports = React.createClass({ - displayName: 'EventTile', - mixins: [EventTileController], - - statics: { - haveTileForEvent: function(e) { - if (eventTileTypes[e.getType()] == undefined) return false; - if (eventTileTypes[e.getType()] == 'molecules.EventAsTextTile') { - return TextForEvent.textForEvent(e) !== ''; - } else { - return true; - } - } - }, - - getInitialState: function() { - return {menu: false}; - }, - - onEditClicked: function(e) { - var MessageContextMenu = sdk.getComponent('molecules.MessageContextMenu'); - var buttonRect = e.target.getBoundingClientRect() - var x = buttonRect.right; - var y = buttonRect.top + (e.target.height / 2); - var self = this; - ContextualMenu.createMenu(MessageContextMenu, { - mxEvent: this.props.mxEvent, - left: x, - top: y, - onFinished: function() { - self.setState({menu: false}); - } - }); - this.setState({menu: true}); - }, - - render: function() { - var MessageTimestamp = sdk.getComponent('atoms.MessageTimestamp'); - var SenderProfile = sdk.getComponent('molecules.SenderProfile'); - var MemberAvatar = sdk.getComponent('atoms.MemberAvatar'); - - var content = this.props.mxEvent.getContent(); - var msgtype = content.msgtype; - - var EventTileType = sdk.getComponent(eventTileTypes[this.props.mxEvent.getType()]); - // This shouldn't happen: the caller should check we support this type - // before trying to instantiate us - if (!EventTileType) { - throw new Error("Event type not supported"); - } - - var classes = classNames({ - mx_EventTile: true, - mx_EventTile_sending: ['sending', 'queued'].indexOf( - this.props.mxEvent.status - ) !== -1, - mx_EventTile_notSent: this.props.mxEvent.status == 'not_sent', - mx_EventTile_highlight: this.shouldHighlight(), - mx_EventTile_continuation: this.props.continuation, - mx_EventTile_last: this.props.last, - mx_EventTile_contextual: this.props.contextual, - menu: this.state.menu, - }); - var timestamp = - var editButton = ( - - ); - - var aux = null; - if (msgtype === 'm.image') aux = "sent an image"; - else if (msgtype === 'm.video') aux = "sent a video"; - else if (msgtype === 'm.file') aux = "uploaded a file"; - - var avatar, sender; - if (!this.props.continuation) { - if (this.props.mxEvent.sender) { - avatar = ( -
    - -
    - ); - } - if (EventTileType.needsSenderProfile()) { - sender = ; - } - } - return ( -
    - { avatar } - { sender } -
    - { timestamp } - { editButton } - -
    -
    - ); - }, -}); diff --git a/src/skins/vector/views/molecules/MFileTile.js b/src/skins/vector/views/molecules/MFileTile.js deleted file mode 100644 index 9180bd6b..00000000 --- a/src/skins/vector/views/molecules/MFileTile.js +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); - -var MFileTileController = require('matrix-react-sdk/lib/controllers/molecules/MFileTile') - -var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); - -module.exports = React.createClass({ - displayName: 'MFileTile', - mixins: [MFileTileController], - - render: function() { - var content = this.props.mxEvent.getContent(); - var cli = MatrixClientPeg.get(); - - var httpUrl = cli.mxcUrlToHttp(content.url); - var text = this.presentableTextForFile(content); - - if (httpUrl) { - return ( - - - - ); - } else { - var extra = text ? ': '+text : ''; - return - Invalid file{extra} - - } - }, -}); diff --git a/src/skins/vector/views/molecules/MImageTile.js b/src/skins/vector/views/molecules/MImageTile.js deleted file mode 100644 index 2f3b7a55..00000000 --- a/src/skins/vector/views/molecules/MImageTile.js +++ /dev/null @@ -1,105 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); -var filesize = require('filesize'); - -var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); -var Modal = require('matrix-react-sdk/lib/Modal'); -var sdk = require('matrix-react-sdk') - -module.exports = React.createClass({ - displayName: 'MImageTile', - - thumbHeight: function(fullWidth, fullHeight, thumbWidth, thumbHeight) { - if (!fullWidth || !fullHeight) { - // Cannot calculate thumbnail height for image: missing w/h in metadata. We can't even - // log this because it's spammy - return undefined; - } - if (fullWidth < thumbWidth && fullHeight < thumbHeight) { - // no scaling needs to be applied - return fullHeight; - } - var widthMulti = thumbWidth / fullWidth; - var heightMulti = thumbHeight / fullHeight; - if (widthMulti < heightMulti) { - // width is the dominant dimension so scaling will be fixed on that - return Math.floor(widthMulti * fullHeight); - } - else { - // height is the dominant dimension so scaling will be fixed on that - return Math.floor(heightMulti * fullHeight); - } - }, - - onClick: function(ev) { - if (ev.button == 0 && !ev.metaKey) { - ev.preventDefault(); - var content = this.props.mxEvent.getContent(); - var httpUrl = MatrixClientPeg.get().mxcUrlToHttp(content.url); - var ImageView = sdk.getComponent("atoms.ImageView"); - Modal.createDialog(ImageView, { - src: httpUrl, - width: content.info.w, - height: content.info.h, - mxEvent: this.props.mxEvent, - }, "mx_Dialog_lightbox"); - } - }, - - render: function() { - var content = this.props.mxEvent.getContent(); - var cli = MatrixClientPeg.get(); - - var thumbHeight = null; - if (content.info) thumbHeight = this.thumbHeight(content.info.w, content.info.h, 480, 360); - - var imgStyle = {}; - if (thumbHeight) imgStyle['height'] = thumbHeight; - - var thumbUrl = cli.mxcUrlToHttp(content.url, 480, 360); - if (thumbUrl) { - return ( - - - {content.body} - - - - ); - } else if (content.body) { - return ( - - Image '{content.body}' cannot be displayed. - - ); - } else { - return ( - - This image cannot be displayed. - - ); - } - }, -}); diff --git a/src/skins/vector/views/molecules/MNoticeTile.js b/src/skins/vector/views/molecules/MNoticeTile.js deleted file mode 100644 index a0cedb1d..00000000 --- a/src/skins/vector/views/molecules/MNoticeTile.js +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); -var sanitizeHtml = require('sanitize-html'); - -var MNoticeTileController = require('matrix-react-sdk/lib/controllers/molecules/MNoticeTile') - -var allowedAttributes = sanitizeHtml.defaults.allowedAttributes; -allowedAttributes['font'] = ['color']; -var sanitizeHtmlParams = { - allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'font' ]), - allowedAttributes: allowedAttributes, -}; - -module.exports = React.createClass({ - displayName: 'MNoticeTile', - mixins: [MNoticeTileController], - - // FIXME: this entire class is copy-pasted from MTextTile :( - render: function() { - var content = this.props.mxEvent.getContent(); - var originalBody = content.body; - var body; - - if (this.props.searchTerm) { - var lastOffset = 0; - var bodyList = []; - var k = 0; - var offset; - - // XXX: rather than searching for the search term in the body, - // we should be looking at the match delimiters returned by the FTS engine - if (content.format === "org.matrix.custom.html") { - var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams); - var safeSearchTerm = sanitizeHtml(this.props.searchTerm, sanitizeHtmlParams); - while ((offset = safeBody.indexOf(safeSearchTerm, lastOffset)) >= 0) { - // FIXME: we need to apply the search highlighting to only the text elements of HTML, which means - // hooking into the sanitizer parser rather than treating it as a string. Otherwise - // the act of highlighting a or whatever will break the HTML badly. - bodyList.push(); - bodyList.push(); - lastOffset = offset + safeSearchTerm.length; - } - bodyList.push(); - } - else { - while ((offset = originalBody.indexOf(this.props.searchTerm, lastOffset)) >= 0) { - bodyList.push({ originalBody.substring(lastOffset, offset) }); - bodyList.push({ this.props.searchTerm }); - lastOffset = offset + this.props.searchTerm.length; - } - bodyList.push({ originalBody.substring(lastOffset) }); - } - body = bodyList; - } - else { - if (content.format === "org.matrix.custom.html") { - var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams); - body = ; - } - else { - body = originalBody; - } - } - - return ( - - { body } - - ); - }, -}); - diff --git a/src/skins/vector/views/molecules/MRoomMemberTile.js b/src/skins/vector/views/molecules/MRoomMemberTile.js deleted file mode 100644 index 0048306d..00000000 --- a/src/skins/vector/views/molecules/MRoomMemberTile.js +++ /dev/null @@ -1,52 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); - -var sdk = require('matrix-react-sdk') -var TextForEvent = require('matrix-react-sdk/lib/TextForEvent'); - -module.exports = React.createClass({ - displayName: 'MRoomMemberTile', - - getMemberEventText: function() { - return TextForEvent.textForEvent(this.props.mxEvent); - }, - - render: function() { - // XXX: for now, just cheekily borrow the css from message tile... - var timestamp = this.props.last ? : null; - var text = this.getMemberEventText(); - if (!text) return
    ; - var MessageTimestamp = sdk.getComponent('atoms.MessageTimestamp'); - var MemberAvatar = sdk.getComponent('atoms.MemberAvatar'); - return ( -
    -
    - -
    - { timestamp } - - - { text } - -
    - ); - }, -}); - diff --git a/src/skins/vector/views/molecules/MTextTile.js b/src/skins/vector/views/molecules/MTextTile.js deleted file mode 100644 index 12bafa37..00000000 --- a/src/skins/vector/views/molecules/MTextTile.js +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); -var sanitizeHtml = require('sanitize-html'); - -var MTextTileController = require('matrix-react-sdk/lib/controllers/molecules/MTextTile') - -var allowedAttributes = sanitizeHtml.defaults.allowedAttributes; -allowedAttributes['font'] = ['color']; -var sanitizeHtmlParams = { - allowedTags: sanitizeHtml.defaults.allowedTags.concat([ 'font' ]), - allowedAttributes: allowedAttributes, -}; - -module.exports = React.createClass({ - displayName: 'MTextTile', - mixins: [MTextTileController], - - // FIXME: this entire class is copy-pasted from MTextTile :( - render: function() { - var content = this.props.mxEvent.getContent(); - var originalBody = content.body; - var body; - - if (this.props.searchTerm) { - var lastOffset = 0; - var bodyList = []; - var k = 0; - var offset; - - // XXX: rather than searching for the search term in the body, - // we should be looking at the match delimiters returned by the FTS engine - if (content.format === "org.matrix.custom.html") { - var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams); - var safeSearchTerm = sanitizeHtml(this.props.searchTerm, sanitizeHtmlParams); - while ((offset = safeBody.indexOf(safeSearchTerm, lastOffset)) >= 0) { - // FIXME: we need to apply the search highlighting to only the text elements of HTML, which means - // hooking into the sanitizer parser rather than treating it as a string. Otherwise - // the act of highlighting a or whatever will break the HTML badly. - bodyList.push(); - bodyList.push(); - lastOffset = offset + safeSearchTerm.length; - } - bodyList.push(); - } - else { - while ((offset = originalBody.indexOf(this.props.searchTerm, lastOffset)) >= 0) { - bodyList.push({ originalBody.substring(lastOffset, offset) }); - bodyList.push({ this.props.searchTerm }); - lastOffset = offset + this.props.searchTerm.length; - } - bodyList.push({ originalBody.substring(lastOffset) }); - } - body = bodyList; - } - else { - if (content.format === "org.matrix.custom.html") { - var safeBody = sanitizeHtml(content.formatted_body, sanitizeHtmlParams); - body = ; - } - else { - body = originalBody; - } - } - - return ( - - { body } - - ); - }, -}); - diff --git a/src/skins/vector/views/molecules/MemberInfo.js b/src/skins/vector/views/molecules/MemberInfo.js deleted file mode 100644 index 24fa1e91..00000000 --- a/src/skins/vector/views/molecules/MemberInfo.js +++ /dev/null @@ -1,101 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); - -var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); -var sdk = require('matrix-react-sdk') -var dis = require('matrix-react-sdk/lib/dispatcher'); -var MemberInfoController = require('matrix-react-sdk/lib/controllers/molecules/MemberInfo') - -// FIXME: this should probably be an organism, to match with MemberList, not a molecule - -module.exports = React.createClass({ - displayName: 'MemberInfo', - mixins: [MemberInfoController], - - onCancel: function(e) { - dis.dispatch({ - action: "view_user", - member: null - }); - }, - - render: function() { - var interactButton, kickButton, banButton, muteButton, giveModButton, spinner; - if (this.props.member.userId === MatrixClientPeg.get().credentials.userId) { - interactButton =
    Leave room
    ; - } - else { - interactButton =
    Start chat
    ; - } - - if (this.state.creatingRoom) { - var Loader = sdk.getComponent("atoms.Spinner"); - spinner = ; - } - - if (this.state.can.kick) { - kickButton =
    - Kick -
    ; - } - if (this.state.can.ban) { - banButton =
    - Ban -
    ; - } - if (this.state.can.mute) { - var muteLabel = this.state.muted ? "Unmute" : "Mute"; - muteButton =
    - {muteLabel} -
    ; - } - if (this.state.can.modifyLevel) { - var giveOpLabel = this.state.isTargetMod ? "Revoke Mod" : "Make Mod"; - giveModButton =
    - {giveOpLabel} -
    - } - - var MemberAvatar = sdk.getComponent('atoms.MemberAvatar'); - return ( -
    - -
    - -
    -

    { this.props.member.name }

    -
    - { this.props.member.userId } -
    -
    - power: { this.props.member.powerLevelNorm }% -
    -
    - {interactButton} - {muteButton} - {kickButton} - {banButton} - {giveModButton} - {spinner} -
    -
    - ); - } -}); diff --git a/src/skins/vector/views/molecules/MemberTile.js b/src/skins/vector/views/molecules/MemberTile.js deleted file mode 100644 index 25ba3db9..00000000 --- a/src/skins/vector/views/molecules/MemberTile.js +++ /dev/null @@ -1,180 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); - -var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); -var sdk = require('matrix-react-sdk') -var dis = require('matrix-react-sdk/lib/dispatcher'); -var MemberTileController = require('matrix-react-sdk/lib/controllers/molecules/MemberTile') - -// The Lato WOFF doesn't include sensible combining diacritics, so Chrome chokes on rendering them. -// Revert to Arial when this happens, which on OSX works at least. -var zalgo = /[\u0300-\u036f\u1ab0-\u1aff\u1dc0-\u1dff\u20d0-\u20ff\ufe20-\ufe2f]/; - -module.exports = React.createClass({ - displayName: 'MemberTile', - mixins: [MemberTileController], - - shouldComponentUpdate: function(nextProps, nextState) { - if (this.state.hover !== nextState.hover) return true; - if ( - this.member_last_modified_time === undefined || - this.member_last_modified_time < nextProps.member.getLastModifiedTime() - ) { - return true - } - if ( - nextProps.member.user && - (this.user_last_modified_time === undefined || - this.user_last_modified_time < nextProps.member.user.getLastModifiedTime()) - ) { - return true - } - return false; - }, - - mouseEnter: function(e) { - this.setState({ 'hover': true }); - }, - - mouseLeave: function(e) { - this.setState({ 'hover': false }); - }, - - onClick: function(e) { - dis.dispatch({ - action: 'view_user', - member: this.props.member, - }); - }, - - getDuration: function(time) { - if (!time) return; - var t = parseInt(time / 1000); - var s = t % 60; - var m = parseInt(t / 60) % 60; - var h = parseInt(t / (60 * 60)) % 24; - var d = parseInt(t / (60 * 60 * 24)); - if (t < 60) { - if (t < 0) { - return "0s"; - } - return s + "s"; - } - if (t < 60 * 60) { - return m + "m"; - } - if (t < 24 * 60 * 60) { - return h + "h"; - } - return d + "d "; - }, - - getPrettyPresence: function(user) { - if (!user) return "Unknown"; - var presence = user.presence; - if (presence === "online") return "Online"; - if (presence === "unavailable") return "Idle"; // XXX: is this actually right? - if (presence === "offline") return "Offline"; - return "Unknown"; - }, - - getPowerLabel: function() { - var label = this.props.member.userId; - if (this.state.isTargetMod) { - label += " - Mod (" + this.props.member.powerLevelNorm + "%)"; - } - return label; - }, - - render: function() { - this.member_last_modified_time = this.props.member.getLastModifiedTime(); - if (this.props.member.user) { - this.user_last_modified_time = this.props.member.user.getLastModifiedTime(); - } - - var isMyUser = MatrixClientPeg.get().credentials.userId == this.props.member.userId; - - var power; - // if (this.props.member && this.props.member.powerLevelNorm > 0) { - // var img = "img/p/p" + Math.floor(20 * this.props.member.powerLevelNorm / 100) + ".png"; - // power = ; - // } - var presenceClass = "mx_MemberTile_offline"; - var mainClassName = "mx_MemberTile "; - if (this.props.member.user) { - if (this.props.member.user.presence === "online") { - presenceClass = "mx_MemberTile_online"; - } - else if (this.props.member.user.presence === "unavailable") { - presenceClass = "mx_MemberTile_unavailable"; - } - } - mainClassName += presenceClass; - if (this.state.hover) { - mainClassName += " mx_MemberTile_hover"; - } - - var name = this.props.member.name; - // if (isMyUser) name += " (me)"; // this does nothing other than introduce line wrapping and pain - //var leave = isMyUser ? : null; - - var nameClass = "mx_MemberTile_name"; - if (zalgo.test(name)) { - nameClass += " mx_MemberTile_zalgo"; - } - - var nameEl; - if (this.state.hover) { - var presence; - // FIXME: make presence data update whenever User.presence changes... - var active = this.props.member.user ? ((Date.now() - (this.props.member.user.lastPresenceTs - this.props.member.user.lastActiveAgo)) || -1) : -1; - if (active >= 0) { - presence =
    { this.getPrettyPresence(this.props.member.user) } { this.getDuration(active) } ago
    ; - } - else { - presence =
    { this.getPrettyPresence(this.props.member.user) }
    ; - } - - nameEl = -
    - -
    { name }
    - { presence } -
    - } - else { - nameEl = -
    - { name } -
    - } - - var MemberAvatar = sdk.getComponent('atoms.MemberAvatar'); - return ( -
    -
    - - { power } -
    - { nameEl } -
    - ); - } -}); diff --git a/src/skins/vector/views/molecules/MessageComposer.js b/src/skins/vector/views/molecules/MessageComposer.js deleted file mode 100644 index 2f0e7ac5..00000000 --- a/src/skins/vector/views/molecules/MessageComposer.js +++ /dev/null @@ -1,79 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); - -var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); -var MessageComposerController = require('matrix-react-sdk/lib/controllers/molecules/MessageComposer') - -var sdk = require('matrix-react-sdk') -var dis = require('matrix-react-sdk/lib/dispatcher') - -module.exports = React.createClass({ - displayName: 'MessageComposer', - mixins: [MessageComposerController], - - onUploadClick: function(ev) { - this.refs.uploadInput.click(); - }, - - onUploadFileSelected: function(ev) { - var files = ev.target.files; - // MessageComposer shouldn't have to rely on it's parent passing in a callback to upload a file - if (files && files.length > 0) { - this.props.uploadFile(files[0]); - } - this.refs.uploadInput.value = null; - }, - - onCallClick: function(ev) { - dis.dispatch({ - action: 'place_call', - type: ev.shiftKey ? "screensharing" : "video", - room_id: this.props.room.roomId - }); - }, - - render: function() { - var me = this.props.room.getMember(MatrixClientPeg.get().credentials.userId); - var uploadInputStyle = {display: 'none'}; - var MemberAvatar = sdk.getComponent('atoms.MemberAvatar'); - return ( -
    -
    -
    -
    - -
    -
    -
    - cancel_button =
    Cancel
    - save_button =
    Save Changes
    - } else { - // - name = -
    -
    { this.props.room.name }
    -
    - -
    -
    - if (topic) topic_el =
    { topic.getContent().topic }
    ; - } - - var roomAvatar = null; - if (this.props.room) { - roomAvatar = ( - - ); - } - - var zoom_button, video_button, voice_button; - if (activeCall) { - if (activeCall.type == "video") { - zoom_button = ( -
    - Fullscreen -
    - ); - } - video_button = -
    - Video call -
    ; - voice_button = -
    - VoIP call -
    ; - } - - header = -
    -
    -
    - { roomAvatar } -
    -
    - { name } - { topic_el } -
    -
    - {call_buttons} - {cancel_button} - {save_button} -
    - { video_button } - { voice_button } - { zoom_button } -
    - Search -
    -
    -
    - } - - return ( -
    - { header } -
    - ); - }, -}); diff --git a/src/skins/vector/views/molecules/RoomSettings.js b/src/skins/vector/views/molecules/RoomSettings.js deleted file mode 100644 index 4fdd40d9..00000000 --- a/src/skins/vector/views/molecules/RoomSettings.js +++ /dev/null @@ -1,232 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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. -*/ - -'use strict'; - -var React = require('react'); -var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); -var sdk = require('matrix-react-sdk'); - -var RoomSettingsController = require('matrix-react-sdk/lib/controllers/molecules/RoomSettings') - -module.exports = React.createClass({ - displayName: 'RoomSettings', - mixins: [RoomSettingsController], - - getTopic: function() { - return this.refs.topic.value; - }, - - getJoinRules: function() { - return this.refs.is_private.checked ? "invite" : "public"; - }, - - getHistoryVisibility: function() { - return this.refs.share_history.checked ? "shared" : "invited"; - }, - - getPowerLevels: function() { - if (!this.state.power_levels_changed) return undefined; - - var power_levels = this.props.room.currentState.getStateEvents('m.room.power_levels', ''); - power_levels = power_levels.getContent(); - - var new_power_levels = { - ban: parseInt(this.refs.ban.value), - kick: parseInt(this.refs.kick.value), - redact: parseInt(this.refs.redact.value), - invite: parseInt(this.refs.invite.value), - events_default: parseInt(this.refs.events_default.value), - state_default: parseInt(this.refs.state_default.value), - users_default: parseInt(this.refs.users_default.value), - users: power_levels.users, - events: power_levels.events, - }; - - return new_power_levels; - }, - - onPowerLevelsChanged: function() { - this.setState({ - power_levels_changed: true - }); - }, - - render: function() { - var ChangeAvatar = sdk.getComponent('molecules.ChangeAvatar'); - - var topic = this.props.room.currentState.getStateEvents('m.room.topic', ''); - if (topic) topic = topic.getContent().topic; - - var join_rule = this.props.room.currentState.getStateEvents('m.room.join_rules', ''); - if (join_rule) join_rule = join_rule.getContent().join_rule; - - var history_visibility = this.props.room.currentState.getStateEvents('m.room.history_visibility', ''); - if (history_visibility) history_visibility = history_visibility.getContent().history_visibility; - - var power_levels = this.props.room.currentState.getStateEvents('m.room.power_levels', ''); - - var events_levels = power_levels.events || {}; - - if (power_levels) { - power_levels = power_levels.getContent(); - - var ban_level = parseInt(power_levels.ban); - var kick_level = parseInt(power_levels.kick); - var redact_level = parseInt(power_levels.redact); - var invite_level = parseInt(power_levels.invite || 0); - var send_level = parseInt(power_levels.events_default || 0); - var state_level = parseInt(power_levels.state_default || 0); - var default_user_level = parseInt(power_levels.users_default || 0); - - if (power_levels.ban == undefined) ban_level = 50; - if (power_levels.kick == undefined) kick_level = 50; - if (power_levels.redact == undefined) redact_level = 50; - - var user_levels = power_levels.users || {}; - - var user_id = MatrixClientPeg.get().credentials.userId; - - var current_user_level = user_levels[user_id]; - if (current_user_level == undefined) current_user_level = default_user_level; - - var power_level_level = events_levels["m.room.power_levels"]; - if (power_level_level == undefined) { - power_level_level = state_level; - } - - var can_change_levels = current_user_level >= power_level_level; - } else { - var ban_level = 50; - var kick_level = 50; - var redact_level = 50; - var invite_level = 0; - var send_level = 0; - var state_level = 0; - var default_user_level = 0; - - var user_levels = []; - var events_levels = []; - - var current_user_level = 0; - - var power_level_level = 0; - - var can_change_levels = false; - } - - var room_avatar_level = parseInt(power_levels.state_default || 0); - if (events_levels['m.room.avatar'] !== undefined) { - room_avatar_level = events_levels['m.room.avatar']; - } - var can_set_room_avatar = current_user_level >= room_avatar_level; - - var change_avatar; - if (can_set_room_avatar) { - change_avatar =
    -

    Room Icon

    - -
    ; - } - - var banned = this.props.room.getMembersWithMembership("ban"); - - return ( -
    -