Merge pull request #356 from matrix-org/matthew/disable-url-previews
Support for disabling/enabling URL previews per-user, per-room and per-user-per-room
This commit is contained in:
commit
fb964be072
13 changed files with 365 additions and 24 deletions
|
@ -186,7 +186,7 @@ module.exports = {
|
||||||
*
|
*
|
||||||
* highlights: optional list of words to highlight, ordered by longest word first
|
* highlights: optional list of words to highlight, ordered by longest word first
|
||||||
*
|
*
|
||||||
* opts.highlightLink: optional href to add to highlights
|
* opts.highlightLink: optional href to add to highlighted words
|
||||||
*/
|
*/
|
||||||
bodyToHtml: function(content, highlights, opts) {
|
bodyToHtml: function(content, highlights, opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
|
@ -113,6 +113,35 @@ module.exports = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getUrlPreviewsDisabled: function() {
|
||||||
|
var event = MatrixClientPeg.get().getAccountData("org.matrix.preview_urls");
|
||||||
|
return (event && event.getContent().disable);
|
||||||
|
},
|
||||||
|
|
||||||
|
setUrlPreviewsDisabled: function(disabled) {
|
||||||
|
// FIXME: handle errors
|
||||||
|
MatrixClientPeg.get().setAccountData("org.matrix.preview_urls", {
|
||||||
|
disable: disabled
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getSyncedSettings: function() {
|
||||||
|
var event = MatrixClientPeg.get().getAccountData("im.vector.web.settings");
|
||||||
|
return event ? event.getContent() : {};
|
||||||
|
},
|
||||||
|
|
||||||
|
getSyncedSetting: function(type) {
|
||||||
|
var settings = this.getSyncedSettings();
|
||||||
|
return settings[type];
|
||||||
|
},
|
||||||
|
|
||||||
|
setSyncedSetting: function(type, value) {
|
||||||
|
var settings = this.getSyncedSettings();
|
||||||
|
settings[type] = value;
|
||||||
|
// FIXME: handle errors
|
||||||
|
MatrixClientPeg.get().setAccountData("im.vector.web.settings", settings);
|
||||||
|
},
|
||||||
|
|
||||||
isFeatureEnabled: function(feature: string): boolean {
|
isFeatureEnabled: function(feature: string): boolean {
|
||||||
return localStorage.getItem(`mx_labs_feature_${feature}`) === 'true';
|
return localStorage.getItem(`mx_labs_feature_${feature}`) === 'true';
|
||||||
},
|
},
|
||||||
|
|
|
@ -74,6 +74,8 @@ module.exports.components['views.messages.TextualEvent'] = require('./components
|
||||||
module.exports.components['views.messages.UnknownBody'] = require('./components/views/messages/UnknownBody');
|
module.exports.components['views.messages.UnknownBody'] = require('./components/views/messages/UnknownBody');
|
||||||
module.exports.components['views.room_settings.AliasSettings'] = require('./components/views/room_settings/AliasSettings');
|
module.exports.components['views.room_settings.AliasSettings'] = require('./components/views/room_settings/AliasSettings');
|
||||||
module.exports.components['views.room_settings.ColorSettings'] = require('./components/views/room_settings/ColorSettings');
|
module.exports.components['views.room_settings.ColorSettings'] = require('./components/views/room_settings/ColorSettings');
|
||||||
|
module.exports.components['views.room_settings.UrlPreviewSettings'] = require('./components/views/room_settings/UrlPreviewSettings');
|
||||||
|
module.exports.components['views.rooms.Autocomplete'] = require('./components/views/rooms/Autocomplete');
|
||||||
module.exports.components['views.rooms.AuxPanel'] = require('./components/views/rooms/AuxPanel');
|
module.exports.components['views.rooms.AuxPanel'] = require('./components/views/rooms/AuxPanel');
|
||||||
module.exports.components['views.rooms.EntityTile'] = require('./components/views/rooms/EntityTile');
|
module.exports.components['views.rooms.EntityTile'] = require('./components/views/rooms/EntityTile');
|
||||||
module.exports.components['views.rooms.EventTile'] = require('./components/views/rooms/EventTile');
|
module.exports.components['views.rooms.EventTile'] = require('./components/views/rooms/EventTile');
|
||||||
|
|
|
@ -44,6 +44,9 @@ module.exports = React.createClass({
|
||||||
// ID of an event to highlight. If undefined, no event will be highlighted.
|
// ID of an event to highlight. If undefined, no event will be highlighted.
|
||||||
highlightedEventId: React.PropTypes.string,
|
highlightedEventId: React.PropTypes.string,
|
||||||
|
|
||||||
|
// Should we show URL Previews
|
||||||
|
showUrlPreview: React.PropTypes.bool,
|
||||||
|
|
||||||
// event after which we should show a read marker
|
// event after which we should show a read marker
|
||||||
readMarkerEventId: React.PropTypes.string,
|
readMarkerEventId: React.PropTypes.string,
|
||||||
|
|
||||||
|
@ -365,6 +368,7 @@ module.exports = React.createClass({
|
||||||
onWidgetLoad={this._onWidgetLoad}
|
onWidgetLoad={this._onWidgetLoad}
|
||||||
readReceipts={readReceipts}
|
readReceipts={readReceipts}
|
||||||
readReceiptMap={this._readReceiptMap}
|
readReceiptMap={this._readReceiptMap}
|
||||||
|
showUrlPreview={this.props.showUrlPreview}
|
||||||
checkUnmounting={this._isUnmounting}
|
checkUnmounting={this._isUnmounting}
|
||||||
eventSendStatus={mxEv.status}
|
eventSendStatus={mxEv.status}
|
||||||
last={last} isSelectedEvent={highlight}/>
|
last={last} isSelectedEvent={highlight}/>
|
||||||
|
|
|
@ -338,6 +338,10 @@ module.exports = React.createClass({
|
||||||
// ignore events for other rooms
|
// ignore events for other rooms
|
||||||
if (!this.state.room || room.roomId != this.state.room.roomId) return;
|
if (!this.state.room || room.roomId != this.state.room.roomId) return;
|
||||||
|
|
||||||
|
if (ev.getType() === "org.matrix.room.preview_urls") {
|
||||||
|
this._updatePreviewUrlVisibility(room);
|
||||||
|
}
|
||||||
|
|
||||||
// ignore anything but real-time updates at the end of the room:
|
// ignore anything but real-time updates at the end of the room:
|
||||||
// updates from pagination will happen when the paginate completes.
|
// updates from pagination will happen when the paginate completes.
|
||||||
if (toStartOfTimeline || !data || !data.liveEvent) return;
|
if (toStartOfTimeline || !data || !data.liveEvent) return;
|
||||||
|
@ -371,6 +375,7 @@ module.exports = React.createClass({
|
||||||
// after a successful peek, or after we join the room).
|
// after a successful peek, or after we join the room).
|
||||||
_onRoomLoaded: function(room) {
|
_onRoomLoaded: function(room) {
|
||||||
this._calculatePeekRules(room);
|
this._calculatePeekRules(room);
|
||||||
|
this._updatePreviewUrlVisibility(room);
|
||||||
},
|
},
|
||||||
|
|
||||||
_calculatePeekRules: function(room) {
|
_calculatePeekRules: function(room) {
|
||||||
|
@ -389,6 +394,42 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_updatePreviewUrlVisibility: function(room) {
|
||||||
|
console.log("_updatePreviewUrlVisibility");
|
||||||
|
|
||||||
|
// check our per-room overrides
|
||||||
|
var roomPreviewUrls = room.getAccountData("org.matrix.room.preview_urls");
|
||||||
|
if (roomPreviewUrls && roomPreviewUrls.getContent().disable !== undefined) {
|
||||||
|
this.setState({
|
||||||
|
showUrlPreview: !roomPreviewUrls.getContent().disable
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check our global disable override
|
||||||
|
var userRoomPreviewUrls = MatrixClientPeg.get().getAccountData("org.matrix.preview_urls");
|
||||||
|
if (userRoomPreviewUrls && userRoomPreviewUrls.getContent().disable) {
|
||||||
|
this.setState({
|
||||||
|
showUrlPreview: false
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the room state event
|
||||||
|
var roomStatePreviewUrls = room.currentState.getStateEvents('org.matrix.room.preview_urls', '');
|
||||||
|
if (roomStatePreviewUrls && roomStatePreviewUrls.getContent().disable) {
|
||||||
|
this.setState({
|
||||||
|
showUrlPreview: false
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, we assume they're on.
|
||||||
|
this.setState({
|
||||||
|
showUrlPreview: true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
onRoom: function(room) {
|
onRoom: function(room) {
|
||||||
// This event is fired when the room is 'stored' by the JS SDK, which
|
// This event is fired when the room is 'stored' by the JS SDK, which
|
||||||
// means it's now a fully-fledged room object ready to be used, so
|
// means it's now a fully-fledged room object ready to be used, so
|
||||||
|
@ -419,14 +460,17 @@ module.exports = React.createClass({
|
||||||
Tinter.tint(color_scheme.primary_color, color_scheme.secondary_color);
|
Tinter.tint(color_scheme.primary_color, color_scheme.secondary_color);
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomAccountData: function(room, event) {
|
onRoomAccountData: function(event, room) {
|
||||||
if (room.roomId == this.props.roomId) {
|
if (room.roomId == this.state.roomId) {
|
||||||
if (event.getType === "org.matrix.room.color_scheme") {
|
if (event.getType() === "org.matrix.room.color_scheme") {
|
||||||
var color_scheme = event.getContent();
|
var color_scheme = event.getContent();
|
||||||
// XXX: we should validate the event
|
// XXX: we should validate the event
|
||||||
console.log("Tinter.tint from onRoomAccountData");
|
console.log("Tinter.tint from onRoomAccountData");
|
||||||
Tinter.tint(color_scheme.primary_color, color_scheme.secondary_color);
|
Tinter.tint(color_scheme.primary_color, color_scheme.secondary_color);
|
||||||
}
|
}
|
||||||
|
else if (event.getType() === "org.matrix.room.preview_urls") {
|
||||||
|
this._updatePreviewUrlVisibility(room);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1506,6 +1550,8 @@ module.exports = React.createClass({
|
||||||
hideMessagePanel = true;
|
hideMessagePanel = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("ShowUrlPreview for %s is %s", this.state.room.roomId, this.state.showUrlPreview);
|
||||||
|
|
||||||
var messagePanel = (
|
var messagePanel = (
|
||||||
<TimelinePanel ref={this._gatherTimelinePanelRef}
|
<TimelinePanel ref={this._gatherTimelinePanelRef}
|
||||||
room={this.state.room}
|
room={this.state.room}
|
||||||
|
@ -1515,6 +1561,7 @@ module.exports = React.createClass({
|
||||||
eventPixelOffset={this.props.eventPixelOffset}
|
eventPixelOffset={this.props.eventPixelOffset}
|
||||||
onScroll={ this.onMessageListScroll }
|
onScroll={ this.onMessageListScroll }
|
||||||
onReadMarkerUpdated={ this._updateTopUnreadMessagesBar }
|
onReadMarkerUpdated={ this._updateTopUnreadMessagesBar }
|
||||||
|
showUrlPreview = { this.state.showUrlPreview }
|
||||||
opacity={ this.props.opacity }
|
opacity={ this.props.opacity }
|
||||||
/>);
|
/>);
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,9 @@ var TimelinePanel = React.createClass({
|
||||||
// half way down the viewport.
|
// half way down the viewport.
|
||||||
eventPixelOffset: React.PropTypes.number,
|
eventPixelOffset: React.PropTypes.number,
|
||||||
|
|
||||||
|
// Should we show URL Previews
|
||||||
|
showUrlPreview: React.PropTypes.bool,
|
||||||
|
|
||||||
// callback which is called when the panel is scrolled.
|
// callback which is called when the panel is scrolled.
|
||||||
onScroll: React.PropTypes.func,
|
onScroll: React.PropTypes.func,
|
||||||
|
|
||||||
|
@ -934,6 +937,7 @@ var TimelinePanel = React.createClass({
|
||||||
readMarkerEventId={ this.state.readMarkerEventId }
|
readMarkerEventId={ this.state.readMarkerEventId }
|
||||||
readMarkerVisible={ this.state.readMarkerVisible }
|
readMarkerVisible={ this.state.readMarkerVisible }
|
||||||
suppressFirstDateSeparator={ this.state.canBackPaginate }
|
suppressFirstDateSeparator={ this.state.canBackPaginate }
|
||||||
|
showUrlPreview = { this.props.showUrlPreview }
|
||||||
ourUserId={ MatrixClientPeg.get().credentials.userId }
|
ourUserId={ MatrixClientPeg.get().credentials.userId }
|
||||||
stickyBottom={ stickyBottom }
|
stickyBottom={ stickyBottom }
|
||||||
onScroll={ this.onMessageListScroll }
|
onScroll={ this.onMessageListScroll }
|
||||||
|
|
|
@ -262,6 +262,63 @@ module.exports = React.createClass({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_renderUserInterfaceSettings: function() {
|
||||||
|
var client = MatrixClientPeg.get();
|
||||||
|
|
||||||
|
var settingsLabels = [
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
id: 'alwaysShowTimestamps',
|
||||||
|
label: 'Always show message timestamps',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'showTwelveHourTimestamps',
|
||||||
|
label: 'Show timestamps in 12 hour format (e.g. 2:30pm)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'useCompactLayout',
|
||||||
|
label: 'Use compact timeline layout',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'useFixedWidthFont',
|
||||||
|
label: 'Use fixed width font',
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
];
|
||||||
|
|
||||||
|
var syncedSettings = UserSettingsStore.getSyncedSettings();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>User Interface</h3>
|
||||||
|
<div className="mx_UserSettings_section">
|
||||||
|
<div className="mx_UserSettings_toggle">
|
||||||
|
<input id="urlPreviewsDisabled"
|
||||||
|
type="checkbox"
|
||||||
|
defaultChecked={ UserSettingsStore.getUrlPreviewsDisabled() }
|
||||||
|
onChange={ e => UserSettingsStore.setUrlPreviewsDisabled(e.target.checked) }
|
||||||
|
/>
|
||||||
|
<label htmlFor="urlPreviewsDisabled">
|
||||||
|
Disable inline URL previews by default
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{ settingsLabels.forEach( setting => {
|
||||||
|
<div className="mx_UserSettings_toggle">
|
||||||
|
<input id={ setting.id }
|
||||||
|
type="checkbox"
|
||||||
|
defaultChecked={ syncedSettings[setting.id] }
|
||||||
|
onChange={ e => UserSettingsStore.setSyncedSetting(setting.id, e.target.checked) }
|
||||||
|
/>
|
||||||
|
<label htmlFor={ setting.id }>
|
||||||
|
{ settings.label }
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
_renderDeviceInfo: function() {
|
_renderDeviceInfo: function() {
|
||||||
if (!UserSettingsStore.isFeatureEnabled("e2e_encryption")) {
|
if (!UserSettingsStore.isFeatureEnabled("e2e_encryption")) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -379,7 +436,7 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
this._renderLabs = function () {
|
this._renderLabs = function () {
|
||||||
let features = LABS_FEATURES.map(feature => (
|
let features = LABS_FEATURES.map(feature => (
|
||||||
<div key={feature.id}>
|
<div key={feature.id} className="mx_UserSettings_toggle">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id={feature.id}
|
id={feature.id}
|
||||||
|
@ -453,6 +510,8 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
{notification_area}
|
{notification_area}
|
||||||
|
|
||||||
|
{this._renderUserInterfaceSettings()}
|
||||||
|
|
||||||
{this._renderDeviceInfo()}
|
{this._renderDeviceInfo()}
|
||||||
|
|
||||||
{this._renderLabs()}
|
{this._renderLabs()}
|
||||||
|
|
|
@ -38,6 +38,9 @@ module.exports = React.createClass({
|
||||||
/* link URL for the highlights */
|
/* link URL for the highlights */
|
||||||
highlightLink: React.PropTypes.string,
|
highlightLink: React.PropTypes.string,
|
||||||
|
|
||||||
|
/* should show URL previews for this event */
|
||||||
|
showUrlPreview: React.PropTypes.bool,
|
||||||
|
|
||||||
/* callback called when dynamic content in events are loaded */
|
/* callback called when dynamic content in events are loaded */
|
||||||
onWidgetLoad: React.PropTypes.func,
|
onWidgetLoad: React.PropTypes.func,
|
||||||
},
|
},
|
||||||
|
@ -71,6 +74,7 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
return <BodyType ref="body" mxEvent={this.props.mxEvent} highlights={this.props.highlights}
|
return <BodyType ref="body" mxEvent={this.props.mxEvent} highlights={this.props.highlights}
|
||||||
highlightLink={this.props.highlightLink}
|
highlightLink={this.props.highlightLink}
|
||||||
|
showUrlPreview={this.props.showUrlPreview}
|
||||||
onWidgetLoad={this.props.onWidgetLoad} />;
|
onWidgetLoad={this.props.onWidgetLoad} />;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -39,6 +39,9 @@ module.exports = React.createClass({
|
||||||
/* link URL for the highlights */
|
/* link URL for the highlights */
|
||||||
highlightLink: React.PropTypes.string,
|
highlightLink: React.PropTypes.string,
|
||||||
|
|
||||||
|
/* should show URL previews for this event */
|
||||||
|
showUrlPreview: React.PropTypes.bool,
|
||||||
|
|
||||||
/* callback for when our widget has loaded */
|
/* callback for when our widget has loaded */
|
||||||
onWidgetLoad: React.PropTypes.func,
|
onWidgetLoad: React.PropTypes.func,
|
||||||
},
|
},
|
||||||
|
@ -56,34 +59,47 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
linkifyElement(this.refs.content, linkifyMatrix.options);
|
linkifyElement(this.refs.content, linkifyMatrix.options);
|
||||||
|
this.calculateUrlPreview();
|
||||||
var links = this.findLinks(this.refs.content.children);
|
|
||||||
if (links.length) {
|
|
||||||
this.setState({ links: links.map((link)=>{
|
|
||||||
return link.getAttribute("href");
|
|
||||||
})});
|
|
||||||
|
|
||||||
// lazy-load the hidden state of the preview widget from localstorage
|
|
||||||
if (global.localStorage) {
|
|
||||||
var hidden = global.localStorage.getItem("hide_preview_" + this.props.mxEvent.getId());
|
|
||||||
this.setState({ widgetHidden: hidden });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.mxEvent.getContent().format === "org.matrix.custom.html")
|
if (this.props.mxEvent.getContent().format === "org.matrix.custom.html")
|
||||||
HtmlUtils.highlightDom(ReactDOM.findDOMNode(this));
|
HtmlUtils.highlightDom(ReactDOM.findDOMNode(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentDidUpdate: function() {
|
||||||
|
this.calculateUrlPreview();
|
||||||
|
},
|
||||||
|
|
||||||
shouldComponentUpdate: function(nextProps, nextState) {
|
shouldComponentUpdate: function(nextProps, nextState) {
|
||||||
|
//console.log("shouldComponentUpdate: ShowUrlPreview for %s is %s", this.props.mxEvent.getId(), this.props.showUrlPreview);
|
||||||
|
|
||||||
// exploit that events are immutable :)
|
// exploit that events are immutable :)
|
||||||
// ...and that .links is only ever set in componentDidMount and never changes
|
|
||||||
return (nextProps.mxEvent.getId() !== this.props.mxEvent.getId() ||
|
return (nextProps.mxEvent.getId() !== this.props.mxEvent.getId() ||
|
||||||
nextProps.highlights !== this.props.highlights ||
|
nextProps.highlights !== this.props.highlights ||
|
||||||
nextProps.highlightLink !== this.props.highlightLink ||
|
nextProps.highlightLink !== this.props.highlightLink ||
|
||||||
|
nextProps.showUrlPreview !== this.props.showUrlPreview ||
|
||||||
nextState.links !== this.state.links ||
|
nextState.links !== this.state.links ||
|
||||||
nextState.widgetHidden !== this.state.widgetHidden);
|
nextState.widgetHidden !== this.state.widgetHidden);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
calculateUrlPreview: function() {
|
||||||
|
//console.log("calculateUrlPreview: ShowUrlPreview for %s is %s", this.props.mxEvent.getId(), this.props.showUrlPreview);
|
||||||
|
|
||||||
|
if (this.props.showUrlPreview && !this.state.links.length) {
|
||||||
|
var links = this.findLinks(this.refs.content.children);
|
||||||
|
if (links.length) {
|
||||||
|
this.setState({ links: links.map((link)=>{
|
||||||
|
return link.getAttribute("href");
|
||||||
|
})});
|
||||||
|
|
||||||
|
// lazy-load the hidden state of the preview widget from localstorage
|
||||||
|
if (global.localStorage) {
|
||||||
|
var hidden = global.localStorage.getItem("hide_preview_" + this.props.mxEvent.getId());
|
||||||
|
this.setState({ widgetHidden: hidden });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
findLinks: function(nodes) {
|
findLinks: function(nodes) {
|
||||||
var links = [];
|
var links = [];
|
||||||
for (var i = 0; i < nodes.length; i++) {
|
for (var i = 0; i < nodes.length; i++) {
|
||||||
|
@ -163,12 +179,14 @@ module.exports = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
var mxEvent = this.props.mxEvent;
|
var mxEvent = this.props.mxEvent;
|
||||||
var content = mxEvent.getContent();
|
var content = mxEvent.getContent();
|
||||||
var body = HtmlUtils.bodyToHtml(content, this.props.highlights,
|
var body = HtmlUtils.bodyToHtml(content, this.props.highlights, {});
|
||||||
{highlightLink: this.props.highlightLink});
|
|
||||||
|
|
||||||
|
if (this.props.highlightLink) {
|
||||||
|
body = <a href={ this.props.highlightLink }>{ body }</a>;
|
||||||
|
}
|
||||||
|
|
||||||
var widgets;
|
var widgets;
|
||||||
if (this.state.links.length && !this.state.widgetHidden) {
|
if (this.state.links.length && !this.state.widgetHidden && this.props.showUrlPreview) {
|
||||||
var LinkPreviewWidget = sdk.getComponent('rooms.LinkPreviewWidget');
|
var LinkPreviewWidget = sdk.getComponent('rooms.LinkPreviewWidget');
|
||||||
widgets = this.state.links.map((link)=>{
|
widgets = this.state.links.map((link)=>{
|
||||||
return <LinkPreviewWidget
|
return <LinkPreviewWidget
|
||||||
|
|
|
@ -57,7 +57,7 @@ module.exports = React.createClass({
|
||||||
data.primary_color = scheme.primary_color;
|
data.primary_color = scheme.primary_color;
|
||||||
data.secondary_color = scheme.secondary_color;
|
data.secondary_color = scheme.secondary_color;
|
||||||
data.index = this._getColorIndex(data);
|
data.index = this._getColorIndex(data);
|
||||||
|
|
||||||
if (data.index === -1) {
|
if (data.index === -1) {
|
||||||
// append the unrecognised colours to our palette
|
// append the unrecognised colours to our palette
|
||||||
data.index = ROOM_COLORS.length;
|
data.index = ROOM_COLORS.length;
|
||||||
|
|
157
src/components/views/room_settings/UrlPreviewSettings.js
Normal file
157
src/components/views/room_settings/UrlPreviewSettings.js
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 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 q = require("q");
|
||||||
|
var React = require('react');
|
||||||
|
var MatrixClientPeg = require('../../../MatrixClientPeg');
|
||||||
|
var sdk = require("../../../index");
|
||||||
|
var Modal = require("../../../Modal");
|
||||||
|
var UserSettingsStore = require('../../../UserSettingsStore');
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = React.createClass({
|
||||||
|
displayName: 'UrlPreviewSettings',
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
room: React.PropTypes.object,
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialState: function() {
|
||||||
|
var cli = MatrixClientPeg.get();
|
||||||
|
var roomState = this.props.room.currentState;
|
||||||
|
|
||||||
|
var roomPreviewUrls = this.props.room.currentState.getStateEvents('org.matrix.room.preview_urls', '');
|
||||||
|
var userPreviewUrls = this.props.room.getAccountData("org.matrix.room.preview_urls");
|
||||||
|
|
||||||
|
return {
|
||||||
|
globalDisableUrlPreview: (roomPreviewUrls && roomPreviewUrls.getContent().disable) || false,
|
||||||
|
userDisableUrlPreview: (userPreviewUrls && (userPreviewUrls.getContent().disable === true)) || false,
|
||||||
|
userEnableUrlPreview: (userPreviewUrls && (userPreviewUrls.getContent().disable === false)) || false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.originalState = Object.assign({}, this.state);
|
||||||
|
},
|
||||||
|
|
||||||
|
saveSettings: function() {
|
||||||
|
var promises = [];
|
||||||
|
|
||||||
|
if (this.state.globalDisableUrlPreview !== this.originalState.globalDisableUrlPreview) {
|
||||||
|
console.log("UrlPreviewSettings: Updating room's preview_urls state event");
|
||||||
|
promises.push(
|
||||||
|
MatrixClientPeg.get().sendStateEvent(
|
||||||
|
this.props.room.roomId, "org.matrix.room.preview_urls", {
|
||||||
|
disable: this.state.globalDisableUrlPreview
|
||||||
|
}, ""
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var content = undefined;
|
||||||
|
if (this.state.userDisableUrlPreview !== this.originalState.userDisableUrlPreview) {
|
||||||
|
console.log("UrlPreviewSettings: Disabling user's per-room preview_urls");
|
||||||
|
content = this.state.userDisableUrlPreview ? { disable : true } : {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.state.userEnableUrlPreview !== this.originalState.userEnableUrlPreview) {
|
||||||
|
console.log("UrlPreviewSettings: Enabling user's per-room preview_urls");
|
||||||
|
if (!content || content.disable === undefined) {
|
||||||
|
content = this.state.userEnableUrlPreview ? { disable : false } : {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content) {
|
||||||
|
promises.push(
|
||||||
|
MatrixClientPeg.get().setRoomAccountData(
|
||||||
|
this.props.room.roomId, "org.matrix.room.preview_urls", content
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("UrlPreviewSettings: saveSettings: " + JSON.stringify(promises));
|
||||||
|
|
||||||
|
return promises;
|
||||||
|
},
|
||||||
|
|
||||||
|
onGlobalDisableUrlPreviewChange: function() {
|
||||||
|
this.setState({
|
||||||
|
globalDisableUrlPreview: this.refs.globalDisableUrlPreview.checked ? true : false,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onUserEnableUrlPreviewChange: function() {
|
||||||
|
this.setState({
|
||||||
|
userDisableUrlPreview: false,
|
||||||
|
userEnableUrlPreview: this.refs.userEnableUrlPreview.checked ? true : false,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onUserDisableUrlPreviewChange: function() {
|
||||||
|
this.setState({
|
||||||
|
userDisableUrlPreview: this.refs.userDisableUrlPreview.checked ? true : false,
|
||||||
|
userEnableUrlPreview: false,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
var self = this;
|
||||||
|
var roomState = this.props.room.currentState;
|
||||||
|
var cli = MatrixClientPeg.get();
|
||||||
|
|
||||||
|
var maySetRoomPreviewUrls = roomState.mayClientSendStateEvent('org.matrix.room.preview_urls', cli);
|
||||||
|
var disableRoomPreviewUrls;
|
||||||
|
if (maySetRoomPreviewUrls) {
|
||||||
|
disableRoomPreviewUrls =
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" ref="globalDisableUrlPreview"
|
||||||
|
onChange={ this.onGlobalDisableUrlPreviewChange }
|
||||||
|
checked={ this.state.globalDisableUrlPreview } />
|
||||||
|
Disable URL previews by default for participants in this room
|
||||||
|
</label>
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
disableRoomPreviewUrls =
|
||||||
|
<label>
|
||||||
|
URL previews are { this.state.globalDisableUrlPreview ? "disabled" : "enabled" } by default for participants in this room.
|
||||||
|
</label>
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx_RoomSettings_toggles">
|
||||||
|
<h3>URL Previews</h3>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
You have <a href="#/settings">{ UserSettingsStore.getUrlPreviewsDisabled() ? 'disabled' : 'enabled' }</a> URL previews by default.
|
||||||
|
</label>
|
||||||
|
{ disableRoomPreviewUrls }
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" ref="userEnableUrlPreview"
|
||||||
|
onChange={ this.onUserEnableUrlPreviewChange }
|
||||||
|
checked={ this.state.userEnableUrlPreview } />
|
||||||
|
Enable URL previews for this room (affects only you)
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" ref="userDisableUrlPreview"
|
||||||
|
onChange={ this.onUserDisableUrlPreviewChange }
|
||||||
|
checked={ this.state.userDisableUrlPreview } />
|
||||||
|
Disable URL previews for this room (affects only you)
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
|
@ -101,6 +101,9 @@ module.exports = React.createClass({
|
||||||
/* link URL for the highlights */
|
/* link URL for the highlights */
|
||||||
highlightLink: React.PropTypes.string,
|
highlightLink: React.PropTypes.string,
|
||||||
|
|
||||||
|
/* should show URL previews for this event */
|
||||||
|
showUrlPreview: React.PropTypes.bool,
|
||||||
|
|
||||||
/* is this the focused event */
|
/* is this the focused event */
|
||||||
isSelectedEvent: React.PropTypes.bool,
|
isSelectedEvent: React.PropTypes.bool,
|
||||||
|
|
||||||
|
@ -359,6 +362,8 @@ module.exports = React.createClass({
|
||||||
var SenderProfile = sdk.getComponent('messages.SenderProfile');
|
var SenderProfile = sdk.getComponent('messages.SenderProfile');
|
||||||
var MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
var MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
||||||
|
|
||||||
|
//console.log("EventTile showUrlPreview for %s is %s", this.props.mxEvent.getId(), this.props.showUrlPreview);
|
||||||
|
|
||||||
var content = this.props.mxEvent.getContent();
|
var content = this.props.mxEvent.getContent();
|
||||||
var msgtype = content.msgtype;
|
var msgtype = content.msgtype;
|
||||||
|
|
||||||
|
@ -420,6 +425,7 @@ module.exports = React.createClass({
|
||||||
<div className="mx_EventTile_line">
|
<div className="mx_EventTile_line">
|
||||||
<EventTileType ref="tile" mxEvent={this.props.mxEvent} highlights={this.props.highlights}
|
<EventTileType ref="tile" mxEvent={this.props.mxEvent} highlights={this.props.highlights}
|
||||||
highlightLink={this.props.highlightLink}
|
highlightLink={this.props.highlightLink}
|
||||||
|
showUrlPreview={this.props.showUrlPreview}
|
||||||
onWidgetLoad={this.props.onWidgetLoad} />
|
onWidgetLoad={this.props.onWidgetLoad} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -216,10 +216,13 @@ module.exports = React.createClass({
|
||||||
// color scheme
|
// color scheme
|
||||||
promises.push(this.saveColor());
|
promises.push(this.saveColor());
|
||||||
|
|
||||||
|
// url preview settings
|
||||||
|
promises.push(this.saveUrlPreviewSettings());
|
||||||
|
|
||||||
// encryption
|
// encryption
|
||||||
promises.push(this.saveEncryption());
|
promises.push(this.saveEncryption());
|
||||||
|
|
||||||
console.log("Performing %s operations", promises.length);
|
console.log("Performing %s operations: %s", promises.length, JSON.stringify(promises));
|
||||||
return q.allSettled(promises);
|
return q.allSettled(promises);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -233,6 +236,11 @@ module.exports = React.createClass({
|
||||||
return this.refs.color_settings.saveSettings();
|
return this.refs.color_settings.saveSettings();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
saveUrlPreviewSettings: function() {
|
||||||
|
if (!this.refs.url_preview_settings) { return q(); }
|
||||||
|
return this.refs.url_preview_settings.saveSettings();
|
||||||
|
},
|
||||||
|
|
||||||
saveEncryption: function () {
|
saveEncryption: function () {
|
||||||
if (!this.refs.encrypt) { return q(); }
|
if (!this.refs.encrypt) { return q(); }
|
||||||
|
|
||||||
|
@ -427,6 +435,7 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
var AliasSettings = sdk.getComponent("room_settings.AliasSettings");
|
var AliasSettings = sdk.getComponent("room_settings.AliasSettings");
|
||||||
var ColorSettings = sdk.getComponent("room_settings.ColorSettings");
|
var ColorSettings = sdk.getComponent("room_settings.ColorSettings");
|
||||||
|
var UrlPreviewSettings = sdk.getComponent("room_settings.UrlPreviewSettings");
|
||||||
var EditableText = sdk.getComponent('elements.EditableText');
|
var EditableText = sdk.getComponent('elements.EditableText');
|
||||||
var PowerSelector = sdk.getComponent('elements.PowerSelector');
|
var PowerSelector = sdk.getComponent('elements.PowerSelector');
|
||||||
|
|
||||||
|
@ -659,6 +668,8 @@ module.exports = React.createClass({
|
||||||
canonicalAliasEvent={this.props.room.currentState.getStateEvents('m.room.canonical_alias', '')}
|
canonicalAliasEvent={this.props.room.currentState.getStateEvents('m.room.canonical_alias', '')}
|
||||||
aliasEvents={this.props.room.currentState.getStateEvents('m.room.aliases')} />
|
aliasEvents={this.props.room.currentState.getStateEvents('m.room.aliases')} />
|
||||||
|
|
||||||
|
<UrlPreviewSettings ref="url_preview_settings" room={this.props.room} />
|
||||||
|
|
||||||
<h3>Permissions</h3>
|
<h3>Permissions</h3>
|
||||||
<div className="mx_RoomSettings_powerLevels mx_RoomSettings_settings">
|
<div className="mx_RoomSettings_powerLevels mx_RoomSettings_settings">
|
||||||
<div className="mx_RoomSettings_powerLevel">
|
<div className="mx_RoomSettings_powerLevel">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue