mirror of
				https://github.com/vector-im/element-web.git
				synced 2025-10-31 00:01:23 +01:00 
			
		
		
		
	Merge branch 'develop' into kegan/delete-empty-files
Conflicts: src/skins/vector/views/molecules/EventAsTextTile.js
This commit is contained in:
		
						commit
						c91b642a8b
					
				
							
								
								
									
										25
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								README.md
									
									
									
									
									
								
							| @ -22,14 +22,27 @@ into the `vector` directory and run your own server. | ||||
| 
 | ||||
| Development | ||||
| =========== | ||||
| You can work on any of the source files within Vector with the setup above, | ||||
| and your changes will cause an instant rebuild. If you also need to make | ||||
| changes to the react sdk, you can: | ||||
| 
 | ||||
| 1. Link the react sdk package into the example: | ||||
| For simple tweaks, you can work on any of the source files within Vector with the | ||||
| setup above, and your changes will cause an instant rebuild. | ||||
| 
 | ||||
| However, all serious development on Vector happens on the `develop` branch.  This typically | ||||
| depends on the `develop` snapshot versions of `matrix-react-sdk` and `matrix-js-sdk` | ||||
| too, which isn't expressed in Vector's `package.json`.  To do this, check out | ||||
| the `develop` branches of these libraries and then use `npm link` to tell Vector | ||||
| about them: | ||||
| 
 | ||||
| 1. `git clone git@github.com:matrix-org/matrix-react-sdk.git` | ||||
| 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: | ||||
|    `npm link path/to/your/react/sdk` | ||||
| 2. Start the development rebuilder in your react SDK directory: | ||||
|    `npm start` | ||||
| 
 | ||||
| Similarly, you may need to `npm link path/to/your/js/sdk` in your `matrix-react-sdk` | ||||
| directory. | ||||
| 
 | ||||
