Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit e596924

Browse files
committed
Merge branch 'develop' into release-v0.12.4
2 parents ff0254d + 8c3a63a commit e596924

File tree

14 files changed

+65
-32
lines changed

14 files changed

+65
-32
lines changed

res/css/views/elements/_ReplyThread.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17+
.mx_ReplyThread {
18+
margin-top: 0;
19+
}
20+
1721
.mx_ReplyThread .mx_DateSeparator {
1822
font-size: 1em !important;
23+
margin-top: 0;
1924
margin-bottom: 0;
2025
padding-bottom: 1px;
2126
bottom: -5px;

src/FromWidgetPostMessageApi.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@ export default class FromWidgetPostMessageApi {
116116
return; // don't log this - debugging APIs like to spam postMessage which floods the log otherwise
117117
}
118118

119+
// Although the requestId is required, we don't use it. We'll be nice and process the message
120+
// if the property is missing, but with a warning for widget developers.
121+
if (!event.data.requestId) {
122+
console.warn("fromWidget action '" + event.data.action + "' does not have a requestId");
123+
}
124+
119125
const action = event.data.action;
120126
const widgetId = event.data.widgetId;
121127
if (action === 'content_loaded') {
@@ -137,12 +143,15 @@ export default class FromWidgetPostMessageApi {
137143
});
138144
} else if (action === 'm.sticker') {
139145
// console.warn('Got sticker message from widget', widgetId);
140-
dis.dispatch({action: 'm.sticker', data: event.data.widgetData, widgetId: event.data.widgetId});
146+
// NOTE -- The widgetData field is deprecated (in favour of the 'data' field) and will be removed eventually
147+
const data = event.data.data || event.data.widgetData;
148+
dis.dispatch({action: 'm.sticker', data: data, widgetId: event.data.widgetId});
141149
} else if (action === 'integration_manager_open') {
142150
// Close the stickerpicker
143151
dis.dispatch({action: 'stickerpicker_close'});
144152
// Open the integration manager
145-
const data = event.data.widgetData;
153+
// NOTE -- The widgetData field is deprecated (in favour of the 'data' field) and will be removed eventually
154+
const data = event.data.data || event.data.widgetData;
146155
const integType = (data && data.integType) ? data.integType : null;
147156
const integId = (data && data.integId) ? data.integId : null;
148157
IntegrationManager.open(integType, integId);

src/HtmlUtils.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,6 @@ const sanitizeHtmlParams = {
186186
],
187187
allowedAttributes: {
188188
// custom ones first:
189-
blockquote: ['data-mx-reply'], // used to allow explicit removal of a reply fallback blockquote, value ignored
190189
font: ['color', 'data-mx-bg-color', 'data-mx-color', 'style'], // custom to matrix
191190
span: ['data-mx-bg-color', 'data-mx-color', 'style'], // custom to matrix
192191
a: ['href', 'name', 'target', 'rel'], // remote target: custom to matrix

src/ScalarMessaging.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ function setWidget(event, roomId) {
349349
userWidgets[widgetId] = {
350350
content: content,
351351
sender: client.getUserId(),
352-
stateKey: widgetId,
352+
state_key: widgetId,
353353
type: 'm.widget',
354354
id: widgetId,
355355
};

src/ToWidgetPostMessageApi.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ export default class ToWidgetPostMessageApi {
5151
if (payload.response === undefined) {
5252
return;
5353
}
54-
const promise = this._requestMap[payload._id];
54+
const promise = this._requestMap[payload.requestId];
5555
if (!promise) {
5656
return;
5757
}
58-
delete this._requestMap[payload._id];
58+
delete this._requestMap[payload.requestId];
5959
promise.resolve(payload);
6060
}
6161

@@ -64,21 +64,21 @@ export default class ToWidgetPostMessageApi {
6464
targetWindow = targetWindow || window.parent; // default to parent window
6565
targetOrigin = targetOrigin || "*";
6666
this._counter += 1;
67-
action._id = Date.now() + "-" + Math.random().toString(36) + "-" + this._counter;
67+
action.requestId = Date.now() + "-" + Math.random().toString(36) + "-" + this._counter;
6868

6969
return new Promise((resolve, reject) => {
70-
this._requestMap[action._id] = {resolve, reject};
70+
this._requestMap[action.requestId] = {resolve, reject};
7171
targetWindow.postMessage(action, targetOrigin);
7272

7373
if (this._timeoutMs > 0) {
7474
setTimeout(() => {
75-
if (!this._requestMap[action._id]) {
75+
if (!this._requestMap[action.requestId]) {
7676
return;
7777
}
7878
console.error("postMessage request timed out. Sent object: " + JSON.stringify(action),
7979
this._requestMap);
80-
this._requestMap[action._id].reject(new Error("Timed out"));
81-
delete this._requestMap[action._id];
80+
this._requestMap[action.requestId].reject(new Error("Timed out"));
81+
delete this._requestMap[action.requestId];
8282
}, this._timeoutMs);
8383
}
8484
});

src/WidgetMessaging.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ export default class WidgetMessaging {
4444
}
4545

4646
messageToWidget(action) {
47+
action.widgetId = this.widgetId; // Required to be sent for all outbound requests
48+
4749
return this.toWidget.exec(action, this.target).then((data) => {
4850
// Check for errors and reject if found
4951
if (data.response === undefined) { // null is valid

src/components/structures/UserSettings.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ const SIMPLE_SETTINGS = [
8080
{ id: "TextualBody.disableBigEmoji" },
8181
{ id: "VideoView.flipVideoHorizontally" },
8282
{ id: "TagPanel.disableTagPanel" },
83+
{ id: "enableWidgetScreenshots" },
8384
];
8485

8586
// These settings must be defined in SettingsStore

src/components/views/elements/AppTile.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export default class AppTile extends React.Component {
8585

8686
/**
8787
* Does the widget support a given capability
88-
* @param {[type]} capability Capability to check for
88+
* @param {string} capability Capability to check for
8989
* @return {Boolean} True if capability supported
9090
*/
9191
_hasCapability(capability) {
@@ -281,6 +281,11 @@ export default class AppTile extends React.Component {
281281
}
282282

283283
_canUserModify() {
284+
// User widgets should always be modifiable by their creator
285+
if (this.props.userWidget && MatrixClientPeg.get().credentials.userId === this.props.creatorUserId) {
286+
return true;
287+
}
288+
// Check if the current user can modify widgets in the current room
284289
return WidgetUtils.canUserModifyWidgets(this.props.room.roomId);
285290
}
286291

@@ -598,7 +603,7 @@ export default class AppTile extends React.Component {
598603
}
599604

600605
// Picture snapshot - only show button when apps are maximised.
601-
const showPictureSnapshotButton = this._hasCapability('screenshot') && this.props.show;
606+
const showPictureSnapshotButton = this._hasCapability('m.capability.screenshot') && this.props.show;
602607
const showPictureSnapshotIcon = 'img/camera_green.svg';
603608
const popoutWidgetIcon = 'img/button-new-window.svg';
604609
const windowStateIcon = (this.props.show ? 'img/minimize.svg' : 'img/maximize.svg');
@@ -702,13 +707,15 @@ AppTile.propTypes = {
702707
showDelete: PropTypes.bool,
703708
// Optionally hide the popout widget icon
704709
showPopout: PropTypes.bool,
705-
// Widget apabilities to allow by default (without user confirmation)
710+
// Widget capabilities to allow by default (without user confirmation)
706711
// NOTE -- Use with caution. This is intended to aid better integration / UX
707712
// basic widget capabilities, e.g. injecting sticker message events.
708713
whitelistCapabilities: PropTypes.array,
709714
// Optional function to be called on widget capability request
710715
// Called with an array of the requested capabilities
711716
onCapabilityRequest: PropTypes.func,
717+
// Is this an instance of a user widget
718+
userWidget: PropTypes.bool,
712719
};
713720

714721
AppTile.defaultProps = {
@@ -721,4 +728,5 @@ AppTile.defaultProps = {
721728
showPopout: true,
722729
handleMinimisePointerEvents: false,
723730
whitelistCapabilities: [],
731+
userWidget: false,
724732
};

src/components/views/elements/ReplyThread.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export default class ReplyThread extends React.Component {
8181

8282
// Part of Replies fallback support
8383
static stripHTMLReply(html) {
84-
return html.replace(/^<blockquote data-mx-reply>[\s\S]+?<!--end-mx-reply--><\/blockquote>/, '');
84+
return html.replace(/^<mx-reply>[\s\S]+?<\/mx-reply>/, '');
8585
}
8686

8787
// Part of Replies fallback support
@@ -102,8 +102,8 @@ export default class ReplyThread extends React.Component {
102102
switch (ev.getContent().msgtype) {
103103
case 'm.text':
104104
case 'm.notice': {
105-
html = `<blockquote data-mx-reply><a href="${evLink}">In reply to</a> <a href="${userLink}">${mxid}</a>`
106-
+ `<br>${html || body}<!--end-mx-reply--></blockquote>`;
105+
html = `<mx-reply><blockquote><a href="${evLink}">In reply to</a> <a href="${userLink}">${mxid}</a>`
106+
+ `<br>${html || body}</blockquote></mx-reply>`;
107107
const lines = body.trim().split('\n');
108108
if (lines.length > 0) {
109109
lines[0] = `<${mxid}> ${lines[0]}`;
@@ -112,28 +112,28 @@ export default class ReplyThread extends React.Component {
112112
break;
113113
}
114114
case 'm.image':
115-
html = `<blockquote data-mx-reply><a href="${evLink}">In reply to</a> <a href="${userLink}">${mxid}</a>`
116-
+ `<br>sent an image.<!--end-mx-reply--></blockquote>`;
115+
html = `<mx-reply><blockquote><a href="${evLink}">In reply to</a> <a href="${userLink}">${mxid}</a>`
116+
+ `<br>sent an image.</blockquote></mx-reply>`;
117117
body = `> <${mxid}> sent an image.\n\n`;
118118
break;
119119
case 'm.video':
120-
html = `<blockquote data-mx-reply><a href="${evLink}">In reply to</a> <a href="${userLink}">${mxid}</a>`
121-
+ `<br>sent a video.<!--end-mx-reply--></blockquote>`;
120+
html = `<mx-reply><blockquote><a href="${evLink}">In reply to</a> <a href="${userLink}">${mxid}</a>`
121+
+ `<br>sent a video.</blockquote></mx-reply>`;
122122
body = `> <${mxid}> sent a video.\n\n`;
123123
break;
124124
case 'm.audio':
125-
html = `<blockquote data-mx-reply><a href="${evLink}">In reply to</a> <a href="${userLink}">${mxid}</a>`
126-
+ `<br>sent an audio file.<!--end-mx-reply--></blockquote>`;
125+
html = `<mx-reply><blockquote><a href="${evLink}">In reply to</a> <a href="${userLink}">${mxid}</a>`
126+
+ `<br>sent an audio file.</blockquote></mx-reply>`;
127127
body = `> <${mxid}> sent an audio file.\n\n`;
128128
break;
129129
case 'm.file':
130-
html = `<blockquote data-mx-reply><a href="${evLink}">In reply to</a> <a href="${userLink}">${mxid}</a>`
131-
+ `<br>sent a file.<!--end-mx-reply--></blockquote>`;
130+
html = `<mx-reply><blockquote><a href="${evLink}">In reply to</a> <a href="${userLink}">${mxid}</a>`
131+
+ `<br>sent a file.</blockquote></mx-reply>`;
132132
body = `> <${mxid}> sent a file.\n\n`;
133133
break;
134134
case 'm.emote': {
135-
html = `<blockquote data-mx-reply><a href="${evLink}">In reply to</a> * `
136-
+ `<a href="${userLink}">${mxid}</a><br>${html || body}<!--end-mx-reply--></blockquote>`;
135+
html = `<mx-reply><blockquote><a href="${evLink}">In reply to</a> * `
136+
+ `<a href="${userLink}">${mxid}</a><br>${html || body}</blockquote></mx-reply>`;
137137
const lines = body.trim().split('\n');
138138
if (lines.length > 0) {
139139
lines[0] = `* <${mxid}> ${lines[0]}`;

src/components/views/rooms/AppsDrawer.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ module.exports = React.createClass({
227227
},
228228

229229
render: function() {
230+
const enableScreenshots = SettingsStore.getValue("enableWidgetScreenshots", this.props.room.room_id);
231+
230232
const apps = this.state.apps.map(
231233
(app, index, arr) => {
232234
return (<AppTile
@@ -242,6 +244,7 @@ module.exports = React.createClass({
242244
creatorUserId={app.creatorUserId}
243245
widgetPageTitle={(app.data && app.data.title) ? app.data.title : ''}
244246
waitForIframeLoad={app.waitForIframeLoad}
247+
whitelistCapabilities={enableScreenshots ? ["m.capability.screenshot"] : []}
245248
/>);
246249
});
247250

0 commit comments

Comments
 (0)