Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
{
"sourceMaps": true,
"presets": [
"@babel/preset-env",
"@babel/preset-typescript"
],
"plugins": [
"@babel/plugin-proposal-class-properties"
]
"sourceMaps": true,
"presets": ["@babel/preset-env", "@babel/preset-typescript"],
"plugins": ["@babel/plugin-proposal-class-properties"]
}
50 changes: 26 additions & 24 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
module.exports = {
plugins: [
"matrix-org",
],
extends: [
"plugin:matrix-org/babel",
],
plugins: ["matrix-org"],
extends: ["plugin:matrix-org/babel"],
parserOptions: {
project: ["./tsconfig-dev.json"],
},
Expand All @@ -19,32 +15,38 @@ module.exports = {
"padded-blocks": ["warn"],
"no-extend-native": ["warn"],
"camelcase": ["warn"],
"no-multi-spaces": ["error", { "ignoreEOLComments": true }],
"space-before-function-paren": ["error", {
"anonymous": "never",
"named": "never",
"asyncArrow": "always",
}],
"no-multi-spaces": ["error", { ignoreEOLComments: true }],
"space-before-function-paren": [
"error",
{
anonymous: "never",
named: "never",
asyncArrow: "always",
},
],
"arrow-parens": "off",
"prefer-promise-reject-errors": "off",
"quotes": "off",
"indent": "off",
"no-constant-condition": "off",
"no-async-promise-executor": "off",
},
overrides: [{
"files": ["src/**/*.ts", "test/**/*.ts"],
"extends": ["plugin:matrix-org/typescript"],
"rules": {
// TypeScript has its own version of this
"babel/no-invalid-this": "off",
overrides: [
{
files: ["src/**/*.ts", "test/**/*.ts"],
extends: ["plugin:matrix-org/typescript"],
rules: {
// TypeScript has its own version of this
"babel/no-invalid-this": "off",

"quotes": "off",
"quotes": "off",
},
},
}, {
"files": ["src/interfaces/**/*.ts"],
"rules": {
"@typescript-eslint/no-empty-object-type": "off",
{
files: ["src/interfaces/**/*.ts"],
rules: {
"@typescript-eslint/no-empty-object-type": "off",
},
},
}],
],
};
2 changes: 1 addition & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: 'yarn'
cache: "yarn"

- name: Install NPM packages
run: yarn install --frozen-lockfile
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: 🔧 Set up node environment
uses: actions/setup-node@v4
with:
cache: 'yarn'
cache: "yarn"

- name: 🛠️ Setup
run: yarn install --pure-lockfile
Expand Down
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ JavaScript/TypeScript SDK for widgets & clients to communicate.

For help and support, visit [#matrix-widgets:matrix.org](https://matrix.to/#/#matrix-widgets:matrix.org) on Matrix.

*Disclaimer: Widgets are not yet in the Matrix spec, so this library may not work with other implementations.*
_Disclaimer: Widgets are not yet in the Matrix spec, so this library may not work with other implementations._

## Building

Expand Down Expand Up @@ -45,14 +45,14 @@ api.requestCapabilities(StickerpickerCapabilities);

// Add custom action handlers (if needed)
api.on(`action:${WidgetApiToWidgetAction.UpdateVisibility}`, (ev: CustomEvent<IVisibilityActionRequest>) => {
ev.preventDefault(); // we're handling it, so stop the widget API from doing something.
console.log(ev.detail); // custom handling here
api.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{});
ev.preventDefault(); // we're handling it, so stop the widget API from doing something.
console.log(ev.detail); // custom handling here
api.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{});
});
api.on("action:com.example.my_action", (ev: CustomEvent<ICustomActionRequest>) => {
ev.preventDefault(); // we're handling it, so stop the widget API from doing something.
console.log(ev.detail); // custom handling here
api.transport.reply(ev.detail, {custom: "reply"});
ev.preventDefault(); // we're handling it, so stop the widget API from doing something.
console.log(ev.detail); // custom handling here
api.transport.reply(ev.detail, { custom: "reply" });
});

// Start the messaging
Expand All @@ -63,7 +63,7 @@ api.sendContentLoaded();

// Later, do something else (if needed)
api.setAlwaysOnScreen(true);
api.transport.send("com.example.my_action", {isExample: true});
api.transport.send("com.example.my_action", { isExample: true });
```

For a more complete example, see the `examples` directory of this repo.
Expand All @@ -82,8 +82,8 @@ const api = new ClientWidgetApi(widget, iframe, driver);

// The API is automatically started, so we just have to wait for a ready before doing something
api.on("ready", () => {
api.updateVisibility(true).then(() => console.log("Widget knows it is visible now"));
api.transport.send("com.example.my_action", {isExample: true});
api.updateVisibility(true).then(() => console.log("Widget knows it is visible now"));
api.transport.send("com.example.my_action", { isExample: true });
});

// Eventually, stop the API handling
Expand Down
25 changes: 13 additions & 12 deletions examples/widget/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,26 @@
* limitations under the License.
*/

html, body {
background-color: #ffffff;
color: #000000;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
html,
body {
background-color: #ffffff;
color: #000000;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}

body {
padding: 20px;
padding: 20px;
}

button {
border: none;
color: #ffffff;
background-color: #2a9d8f;
border-radius: 4px;
padding: 6px 12px;
cursor: pointer;
border: none;
color: #ffffff;
background-color: #2a9d8f;
border-radius: 4px;
padding: 6px 12px;
cursor: pointer;
}

#stickyState {
color: #3d5a80;
color: #3d5a80;
}
62 changes: 33 additions & 29 deletions examples/widget/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<head>
<title>Example Widget</title>

<!--
Expand All @@ -42,8 +42,8 @@

<!-- CSS is just for aesthetics and not important to the example -->
<link href="index.css" rel="stylesheet" />
</head>
<body>
</head>
<body>
<!-- The widget will be loaded into this container -->
<div id="container">Loading...</div>

Expand All @@ -55,55 +55,59 @@

<!-- The actual widget functionality -->
<script type="text/javascript">
try {
try {
const qs = parseFragment();
const widgetId = assertParam(qs, 'widgetId');
const userId = assertParam(qs, 'userId');
const widgetId = assertParam(qs, "widgetId");
const userId = assertParam(qs, "userId");
// Allow all origins
const targetOrigin = '*';
const targetOrigin = "*";
let isSticky = false;

// Set up the widget API as soon as possible to avoid problems with the client
const widgetApi = new mxwidgets.WidgetApi(widgetId, targetOrigin);
widgetApi.requestCapability(mxwidgets.MatrixCapabilities.AlwaysOnScreen);

widgetApi.on("ready", function() {
// Fill in the basic widget details now that we're allowed to operate.
document.getElementById("container").innerHTML = "Hello <span id='userId'></span>!<br /><br />"
+ "Currently stuck on screen: <span id='stickyState'></span><br /><br />"
+ "<button onclick='toggleSticky()'>Toggle sticky state</button>";
widgetApi.on("ready", function () {
// Fill in the basic widget details now that we're allowed to operate.
document.getElementById("container").innerHTML =
"Hello <span id='userId'></span>!<br /><br />" +
"Currently stuck on screen: <span id='stickyState'></span><br /><br />" +
"<button onclick='toggleSticky()'>Toggle sticky state</button>";

// Fill in the user ID using innerText to avoid XSS
document.getElementById("userId").innerText = userId;
// Fill in the user ID using innerText to avoid XSS
document.getElementById("userId").innerText = userId;

// Update the UI and ensure that we end up not sticky to start
sendStickyState();
// Update the UI and ensure that we end up not sticky to start
sendStickyState();
});

// Start the widget as soon as possible too, otherwise the client might time us out.
widgetApi.start();

function toggleSticky() {
// called by the button when clicked - toggle the sticky state
isSticky = !isSticky;
sendStickyState();
// called by the button when clicked - toggle the sticky state
isSticky = !isSticky;
sendStickyState();
}

function updateStickyState() {
document.getElementById("stickyState").innerText = isSticky.toString();
document.getElementById("stickyState").innerText = isSticky.toString();
}

function sendStickyState() {
updateStickyState(); // update first to make the UI go faster than the request
widgetApi.setAlwaysOnScreen(isSticky).then(function(r) {
console.log("[Widget] Client responded with: ", r);
}).catch(function(e) {
handleError(e);
updateStickyState(); // update first to make the UI go faster than the request
widgetApi
.setAlwaysOnScreen(isSticky)
.then(function (r) {
console.log("[Widget] Client responded with: ", r);
})
.catch(function (e) {
handleError(e);
});
}
} catch (e) {
} catch (e) {
handleError(e);
}
}
</script>
</body>
</body>
</html>
4 changes: 2 additions & 2 deletions examples/widget/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
*/

function parseFragment() {
const fragmentString = (window.location.hash || "?");
return new URLSearchParams(fragmentString.substring(Math.max(fragmentString.indexOf('?'), 0)));
const fragmentString = window.location.hash || "?";
return new URLSearchParams(fragmentString.substring(Math.max(fragmentString.indexOf("?"), 0)));
}

function assertParam(fragment, name) {
Expand Down
12 changes: 6 additions & 6 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ import { env } from "process";
import type { Config } from "jest";

const config: Config = {
testEnvironment: "jsdom",
testMatch: ["<rootDir>/test/**/*-test.[jt]s?(x)"],
collectCoverageFrom: ["<rootDir>/src/**/*.{js,ts,tsx}"],
coverageReporters: ["text-summary", "lcov"],
testResultsProcessor: "@casualbot/jest-sonar-reporter",
testEnvironment: "jsdom",
testMatch: ["<rootDir>/test/**/*-test.[jt]s?(x)"],
collectCoverageFrom: ["<rootDir>/src/**/*.{js,ts,tsx}"],
coverageReporters: ["text-summary", "lcov"],
testResultsProcessor: "@casualbot/jest-sonar-reporter",
};

// if we're running under GHA, enable the GHA reporter
if (env["GITHUB_ACTIONS"] !== undefined) {
config.reporters = [["github-actions", { silent: false }], "summary"];
config.reporters = [["github-actions", { silent: false }], "summary"];
}

export default config;
20 changes: 20 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@
"lint:workflows": "find .github/workflows -type f \\( -iname '*.yaml' -o -iname '*.yml' \\) | xargs -I {} sh -c 'echo \"Linting {}\"; action-validator \"{}\"'",
"test": "jest"
},
"prettier": {
"printWidth": 120,
"tabWidth": 2,
"quoteProps": "consistent",
"trailingComma": "all",
"overrides": [
{
"files": [
"src/**/*.ts",
"*.js",
"test/**/*.ts",
"*.yml"
],
"options": {
"tabWidth": 4
}
}
]
},
"files": [
"src",
"lib",
Expand Down Expand Up @@ -59,6 +78,7 @@
"eslint-plugin-unicorn": "^56.0.0",
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
"prettier": "3.4.2",
"rimraf": "^3.0.2",
"tinyify": "^3.0.0",
"ts-node": "^10.9.1",
Expand Down
4 changes: 1 addition & 3 deletions renovate.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
]
"extends": ["config:recommended"]
}
Loading
Loading