| If you add or remove any components from the Vector skin, you will need to rebuild | ||||
| the skin's index by running, `npm run reskindex`. | ||||
|  | ||||
| @ -49,15 +49,25 @@ module.exports = { | ||||
| 
 | ||||
|         var position = { | ||||
|             top: props.top - 20, | ||||
|             right: props.right + 8, | ||||
|         }; | ||||
| 
 | ||||
|         var chevron = null; | ||||
|         if (props.left) { | ||||
|             chevron = <img className="mx_ContextualMenu_chevron_left" src="img/chevron-left.png" width="9" height="16" /> | ||||
|             position.left = props.left + 8; | ||||
|         } else { | ||||
|             chevron = <img className="mx_ContextualMenu_chevron_right" src="img/chevron-right.png" width="9" height="16" /> | ||||
|             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 = ( | ||||
|             <div className="mx_ContextualMenu_wrapper"> | ||||
|             <div className={className}> | ||||
|                 <div className="mx_ContextualMenu" style={position}> | ||||
|                     <img className="mx_ContextualMenu_chevron" src="img/chevron-right.png" width="9" height="16" /> | ||||
|                     {chevron} | ||||
|                     <Element {...props} onFinished={closeMenu}/> | ||||
|                 </div> | ||||
|                 <div className="mx_ContextualMenu_background" onClick={closeMenu}></div> | ||||
|  | ||||
| @ -33,6 +33,7 @@ module.exports = { | ||||
|         cli.on("Room", this.onRoom); | ||||
|         cli.on("Room.timeline", this.onRoomTimeline); | ||||
|         cli.on("Room.name", this.onRoomName); | ||||
|         cli.on("RoomState.events", this.onRoomStateEvents); | ||||
| 
 | ||||
|         var rooms = this.getRoomList(); | ||||
|         this.setState({ | ||||
| @ -66,6 +67,7 @@ module.exports = { | ||||
|             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); | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
| @ -110,6 +112,11 @@ module.exports = { | ||||
|         this.refreshRoomList(); | ||||
|     }, | ||||
| 
 | ||||
|     onRoomStateEvents: function(ev, state) { | ||||
|         setTimeout(this.refreshRoomList, 0); | ||||
|     }, | ||||
| 
 | ||||
| 
 | ||||
|     refreshRoomList: function() { | ||||
|         var rooms = this.getRoomList(); | ||||
|         this.setState({ | ||||
|  | ||||
| @ -63,6 +63,7 @@ module.exports = { | ||||
|             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); | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
| @ -356,23 +357,20 @@ module.exports = { | ||||
|     }, | ||||
| 
 | ||||
|     getEventTiles: function() { | ||||
|         var tileTypes = { | ||||
|             'm.room.message': sdk.getComponent('molecules.MessageTile'), | ||||
|             'm.room.member' : sdk.getComponent('molecules.EventAsTextTile'), | ||||
|             'm.call.invite' : sdk.getComponent('molecules.EventAsTextTile'), | ||||
|             'm.call.answer' : sdk.getComponent('molecules.EventAsTextTile'), | ||||
|             'm.call.hangup' : sdk.getComponent('molecules.EventAsTextTile'), | ||||
|             'm.room.topic'  : sdk.getComponent('molecules.EventAsTextTile'), | ||||
|         }; | ||||
| 
 | ||||
|         var DateSeparator = sdk.getComponent('molecules.DateSeparator'); | ||||
| 
 | ||||
|         var ret = []; | ||||
|         var count = 0; | ||||
| 
 | ||||
|         var EventTile = sdk.getComponent('molecules.EventTile'); | ||||
| 
 | ||||
|         for (var i = this.state.room.timeline.length-1; i >= 0 && count < this.state.messageCap; --i) { | ||||
|             var mxEv = this.state.room.timeline[i]; | ||||
|             var TileType = tileTypes[mxEv.getType()]; | ||||
| 
 | ||||
|             if (!EventTile.supportsEventType(mxEv.getType())) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             var continuation = false; | ||||
|             var last = false; | ||||
|             var dateSeparator = null; | ||||
| @ -401,13 +399,12 @@ module.exports = { | ||||
| 
 | ||||
|             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 = <DateSeparator key={ts1} ts={ts1}/>; | ||||
|                 dateSeparator = <li key={ts1}><DateSeparator ts={ts1}/></li>; | ||||
|                 continuation = false; | ||||
|             } | ||||
| 
 | ||||
|             if (!TileType) continue; | ||||
|             ret.unshift( | ||||
|                 <li key={mxEv.getId()}><TileType mxEvent={mxEv} continuation={continuation} last={last}/></li> | ||||
|                 <li key={mxEv.getId()}><EventTile mxEvent={mxEv} continuation={continuation} last={last}/></li> | ||||
|             ); | ||||
|             if (dateSeparator) { | ||||
|                 ret.unshift(dateSeparator); | ||||
|  | ||||
| @ -67,13 +67,20 @@ a:visited { | ||||
|     padding: 6px; | ||||
| } | ||||
| 
 | ||||
| .mx_ContextualMenu_chevron { | ||||
| .mx_ContextualMenu_chevron_right { | ||||
|     padding: 12px; | ||||
|     position: absolute; | ||||
|     right: -21px; | ||||
|     top: 0px; | ||||
| } | ||||
| 
 | ||||
| .mx_ContextualMenu_chevron_left { | ||||
|     padding: 12px; | ||||
|     position: absolute; | ||||
|     left: -21px; | ||||
|     top: 0px; | ||||
| } | ||||
| 
 | ||||
| .mx_ContextualMenu_field { | ||||
|     padding: 3px 6px 3px 6px; | ||||
|     cursor: pointer; | ||||
|  | ||||
| @ -14,14 +14,14 @@ See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| .mx_MessageTile { | ||||
| .mx_EventTile { | ||||
|     max-width: 100%; | ||||
|     clear: both; | ||||
|     margin-top: 32px; | ||||
|     margin-left: 56px; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile_avatar { | ||||
| .mx_EventTile_avatar { | ||||
|     padding-left: 12px; | ||||
|     padding-right: 12px; | ||||
|     margin-left: -64px; | ||||
| @ -29,17 +29,17 @@ limitations under the License. | ||||
|     float: left; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile_avatar img { | ||||
| .mx_EventTile_avatar img { | ||||
|     background-color: #dbdbdb; | ||||
|     border-radius: 20px; | ||||
|     border: 0px; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile_continuation { | ||||
| .mx_EventTile_continuation { | ||||
|     margin-top: 8px ! important; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile .mx_SenderProfile { | ||||
| .mx_EventTile .mx_SenderProfile { | ||||
|     color: #454545; | ||||
|     opacity: 0.5; | ||||
|     font-size: 14px; | ||||
| @ -47,35 +47,35 @@ limitations under the License. | ||||
|     display: block; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile .mx_MessageTimestamp { | ||||
| .mx_EventTile .mx_MessageTimestamp { | ||||
|     color: #454545; | ||||
|     opacity: 0.5; | ||||
|     font-size: 14px; | ||||
|     float: right; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile_content { | ||||
| .mx_EventTile_content { | ||||
|     padding-right: 100px; | ||||
|     display: block; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile_notice .mx_MessageTile_content { | ||||
| .mx_EventTile_notice .mx_MessageTile_content { | ||||
|     opacity: 0.5; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile_sending { | ||||
| .mx_EventTile_sending { | ||||
|     color: #ddd; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile_notSent { | ||||
| .mx_EventTile_notSent { | ||||
|     color: #f11; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile_highlight { | ||||
| .mx_EventTile_highlight { | ||||
|     color: #FF0064; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile_msgOption { | ||||
| .mx_EventTile_msgOption { | ||||
|     float: right; | ||||
| } | ||||
| 
 | ||||
| @ -83,29 +83,30 @@ limitations under the License. | ||||
|     display: none; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile_last .mx_MessageTimestamp { | ||||
| .mx_EventTile_last .mx_MessageTimestamp { | ||||
|     display: block; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile:hover .mx_MessageTimestamp { | ||||
| .mx_EventTile:hover .mx_MessageTimestamp { | ||||
|     display: block; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile_editButton { | ||||
| .mx_EventTile_editButton { | ||||
|     float: right; | ||||
|     display: none; | ||||
|     border: 0px; | ||||
|     outline: none; | ||||
|     margin-right: 3px; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile:hover .mx_MessageTile_editButton { | ||||
| .mx_EventTile:hover .mx_EventTile_editButton { | ||||
|     display: inline-block; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile.menu .mx_MessageTile_editButton { | ||||
| .mx_EventTile.menu .mx_EventTile_editButton { | ||||
|     display: inline-block; | ||||
| } | ||||
| 
 | ||||
| .mx_MessageTile.menu .mx_MessageTimestamp { | ||||
| .mx_EventTile.menu .mx_MessageTimestamp { | ||||
|     display: inline-block; | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								src/skins/vector/img/50e2c2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/skins/vector/img/50e2c2.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 146 B | 
							
								
								
									
										
											BIN
										
									
								
								src/skins/vector/img/80cef4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/skins/vector/img/80cef4.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 146 B | 
							
								
								
									
										
											BIN
										
									
								
								src/skins/vector/img/f4c371.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/skins/vector/img/f4c371.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 146 B | 
| @ -41,6 +41,7 @@ skin['molecules.ChangeDisplayName'] = require('./views/molecules/ChangeDisplayNa | ||||
| 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.MatrixToolbar'] = require('./views/molecules/MatrixToolbar'); | ||||
| skin['molecules.MemberInfo'] = require('./views/molecules/MemberInfo'); | ||||
| skin['molecules.MemberTile'] = require('./views/molecules/MemberTile'); | ||||
|  | ||||
| @ -42,7 +42,7 @@ module.exports = React.createClass({ | ||||
|             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()); | ||||
|             return days[date.getDay()] + ", " + months[date.getMonth()] + " " + (date.getDay()+1) + " " + date.getFullYear() + " " + pad(date.getHours()) + ':' + pad(date.getMinutes()); | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
|  | ||||
| @ -17,6 +17,7 @@ limitations under the License. | ||||
| 'use strict'; | ||||
| 
 | ||||
| var React = require('react'); | ||||
| var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); | ||||
| 
 | ||||
| var RoomAvatarController = require('matrix-react-sdk/lib/controllers/atoms/RoomAvatar') | ||||
| 
 | ||||
| @ -24,10 +25,31 @@ module.exports = React.createClass({ | ||||
|     displayName: 'RoomAvatar', | ||||
|     mixins: [RoomAvatarController], | ||||
| 
 | ||||
|     getUrlList: function() { | ||||
|         return [ | ||||
|             this.roomAvatarUrl(), | ||||
|             this.getOneToOneAvatar(), | ||||
|             this.getFallbackAvatar() | ||||
|         ]; | ||||
|     }, | ||||
| 
 | ||||
|     getFallbackAvatar: function() { | ||||
|         var images = [ '80cef4', '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 = { | ||||
|             maxWidth: this.props.width, | ||||
|             maxHeight: this.props.height, | ||||
|         }; | ||||
|         return ( | ||||
|             <img className="mx_RoomAvatar" src={this.state.imageUrl} onError={this.onError} | ||||
|                 width={this.props.width} height={this.props.height} | ||||
|                 style={style} | ||||
|             /> | ||||
|         ); | ||||
|     } | ||||
|  | ||||
| @ -18,6 +18,7 @@ limitations under the License. | ||||
| 
 | ||||
| var React = require('react'); | ||||
| 
 | ||||
| var sdk = require('matrix-react-sdk') | ||||
| var ChangeAvatarController = require('matrix-react-sdk/lib/controllers/molecules/ChangeAvatar') | ||||
| 
 | ||||
| var Loader = require("react-loader"); | ||||
| @ -28,6 +29,7 @@ module.exports = React.createClass({ | ||||
|     mixins: [ChangeAvatarController], | ||||
| 
 | ||||
|     onFileSelected: function(ev) { | ||||
|         this.avatarSet = true; | ||||
|         this.setAvatarFromFile(ev.target.files[0]); | ||||
|     }, | ||||
| 
 | ||||
| @ -38,13 +40,27 @@ module.exports = React.createClass({ | ||||
|     }, | ||||
| 
 | ||||
|     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 = <RoomAvatar room={this.props.room} width='320' height='240' resizeMethod='scale' />; | ||||
|         } else { | ||||
|             var style = { | ||||
|                 maxWidth: 320, | ||||
|                 maxHeight: 240, | ||||
|             }; | ||||
|             avatarImg = <img src={this.state.avatarUrl} style={style} />; | ||||
|         } | ||||
| 
 | ||||
|         switch (this.state.phase) { | ||||
|             case this.Phases.Display: | ||||
|             case this.Phases.Error: | ||||
|                 return ( | ||||
|                     <div> | ||||
|                         <div className="mx_Dialog_content"> | ||||
|                             <img src={this.state.avatarUrl}/> | ||||
|                             {avatarImg} | ||||
|                         </div> | ||||
|                         <div className="mx_Dialog_content"> | ||||
|                             Upload new: | ||||
|  | ||||
| @ -24,25 +24,19 @@ var TextForEvent = require('matrix-react-sdk/lib/TextForEvent'); | ||||
| module.exports = React.createClass({ | ||||
|     displayName: 'EventAsTextTile', | ||||
| 
 | ||||
|     render: function() { | ||||
|         var MessageTimestamp = sdk.getComponent('atoms.MessageTimestamp'); | ||||
|         var MemberAvatar = sdk.getComponent('atoms.MemberAvatar'); | ||||
|     statics: { | ||||
|         needsSenderProfile: function() { | ||||
|             return false; | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
|     render: function() { | ||||
|         var text = TextForEvent.textForEvent(this.props.mxEvent); | ||||
|         if (text == null || text.length == 0) return null; | ||||
| 
 | ||||
|         var timestamp = this.props.last ? <MessageTimestamp ts={this.props.mxEvent.getTs()} /> : null; | ||||
|         var avatar = this.props.mxEvent.sender ? <MemberAvatar member={this.props.mxEvent.sender} /> : null; | ||||
|         return ( | ||||
|             <div className="mx_MessageTile mx_MessageTile_notice"> | ||||
|                 <div className="mx_MessageTile_avatar"> | ||||
|                     { avatar } | ||||
|                 </div>             | ||||
|                 { timestamp } | ||||
|                 <span className="mx_SenderProfile"></span> | ||||
|                 <span className="mx_MessageTile_content"> | ||||
|                     {TextForEvent.textForEvent(this.props.mxEvent)} | ||||
|                 </span> | ||||
|             <div className="mx_EventAsTextTile"> | ||||
|                 {TextForEvent.textForEvent(this.props.mxEvent)} | ||||
|             </div> | ||||
|         ); | ||||
|     }, | ||||
|  | ||||
							
								
								
									
										133
									
								
								src/skins/vector/views/molecules/EventTile.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								src/skins/vector/views/molecules/EventTile.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,133 @@ | ||||
| /* | ||||
| 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 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.topic'  : 'molecules.EventAsTextTile', | ||||
| }; | ||||
| 
 | ||||
| module.exports = React.createClass({ | ||||
|     displayName: 'EventTile', | ||||
|     mixins: [EventTileController], | ||||
| 
 | ||||
|     statics: { | ||||
|         supportsEventType: function(et) { | ||||
|             return eventTileTypes[et] !== undefined; | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
|     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 UnknownMessageTile = sdk.getComponent('molecules.UnknownMessageTile'); | ||||
| 
 | ||||
|         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) { | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         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, | ||||
|             menu: this.state.menu | ||||
|         }); | ||||
|         var timestamp = <MessageTimestamp ts={this.props.mxEvent.getTs()} /> | ||||
|         var editButton = ( | ||||
|             <input | ||||
|                 type="image" src="img/edit.png" alt="Edit" | ||||
|                 className="mx_EventTile_editButton" onClick={this.onEditClicked} | ||||
|             /> | ||||
|         ); | ||||
| 
 | ||||
|         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 = ( | ||||
|                     <div className="mx_EventTile_avatar"> | ||||
|                         <MemberAvatar member={this.props.mxEvent.sender} /> | ||||
|                     </div> | ||||
|                 ); | ||||
|             } | ||||
|             if (EventTileType.needsSenderProfile()) { | ||||
|                 sender = <SenderProfile mxEvent={this.props.mxEvent} aux={aux} />; | ||||
|             } | ||||
|         } | ||||
|         return ( | ||||
|             <div className={classes}> | ||||
|                 { avatar } | ||||
|                 { sender } | ||||
|                 <div> | ||||
|                     { timestamp } | ||||
|                     { editButton } | ||||
|                     <EventTileType mxEvent={this.props.mxEvent} /> | ||||
|                 </div> | ||||
|             </div> | ||||
|         ); | ||||
|     }, | ||||
| }); | ||||
| @ -52,9 +52,27 @@ module.exports = React.createClass({ | ||||
|         if (this.props.onFinished) this.props.onFinished(); | ||||
|     }, | ||||
| 
 | ||||
|     onRedactClick: function() { | ||||
|         MatrixClientPeg.get().redactEvent( | ||||
|             this.props.mxEvent.getRoomId(), this.props.mxEvent.getId() | ||||
|         ).done(function() { | ||||
|             // message should disappear by itself
 | ||||
|         }, function(e) { | ||||
|             var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); | ||||
|             // display error message stating you couldn't delete this.
 | ||||
|             var code = e.errcode || e.statusCode; | ||||
|             Modal.createDialog(ErrorDialog, { | ||||
|                 title: "Error", | ||||
|                 description: "You cannot delete this message. (" + code + ")" | ||||
|             }); | ||||
|         }); | ||||
|         if (this.props.onFinished) this.props.onFinished(); | ||||
|     }, | ||||
| 
 | ||||
|     render: function() { | ||||
|         var resendButton; | ||||
|         var viewSourceButton; | ||||
|         var redactButton; | ||||
| 
 | ||||
|         if (this.props.mxEvent.status == 'not_sent') { | ||||
|             resendButton = ( | ||||
| @ -63,6 +81,13 @@ module.exports = React.createClass({ | ||||
|                 </div> | ||||
|             ); | ||||
|         } | ||||
|         else { | ||||
|             redactButton = ( | ||||
|                 <div className="mx_ContextualMenu_field" onClick={this.onRedactClick}> | ||||
|                     Delete | ||||
|                 </div> | ||||
|             ); | ||||
|         } | ||||
|         viewSourceButton = ( | ||||
|             <div className="mx_ContextualMenu_field" onClick={this.onViewSourceClick}> | ||||
|                 View Source | ||||
| @ -72,6 +97,7 @@ module.exports = React.createClass({ | ||||
|         return ( | ||||
|             <div> | ||||
|                 {resendButton} | ||||
|                 {redactButton} | ||||
|                 {viewSourceButton} | ||||
|             </div> | ||||
|         ); | ||||
|  | ||||
| @ -28,28 +28,13 @@ module.exports = React.createClass({ | ||||
|     displayName: 'MessageTile', | ||||
|     mixins: [MessageTileController], | ||||
| 
 | ||||
|     onEditClicked: function(e) { | ||||
|         var MessageContextMenu = sdk.getComponent('molecules.MessageContextMenu'); | ||||
|         var buttonRect = e.target.getBoundingClientRect() | ||||
|         var x = window.innerWidth - buttonRect.left; | ||||
|         var y = buttonRect.top + (e.target.height / 2); | ||||
|         var self = this; | ||||
|         ContextualMenu.createMenu(MessageContextMenu, { | ||||
|             mxEvent: this.props.mxEvent, | ||||
|             right: x, | ||||
|             top: y, | ||||
|             onFinished: function() { | ||||
|                 self.setState({menu: false}); | ||||
|             } | ||||
|         }); | ||||
|         this.setState({menu: true}); | ||||
|     statics: { | ||||
|         needsSenderProfile: function() { | ||||
|             return true; | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
|     render: function() { | ||||
|         var MessageTimestamp = sdk.getComponent('atoms.MessageTimestamp'); | ||||
|         var SenderProfile = sdk.getComponent('molecules.SenderProfile'); | ||||
|         var MemberAvatar = sdk.getComponent('atoms.MemberAvatar'); | ||||
| 
 | ||||
|         var UnknownMessageTile = sdk.getComponent('molecules.UnknownMessageTile'); | ||||
| 
 | ||||
|         var tileTypes = { | ||||
| @ -66,56 +51,7 @@ module.exports = React.createClass({ | ||||
|         if (msgtype && tileTypes[msgtype]) { | ||||
|             TileType = tileTypes[msgtype]; | ||||
|         } | ||||
|         var classes = classNames({ | ||||
|             mx_MessageTile: true, | ||||
|             mx_MessageTile_sending: ['sending', 'queued'].indexOf( | ||||
|                 this.props.mxEvent.status | ||||
|             ) !== -1, | ||||
|             mx_MessageTile_notSent: this.props.mxEvent.status == 'not_sent', | ||||
|             mx_MessageTile_highlight: this.shouldHighlight(), | ||||
|             mx_MessageTile_continuation: this.props.continuation, | ||||
|             mx_MessageTile_last: this.props.last, | ||||
|             menu: this.state.menu | ||||
|         }); | ||||
|         var timestamp = <MessageTimestamp ts={this.props.mxEvent.getTs()} /> | ||||
|         var editButton = ( | ||||
|             <input | ||||
|                 type="image" src="img/edit.png" alt="Edit" | ||||
|                 className="mx_MessageTile_editButton" onClick={this.onEditClicked} | ||||
|             /> | ||||
|         ); | ||||
| 
 | ||||
|         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, resend; | ||||
|         if (!this.props.continuation) { | ||||
|             if (this.props.mxEvent.sender) { | ||||
|                 avatar = ( | ||||
|                     <div className="mx_MessageTile_avatar"> | ||||
|                         <MemberAvatar member={this.props.mxEvent.sender} /> | ||||
|                     </div> | ||||
|                 ); | ||||
|             } | ||||
|             sender = <SenderProfile mxEvent={this.props.mxEvent} aux={aux} />; | ||||
|         } | ||||
|         if (this.props.mxEvent.status === "not_sent" && !this.state.resending) { | ||||
|             resend = <button className="mx_MessageTile_msgOption" onClick={this.onResend}> | ||||
|                 Resend | ||||
|             </button>; | ||||
|         } | ||||
|         return ( | ||||
|             <div className={classes}> | ||||
|                 { avatar } | ||||
|                 { sender } | ||||
|                 <div> | ||||
|                     { timestamp } | ||||
|                     { editButton } | ||||
|                     <TileType mxEvent={this.props.mxEvent} /> | ||||
|                 </div> | ||||
|             </div> | ||||
|         ); | ||||
|         return <TileType mxEvent={this.props.mxEvent} />; | ||||
|     }, | ||||
| }); | ||||
|  | ||||
| @ -18,6 +18,7 @@ limitations under the License. | ||||
| 
 | ||||
| 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') | ||||
| 
 | ||||
| @ -65,6 +66,8 @@ module.exports = React.createClass({ | ||||
|     }, | ||||
| 
 | ||||
|     render: function() { | ||||
|         var ChangeAvatar = sdk.getComponent('molecules.ChangeAvatar'); | ||||
| 
 | ||||
|         var topic = this.props.room.currentState.getStateEvents('m.room.topic', ''); | ||||
|         if (topic) topic = topic.getContent().topic; | ||||
| 
 | ||||
| @ -76,6 +79,8 @@ module.exports = React.createClass({ | ||||
| 
 | ||||
|         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(); | ||||
| 
 | ||||
| @ -91,8 +96,7 @@ module.exports = React.createClass({ | ||||
|             if (power_levels.kick == undefined) kick_level = 50; | ||||
|             if (power_levels.redact == undefined) redact_level = 50; | ||||
| 
 | ||||
|             var user_levels = power_levels.users || []; | ||||
|             var events_levels = power_levels.events || []; | ||||
|             var user_levels = power_levels.users || {}; | ||||
| 
 | ||||
|             var user_id = MatrixClientPeg.get().credentials.userId; | ||||
| 
 | ||||
| @ -124,7 +128,21 @@ module.exports = React.createClass({ | ||||
|             var can_change_levels = false; | ||||
|         } | ||||
| 
 | ||||
|         var banned = this.props.room.getMembersWithMemership("ban"); | ||||
|         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 = <div> | ||||
|                 <h3>Room Icon</h3> | ||||
|                 <ChangeAvatar room={this.props.room} /> | ||||
|             </div>; | ||||
|         } | ||||
| 
 | ||||
|         var banned = this.props.room.getMembersWithMembership("ban"); | ||||
| 
 | ||||
|         return ( | ||||
|             <div className="mx_RoomSettings"> | ||||
| @ -207,6 +225,7 @@ module.exports = React.createClass({ | ||||
|                         ); | ||||
|                     })} | ||||
|                 </div> | ||||
|                 {change_avatar} | ||||
|             </div> | ||||
|         ); | ||||
|     } | ||||
|  | ||||
| @ -58,15 +58,16 @@ var NotifierView = { | ||||
|             if (ev.getContent().body) msg = ev.getContent().body; | ||||
|         } | ||||
| 
 | ||||
|         var avatarUrl = Avatar.avatarUrlForMember( | ||||
|         var avatarUrl = ev.sender ? Avatar.avatarUrlForMember( | ||||
|             ev.sender, 40, 40, 'crop' | ||||
|         ); | ||||
|         ) : null; | ||||
| 
 | ||||
|         var notification = new global.Notification( | ||||
|             title, | ||||
|             { | ||||
|                 "body": msg, | ||||
|                 "icon": avatarUrl | ||||
|                 "icon": avatarUrl, | ||||
|                 "tag": "vector" | ||||
|             } | ||||
|         ); | ||||
| 
 | ||||
|  | ||||
| @ -149,6 +149,11 @@ module.exports = React.createClass({ | ||||
|                 var innerProgressStyle = { | ||||
|                     width: ((this.state.upload.uploadedBytes / this.state.upload.totalBytes) * 100) + '%' | ||||
|                 }; | ||||
|                 var uploadedSize = filesize(this.state.upload.uploadedBytes); | ||||
|                 var totalSize = filesize(this.state.upload.totalBytes); | ||||
|                 if (uploadedSize.replace(/^.* /,'') === totalSize.replace(/^.* /,'')) { | ||||
|                     uploadedSize = uploadedSize.replace(/ .*/, ''); | ||||
|                 } | ||||
|                 statusBar = ( | ||||
|                     <div className="mx_RoomView_uploadBar"> | ||||
|                         <div className="mx_RoomView_uploadProgressOuter"> | ||||
| @ -157,7 +162,7 @@ module.exports = React.createClass({ | ||||
|                         <img className="mx_RoomView_uploadIcon" src="img/fileicon.png" width="40" height="40"/> | ||||
|                         <img className="mx_RoomView_uploadCancel" src="img/cancel.png" width="40" height="40"/> | ||||
|                         <div className="mx_RoomView_uploadBytes"> | ||||
|                             {filesize(this.state.upload.uploadedBytes).replace(/ .*/, '')} / {filesize(this.state.upload.totalBytes)} | ||||
|                             { uploadedSize } / { totalSize } | ||||
|                         </div> | ||||
|                         <div className="mx_RoomView_uploadFilename">Uploading {this.state.upload.fileName}</div> | ||||
|                     </div> | ||||
|  | ||||
| @ -26,7 +26,6 @@ var Loader = require("react-loader"); | ||||
| 
 | ||||
| var dis = require('matrix-react-sdk/lib/dispatcher'); | ||||
| 
 | ||||
| 
 | ||||
| module.exports = React.createClass({ | ||||
|     displayName: 'MatrixChat', | ||||
|     mixins: [MatrixChatController], | ||||
| @ -40,6 +39,23 @@ module.exports = React.createClass({ | ||||
|     componentDidMount: function() { | ||||
|         window.addEventListener('resize', this.handleResize); | ||||
|         this.handleResize(); | ||||
| 
 | ||||
|         matrixLinkify.onUserClick = function(e, userId) { | ||||
|             // this can really go anywhere..
 | ||||
|             // sprout a MemberInfo context menu.
 | ||||
|             console.log("Context => %s => %s", userId, e.target); | ||||
| 
 | ||||
|             var MemberInfo = sdk.getComponent('molecules.MemberInfo'); | ||||
|             var member = new RoomMember(null, href); | ||||
|             ContextualMenu.createMenu(MemberInfo, { | ||||
|                 member: member, | ||||
|                 right: window.innerWidth - e.pageX, | ||||
|                 top: e.pageY, | ||||
|                 onFinished: function() { | ||||
|                     console.log("^_^ All done!"); | ||||
|                 } | ||||
|             }); | ||||
|         }; | ||||
|     }, | ||||
| 
 | ||||
|     componentWillUnmount: function() { | ||||
|  | ||||
| @ -25,10 +25,9 @@ var Loader = require("react-loader"); | ||||
| 
 | ||||
| var RegisterController = require('../../../../controllers/templates/Register') | ||||
| 
 | ||||
| module.exports = React.createClass({ | ||||
|     DEFAULT_HS_URL: 'https://matrix.org', | ||||
|     DEFAULT_IS_URL: 'https://vector.im', | ||||
| var config = require('../../../../../config.json'); | ||||
| 
 | ||||
| module.exports = React.createClass({ | ||||
|     displayName: 'Register', | ||||
|     mixins: [RegisterController], | ||||
| 
 | ||||
| @ -39,8 +38,8 @@ module.exports = React.createClass({ | ||||
|     }, | ||||
| 
 | ||||
|     componentWillMount: function() { | ||||
|         this.customHsUrl = this.DEFAULT_HS_URL; | ||||
|         this.customIsUrl = this.DEFAULT_IS_URL; | ||||
|         this.customHsUrl = config.default_hs_url; | ||||
|         this.customIsUrl = config.default_is_url; | ||||
|     }, | ||||
| 
 | ||||
|     getRegFormVals: function() { | ||||
| @ -56,7 +55,7 @@ module.exports = React.createClass({ | ||||
|         if (this.state.serverConfigVisible) { | ||||
|             return this.customHsUrl; | ||||
|         } else { | ||||
|             return this.DEFAULT_HS_URL; | ||||
|             return config.default_hs_url; | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
| @ -64,7 +63,7 @@ module.exports = React.createClass({ | ||||
|         if (this.state.serverConfigVisible) { | ||||
|             return this.customIsUrl; | ||||
|         } else { | ||||
|             return this.DEFAULT_IS_URL; | ||||
|             return config.default_is_url; | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
| @ -173,6 +172,12 @@ module.exports = React.createClass({ | ||||
|                 case this.FieldErrors.InUse: | ||||
|                     strings.push(keys[i]+" is already taken"); | ||||
|                     break; | ||||
|                 case this.FieldErrors.Length: | ||||
|                     strings.push(keys[i] + " is not long enough."); | ||||
|                     break; | ||||
|                 default: | ||||
|                     console.error("Unhandled FieldError: %s", bad[keys[i]]); | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|         var errtxt = strings.join(', '); | ||||
|  | ||||
| @ -20,7 +20,8 @@ module.exports = { | ||||
|             // removed which gives a tree with matrix-react-sdk and vector
 | ||||
|             // trees smashed together, but this fixes everything being under
 | ||||
|             // various levels of '.' and '..'
 | ||||
|             return info.resourcePath.replace(/^[\/\.]*/, ''); | ||||
|             // Also, sometimes the resource path is absolute.
 | ||||
|             return path.relative(process.cwd(), info.resourcePath).replace(/^[\/\.]*/, ''); | ||||
|         } | ||||
|     }, | ||||
|     resolve: { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user