forked from matrix/element-web
Compare commits
5 Commits
develop
...
travis/inl
Author | SHA1 | Date |
---|---|---|
Travis Ralston | b06de25898 | |
Travis Ralston | 62a152b68a | |
Travis Ralston | fe831dc8dd | |
Travis Ralston | 7ff2b598af | |
Travis Ralston | 1b8fe9e782 |
|
@ -60,6 +60,13 @@ Ban lists are rooms within Matrix, proposed as [MSC2313](https://github.com/matr
|
||||||
[Mjolnir](https://github.com/matrix-org/mjolnir) is a set of moderation tools which support
|
[Mjolnir](https://github.com/matrix-org/mjolnir) is a set of moderation tools which support
|
||||||
ban lists.
|
ban lists.
|
||||||
|
|
||||||
|
## Inline widgets
|
||||||
|
|
||||||
|
`feature_inline_widgets` allows rendering and sending of inline widgets. Inline
|
||||||
|
widgets are typically polls or rich embedded content in rooms.
|
||||||
|
|
||||||
|
[#riot-web:matrix.org]: https://matrix.to/#/#riot-web:matrix.org
|
||||||
|
|
||||||
## Verifications in DMs (`feature_dm_verification`)
|
## Verifications in DMs (`feature_dm_verification`)
|
||||||
|
|
||||||
An implementation of [MSC2241](https://github.com/matrix-org/matrix-doc/pull/2241). When enabled, verification might not work with devices which don't support MSC2241.
|
An implementation of [MSC2241](https://github.com/matrix-org/matrix-doc/pull/2241). When enabled, verification might not work with devices which don't support MSC2241.
|
||||||
|
|
|
@ -71,6 +71,9 @@
|
||||||
"olm": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz",
|
"olm": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz",
|
||||||
"postcss-easings": "^2.0.0",
|
"postcss-easings": "^2.0.0",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
|
"querystring": "^0.2.0",
|
||||||
|
"random-string": "^0.2.0",
|
||||||
|
"randomstring": "^1.1.5",
|
||||||
"react": "^16.9.0",
|
"react": "^16.9.0",
|
||||||
"react-dom": "^16.9.0",
|
"react-dom": "^16.9.0",
|
||||||
"sanitize-html": "^1.19.1",
|
"sanitize-html": "^1.19.1",
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 New Vector 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import randomString from "random-string";
|
||||||
|
|
||||||
|
// Dev note: This is largely inspired by Dimension. Used with permission.
|
||||||
|
// https://github.com/turt2live/matrix-dimension/blob/4f92d560266635e5a3c824606215b84e8c0b19f5/web/app/shared/services/scalar/scalar-widget.api.ts#L1
|
||||||
|
export default class WidgetApi {
|
||||||
|
|
||||||
|
_origin;
|
||||||
|
_widgetId;
|
||||||
|
_capabilities;
|
||||||
|
_inFlightRequests = {}; // { reqId => replyFn(payload) }
|
||||||
|
|
||||||
|
constructor(origin, widgetId, capabilities) {
|
||||||
|
this._origin = new URL(origin).origin;
|
||||||
|
this._widgetId = widgetId;
|
||||||
|
this._capabilities = capabilities;
|
||||||
|
|
||||||
|
const toWidgetActions = {
|
||||||
|
"capabilities": this._onCapabilitiesRequest.bind(this),
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("message", event => {
|
||||||
|
if (event.origin !== this._origin) return; // ignore due to invalid origin
|
||||||
|
if (!event.data) return;
|
||||||
|
if (event.data.widgetId !== this._widgetId) return;
|
||||||
|
|
||||||
|
const payload = event.data;
|
||||||
|
if (payload.api === "toWidget" && payload.action) {
|
||||||
|
console.log("[Inline Widget] Got toWidget: " + JSON.stringify(payload));
|
||||||
|
const handler = toWidgetActions[payload.action];
|
||||||
|
if (handler) handler(payload);
|
||||||
|
}
|
||||||
|
if (payload.api === "fromWidget" && this._inFlightRequests[payload.requestId]) {
|
||||||
|
console.log("[Inline Widget] Got fromWidget reply: " + JSON.stringify(payload));
|
||||||
|
const handler = this._inFlightRequests[payload.requestId];
|
||||||
|
delete this._inFlightRequests[payload.requestId];
|
||||||
|
handler(payload);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendText(text) {
|
||||||
|
this.sendEvent("m.room.message", {msgtype: "m.text", body: text});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendNotice(text) {
|
||||||
|
this.sendEvent("m.room.message", {msgtype: "m.notice", body: text});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendEvent(eventType, content) {
|
||||||
|
this._callAction("send_event", {
|
||||||
|
type: eventType,
|
||||||
|
content: content,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_callAction(action, payload) {
|
||||||
|
if (!window.parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = {
|
||||||
|
api: "fromWidget",
|
||||||
|
widgetId: this._widgetId,
|
||||||
|
action: action,
|
||||||
|
requestId: randomString({length: 16}),
|
||||||
|
data: payload,
|
||||||
|
};
|
||||||
|
|
||||||
|
this._inFlightRequests[request.requestId] = () => {};
|
||||||
|
|
||||||
|
console.log("[Inline Widget] Sending fromWidget: ", request);
|
||||||
|
window.parent.postMessage(request, this._origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
_replyPayload(incPayload, payload) {
|
||||||
|
if (!window.parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let request = JSON.parse(JSON.stringify(incPayload));
|
||||||
|
request["response"] = payload;
|
||||||
|
|
||||||
|
window.parent.postMessage(request, this._origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onCapabilitiesRequest(payload) {
|
||||||
|
this._replyPayload(payload, {capabilities: this._capabilities});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<body>
|
||||||
|
<div id="widgetHtml"></div>
|
||||||
|
</body>
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 New Vector 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.
|
||||||
|
*/
|
||||||
|
import queryString from "querystring";
|
||||||
|
import WidgetApi from "./WidgetApi";
|
||||||
|
|
||||||
|
let widgetApi;
|
||||||
|
try {
|
||||||
|
const qs = queryString.parse(window.location.search.substring(1));
|
||||||
|
if (!qs["widgetId"]) {
|
||||||
|
// noinspection ExceptionCaughtLocallyJS
|
||||||
|
throw new Error("Missing widgetId in query string");
|
||||||
|
}
|
||||||
|
if (!qs["parentUrl"]) {
|
||||||
|
// noinspection ExceptionCaughtLocallyJS
|
||||||
|
throw new Error("Missing parentUrl in query string");
|
||||||
|
}
|
||||||
|
|
||||||
|
const widgetOpts = JSON.parse(atob(window.location.hash
|
||||||
|
.substring(1)
|
||||||
|
.replace(/-/g, '+')
|
||||||
|
.replace(/_/g, '/')));
|
||||||
|
|
||||||
|
// This widget wrapper is always on the same origin as the client itself
|
||||||
|
widgetApi = new WidgetApi(qs["parentUrl"], qs["widgetId"], widgetOpts["capabilities"]);
|
||||||
|
|
||||||
|
document.getElementById("widgetHtml").innerHTML = widgetOpts['html'];
|
||||||
|
bindButtons();
|
||||||
|
} catch (e) {
|
||||||
|
console.error("[Inline Widget Wrapper] Error loading widget from URL: ", e);
|
||||||
|
document.getElementById("widgetHtml").innerText = "Failed to load widget";
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindButtons() {
|
||||||
|
const buttons = document.getElementsByTagName("button");
|
||||||
|
if (!buttons) return;
|
||||||
|
for (const button of buttons) {
|
||||||
|
button.addEventListener("click", onClick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClick(event) {
|
||||||
|
if (!event.target) return;
|
||||||
|
|
||||||
|
const action = event.target.getAttribute("data-mx-action");
|
||||||
|
if (!action) return; // TODO: Submit form or something?
|
||||||
|
|
||||||
|
const value = event.target.getAttribute("data-mx-value");
|
||||||
|
if (!value) return; // ignore - no value
|
||||||
|
|
||||||
|
if (action === "m.send_text") {
|
||||||
|
widgetApi.sendText(value);
|
||||||
|
} else if (action === "m.send_notice") {
|
||||||
|
widgetApi.sendNotice(value);
|
||||||
|
} else if (action === "m.send_hidden") {
|
||||||
|
widgetApi.sendEvent("m.room.hidden", {body: value});
|
||||||
|
} // else ignore
|
||||||
|
}
|
||||||
|
// TODO: Binding of forms, etc
|
|
@ -35,6 +35,7 @@ module.exports = (env, argv) => {
|
||||||
"indexeddb-worker": "./src/vector/indexeddb-worker.js",
|
"indexeddb-worker": "./src/vector/indexeddb-worker.js",
|
||||||
"mobileguide": "./src/vector/mobile_guide/index.js",
|
"mobileguide": "./src/vector/mobile_guide/index.js",
|
||||||
"usercontent": "./node_modules/matrix-react-sdk/src/usercontent/index.js",
|
"usercontent": "./node_modules/matrix-react-sdk/src/usercontent/index.js",
|
||||||
|
"inline-widget-wrapper": "./src/vector/inline_widget_wrapper/index.js",
|
||||||
|
|
||||||
// CSS themes
|
// CSS themes
|
||||||
"theme-light": "./node_modules/matrix-react-sdk/res/themes/light/css/light.scss",
|
"theme-light": "./node_modules/matrix-react-sdk/res/themes/light/css/light.scss",
|
||||||
|
@ -303,7 +304,7 @@ module.exports = (env, argv) => {
|
||||||
// HtmlWebpackPlugin will screw up our formatting like the names
|
// HtmlWebpackPlugin will screw up our formatting like the names
|
||||||
// of the themes and which chunks we actually care about.
|
// of the themes and which chunks we actually care about.
|
||||||
inject: false,
|
inject: false,
|
||||||
excludeChunks: ['mobileguide', 'usercontent'],
|
excludeChunks: ['mobileguide', 'usercontent', 'inline-widget-wrapper'],
|
||||||
minify: argv.mode === 'production',
|
minify: argv.mode === 'production',
|
||||||
vars: {
|
vars: {
|
||||||
og_image_url: og_image_url,
|
og_image_url: og_image_url,
|
||||||
|
@ -318,6 +319,13 @@ module.exports = (env, argv) => {
|
||||||
chunks: ['mobileguide'],
|
chunks: ['mobileguide'],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
// This is an inline widget wrapper, similar to usercontent
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: './src/vector/inline_widget_wrapper/index.html',
|
||||||
|
filename: 'inline_widget_wrapper/index.html',
|
||||||
|
chunks: ['inline-widget-wrapper'],
|
||||||
|
}),
|
||||||
|
|
||||||
// This is the usercontent sandbox's entry point (separate for iframing)
|
// This is the usercontent sandbox's entry point (separate for iframing)
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: './node_modules/matrix-react-sdk/src/usercontent/index.html',
|
template: './node_modules/matrix-react-sdk/src/usercontent/index.html',
|
||||||
|
|
19
yarn.lock
19
yarn.lock
|
@ -1834,6 +1834,11 @@ array-union@^1.0.1, array-union@^1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
array-uniq "^1.0.1"
|
array-uniq "^1.0.1"
|
||||||
|
|
||||||
|
array-uniq@1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.2.tgz#5fcc373920775723cfd64d65c64bef53bf9eba6d"
|
||||||
|
integrity sha1-X8w3OSB3VyPP1k1lxkvvU7+eum0=
|
||||||
|
|
||||||
array-uniq@^1.0.1:
|
array-uniq@^1.0.1:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
|
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
|
||||||
|
@ -9775,7 +9780,7 @@ querystring-es3@^0.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
|
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
|
||||||
integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=
|
integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=
|
||||||
|
|
||||||
querystring@0.2.0:
|
querystring@0.2.0, querystring@^0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
|
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
|
||||||
integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
|
integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
|
||||||
|
@ -9802,6 +9807,11 @@ raf@^3.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
performance-now "^2.1.0"
|
performance-now "^2.1.0"
|
||||||
|
|
||||||
|
random-string@^0.2.0:
|
||||||
|
version "0.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/random-string/-/random-string-0.2.0.tgz#a46e4375352beda9a0d7b0d19ed6d321ecd1d82d"
|
||||||
|
integrity sha1-pG5DdTUr7amg17DRntbTIezR2C0=
|
||||||
|
|
||||||
randomatic@^3.0.0:
|
randomatic@^3.0.0:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed"
|
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed"
|
||||||
|
@ -9826,6 +9836,13 @@ randomfill@^1.0.3:
|
||||||
randombytes "^2.0.5"
|
randombytes "^2.0.5"
|
||||||
safe-buffer "^5.1.0"
|
safe-buffer "^5.1.0"
|
||||||
|
|
||||||
|
randomstring@^1.1.5:
|
||||||
|
version "1.1.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/randomstring/-/randomstring-1.1.5.tgz#6df0628f75cbd5932930d9fe3ab4e956a18518c3"
|
||||||
|
integrity sha1-bfBij3XL1ZMpMNn+OrTpVqGFGMM=
|
||||||
|
dependencies:
|
||||||
|
array-uniq "1.0.2"
|
||||||
|
|
||||||
range-parser@^1.2.1, range-parser@~1.2.1:
|
range-parser@^1.2.1, range-parser@~1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
|
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
|
||||||
|
|
Loading…
Reference in New Issue