Compare commits
14 Commits
Author | SHA1 | Date |
---|---|---|
Sven Slootweg | 25d51ef4eb | 5 years ago |
Sven Slootweg | 27dc997d70 | 5 years ago |
Sven Slootweg | 6ab1082541 | 5 years ago |
Sven Slootweg | 3cc671c87d | 5 years ago |
Sven Slootweg | 49ae582ba2 | 5 years ago |
Sven Slootweg | b33207a23c | 5 years ago |
Sven Slootweg | 89efaed81a | 5 years ago |
Sven Slootweg | 5eb2e66a15 | 5 years ago |
Sven Slootweg | ed9fd6ec46 | 5 years ago |
Sven Slootweg | 0a559317ac | 5 years ago |
Sven Slootweg | 1bc0205bbf | 5 years ago |
Sven Slootweg | aca6f3768d | 5 years ago |
Sven Slootweg | b7f794ffa6 | 5 years ago |
Sven Slootweg | 799da40524 | 5 years ago |
@ -0,0 +1,78 @@
|
|||||||
|
module.exports = {
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"commonjs": true,
|
||||||
|
"es6": true,
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"experimentalObjectRestSpread": true,
|
||||||
|
"jsx": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"react"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
/* Things that should effectively be syntax errors. */
|
||||||
|
"indent": [ "error", "tab", {
|
||||||
|
SwitchCase: 1
|
||||||
|
}],
|
||||||
|
"linebreak-style": [ "error", "unix" ],
|
||||||
|
"semi": [ "error", "always" ],
|
||||||
|
/* Things that are always mistakes. */
|
||||||
|
"getter-return": [ "error" ],
|
||||||
|
"no-compare-neg-zero": [ "error" ],
|
||||||
|
"no-dupe-args": [ "error" ],
|
||||||
|
"no-dupe-keys": [ "error" ],
|
||||||
|
"no-duplicate-case": [ "error" ],
|
||||||
|
"no-empty": [ "error" ],
|
||||||
|
"no-empty-character-class": [ "error" ],
|
||||||
|
"no-ex-assign": [ "error" ],
|
||||||
|
"no-extra-semi": [ "error" ],
|
||||||
|
"no-func-assign": [ "error" ],
|
||||||
|
"no-invalid-regexp": [ "error" ],
|
||||||
|
"no-irregular-whitespace": [ "error" ],
|
||||||
|
"no-obj-calls": [ "error" ],
|
||||||
|
"no-sparse-arrays": [ "error" ],
|
||||||
|
"no-undef": [ "error" ],
|
||||||
|
"no-unreachable": [ "error" ],
|
||||||
|
"no-unsafe-finally": [ "error" ],
|
||||||
|
"use-isnan": [ "error" ],
|
||||||
|
"valid-typeof": [ "error" ],
|
||||||
|
"curly": [ "error" ],
|
||||||
|
"no-caller": [ "error" ],
|
||||||
|
"no-fallthrough": [ "error" ],
|
||||||
|
"no-extra-bind": [ "error" ],
|
||||||
|
"no-extra-label": [ "error" ],
|
||||||
|
"array-callback-return": [ "error" ],
|
||||||
|
"prefer-promise-reject-errors": [ "error" ],
|
||||||
|
"no-with": [ "error" ],
|
||||||
|
"no-useless-concat": [ "error" ],
|
||||||
|
"no-unused-labels": [ "error" ],
|
||||||
|
"no-unused-expressions": [ "error" ],
|
||||||
|
"no-unused-vars": [ "error" , { argsIgnorePattern: "^_" } ],
|
||||||
|
"no-return-assign": [ "error" ],
|
||||||
|
"no-self-assign": [ "error" ],
|
||||||
|
"no-new-wrappers": [ "error" ],
|
||||||
|
"no-redeclare": [ "error" ],
|
||||||
|
"no-loop-func": [ "error" ],
|
||||||
|
"no-implicit-globals": [ "error" ],
|
||||||
|
"strict": [ "error", "global" ],
|
||||||
|
/* Make JSX not cause 'unused variable' errors. */
|
||||||
|
"react/jsx-uses-react": ["error"],
|
||||||
|
"react/jsx-uses-vars": ["error"],
|
||||||
|
/* Development code that should be removed before deployment. */
|
||||||
|
"no-console": [ "warn" ],
|
||||||
|
"no-constant-condition": [ "warn" ],
|
||||||
|
"no-debugger": [ "warn" ],
|
||||||
|
"no-alert": [ "warn" ],
|
||||||
|
"no-warning-comments": ["warn", {
|
||||||
|
terms: ["fixme"]
|
||||||
|
}],
|
||||||
|
/* Common mistakes that can *occasionally* be intentional. */
|
||||||
|
"no-template-curly-in-string": ["warn"],
|
||||||
|
"no-unsafe-negation": [ "warn" ],
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch debugging in Firefox",
|
||||||
|
"type": "firefox",
|
||||||
|
"request": "launch",
|
||||||
|
"reAttach": true,
|
||||||
|
"url": "http://localhost:3000/",
|
||||||
|
"webRoot": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Attach",
|
||||||
|
"type": "firefox",
|
||||||
|
"request": "attach"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Launch WebExtension",
|
||||||
|
"type": "firefox",
|
||||||
|
"request": "launch",
|
||||||
|
"reAttach": true,
|
||||||
|
"addonPath": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,19 +1,18 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
const React = require('react')
|
const React = require('react');
|
||||||
const ReactDOM = require('react-dom')
|
const create = require('create-react-class');
|
||||||
const create = require('create-react-class')
|
|
||||||
|
|
||||||
let Event = create({
|
let Event = create({
|
||||||
displayName: "genericStateEvent",
|
displayName: "genericStateEvent",
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
let event = this.props.event
|
let event = this.props.event;
|
||||||
return (
|
return (
|
||||||
<div className="body">
|
<div className="body">
|
||||||
{event.plaintext()}
|
{event.plaintext()}
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
module.exports = Event
|
module.exports = Event;
|
||||||
|
@ -1,43 +1,39 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
const React = require('react')
|
const React = require('react');
|
||||||
const ReactDOM = require('react-dom')
|
const create = require('create-react-class');
|
||||||
const create = require('create-react-class')
|
|
||||||
const Promise = require('bluebird')
|
|
||||||
|
|
||||||
const riot = require('../../lib/riot-utils.js')
|
|
||||||
|
|
||||||
let Event = create({
|
let Event = create({
|
||||||
displayName: "m.text",
|
displayName: "m.text",
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
let event = this.props.event
|
let event = this.props.event;
|
||||||
let formattedEvent = this.props.formattedEvent
|
let formattedEvent = this.props.formattedEvent;
|
||||||
|
|
||||||
let eventBody
|
let eventBody;
|
||||||
|
|
||||||
if (formattedEvent.html) {
|
if (formattedEvent.html) {
|
||||||
eventBody = <div
|
eventBody = <div
|
||||||
className="body"
|
className="body"
|
||||||
dangerouslySetInnerHTML={{__html: formattedEvent.body}}
|
dangerouslySetInnerHTML={{__html: formattedEvent.body}}
|
||||||
/>
|
/>;
|
||||||
} else {
|
} else {
|
||||||
eventBody =
|
eventBody =
|
||||||
<div className="body">
|
<div className="body">
|
||||||
{formattedEvent.body}
|
{formattedEvent.body}
|
||||||
</div>
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let eventClass = ""
|
let eventClass = "";
|
||||||
if (event.local) {
|
if (event.local) {
|
||||||
eventClass += " local"
|
eventClass += " local";
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className={eventClass}>
|
return <div className={eventClass}>
|
||||||
{eventBody}
|
{eventBody}
|
||||||
</div>
|
</div>;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
module.exports = Event
|
module.exports = Event;
|
||||||
|
@ -1,46 +1,44 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
const React = require('react')
|
|
||||||
const ReactDOM = require('react-dom')
|
|
||||||
const create = require('create-react-class')
|
|
||||||
|
|
||||||
let fileUpload = create({
|
const Promise = require("bluebird");
|
||||||
displayName: "FileUpload",
|
const React = require('react');
|
||||||
|
|
||||||
setFileRef: function(e) {
|
const withElement = require("../lib/with-element");
|
||||||
if (e != null) {
|
const fileToDataUrl = require("../lib/file-to-data-url");
|
||||||
e.addEventListener('change', this.startUpload)
|
|
||||||
this.setState({
|
|
||||||
fileRef: e
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
startUpload: function(e) {
|
module.exports = function FileUpload({ addUpload }) {
|
||||||
Array.from(e.target.files).forEach((file) => {
|
function handleChange(event) {
|
||||||
|
return Promise.map(Array.from(event.target.files), (file) => {
|
||||||
if (file.type.startsWith("image/")) {
|
if (file.type.startsWith("image/")) {
|
||||||
let reader = new FileReader()
|
return Promise.try(() => {
|
||||||
reader.onloadend = () => {
|
return fileToDataUrl(file);
|
||||||
let fileObject = {
|
}).then((url) => {
|
||||||
|
return addUpload({
|
||||||
file: file,
|
file: file,
|
||||||
preview: reader.result
|
preview: url
|
||||||
}
|
});
|
||||||
this.props.addUpload(fileObject)
|
});
|
||||||
}
|
|
||||||
reader.readAsDataURL(file)
|
|
||||||
} else {
|
} else {
|
||||||
this.props.addUpload({file: file, preview: "/icons/file.svg"})
|
return addUpload({
|
||||||
|
file: file,
|
||||||
|
preview: "/icons/file.svg"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
let setFileRef = withElement((element) => {
|
||||||
|
element.addEventListener("change", handleChange);
|
||||||
|
|
||||||
|
return function() {
|
||||||
|
element.removeEventListener("change", handleChange);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fileUpload">
|
<div className="fileUpload">
|
||||||
<input type="file" id="fileUpload" multiple ref={this.setFileRef} />
|
<input type="file" id="fileUpload" multiple ref={setFileRef} />
|
||||||
<label htmlFor="fileUpload"><img src="/icons/file.svg"/></label>
|
<label htmlFor="fileUpload"><img src="/icons/file.svg"/></label>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
})
|
|
||||||
|
|
||||||
module.exports = fileUpload
|
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
const React = require('react')
|
const React = require('react');
|
||||||
const ReactDOM = require('react-dom')
|
const create = require('create-react-class');
|
||||||
const create = require('create-react-class')
|
|
||||||
const Promise = require('bluebird')
|
|
||||||
|
|
||||||
let info = create({
|
let info = create({
|
||||||
displayName: "Info",
|
displayName: "Info",
|
||||||
render: function() {
|
render: function() {
|
||||||
let title = ""
|
let title = "";
|
||||||
if (this.props.room != undefined) {
|
if (this.props.room != undefined) {
|
||||||
title = this.props.room.name
|
title = this.props.room.name;
|
||||||
}
|
}
|
||||||
return <div className="info">{title}</div>
|
return <div className="info">{title}</div>;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
module.exports = info
|
module.exports = info;
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const Promise = require("bluebird");
|
||||||
|
|
||||||
|
module.exports = function createApiRequester(apiUrl) {
|
||||||
|
return function apiRequest(path, body) {
|
||||||
|
return Promise.try(() => {
|
||||||
|
let targetUrl = apiUrl + path;
|
||||||
|
|
||||||
|
return Promise.try(() => {
|
||||||
|
return fetch(targetUrl, {
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json'
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
});
|
||||||
|
}).then((response) => {
|
||||||
|
if (response.status >= 200 && response.status < 400) {
|
||||||
|
return response.json();
|
||||||
|
} else {
|
||||||
|
throw new Error(`Non-200 response code for ${targetUrl}: ${response.status}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,19 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const Promise = require("bluebird");
|
||||||
|
|
||||||
|
module.exports = function readFileAsDataUrl(dataUrl) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onload = function(event) {
|
||||||
|
resolve(event.target.result);
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.onerror = function(error) {
|
||||||
|
reject(error);
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsDataURL(dataUrl);
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,49 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const jdenticon = require("jdenticon");
|
||||||
|
const defaultValue = require("default-value");
|
||||||
|
|
||||||
|
module.exports = function generateJdenticon(name) {
|
||||||
|
function setConfig() {
|
||||||
|
/* NOTE: This is a hack to ensure that any other code using the `jdenticon` library can't mess with our config, since it's set globally. This function gets called prior to *every* jdenticon-generating operation. */
|
||||||
|
jdenticon.config = {
|
||||||
|
lightness: {
|
||||||
|
color: [0.58, 0.66],
|
||||||
|
grayscale: [0.30, 0.90]
|
||||||
|
},
|
||||||
|
saturation: {
|
||||||
|
color: 0.66,
|
||||||
|
grayscale: 0.00
|
||||||
|
},
|
||||||
|
backColor: "#00000000"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
toSvg: function (size) {
|
||||||
|
setConfig();
|
||||||
|
|
||||||
|
return jdenticon.toSvg(name, size);
|
||||||
|
},
|
||||||
|
primaryColor: function () {
|
||||||
|
let svg = this.toSvg();
|
||||||
|
|
||||||
|
let color = svg.match(/#([a-f0-9]{6})/g).find((candidate) => {
|
||||||
|
let r = candidate.substr(1, 2);
|
||||||
|
let g = candidate.substr(3, 2);
|
||||||
|
let b = candidate.substr(5, 2);
|
||||||
|
|
||||||
|
let isGrayScale = (r === g && g === b);
|
||||||
|
|
||||||
|
return !isGrayScale;
|
||||||
|
});
|
||||||
|
|
||||||
|
return defaultValue(color, "#ff0000");
|
||||||
|
},
|
||||||
|
update: function (element) {
|
||||||
|
setConfig();
|
||||||
|
|
||||||
|
jdenticon.update(element, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,15 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { validateOptions, required, isNumber, isString } = require("validatem");
|
||||||
|
const isMXC = require("./validate/is-mxc");
|
||||||
|
|
||||||
|
module.exports = function generateThumbnailUrl({homeserver, mxc, width, height }) {
|
||||||
|
validateOptions(arguments, {
|
||||||
|
homeserver: [ required, isString ],
|
||||||
|
mxc: [ required, isMXC ],
|
||||||
|
width: [ required, isNumber ],
|
||||||
|
height: [ required, isNumber ]
|
||||||
|
});
|
||||||
|
|
||||||
|
return `${homeserver}/_matrix/media/v1/thumbnail/${mxc.homeserver}/${mxc.id}?width=${width}&height=${height}&method=scale`;
|
||||||
|
};
|
@ -0,0 +1,34 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
module.exports = function groupEvents(events) {
|
||||||
|
let currentSender = "";
|
||||||
|
let currentType = "";
|
||||||
|
let currentEvents = [];
|
||||||
|
let eventGroups = [];
|
||||||
|
|
||||||
|
function finalizeGroup() {
|
||||||
|
if (currentEvents.length > 0) {
|
||||||
|
eventGroups.push({
|
||||||
|
sender: currentSender,
|
||||||
|
events: currentEvents
|
||||||
|
});
|
||||||
|
|
||||||
|
currentEvents = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
events.forEach((event) => {
|
||||||
|
/* TODO: Eventually group multiple non-message events from a single user into a single event item as well, even when they are of different types */
|
||||||
|
if (event.sender !== currentSender || event.type !== currentType) {
|
||||||
|
finalizeGroup();
|
||||||
|
currentSender = event.sender;
|
||||||
|
currentType = event.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentEvents.push(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
finalizeGroup();
|
||||||
|
|
||||||
|
return eventGroups;
|
||||||
|
};
|
@ -1,56 +1,58 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
// should be able to handle images, stickers, and video
|
// should be able to handle images, stickers, and video
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
parseEvent: function(client, event, maxHeight, maxWidth) {
|
parseEvent: function(client, event, maxHeight, maxWidth) {
|
||||||
if (event.content.msgtype == "m.image") {
|
if (event.content.msgtype == "m.image") {
|
||||||
let h = maxHeight
|
let h = maxHeight;
|
||||||
let w = maxWidth
|
let w = maxWidth;
|
||||||
|
|
||||||
let media_url = client.mxcUrlToHttp(event.content.url)
|
let media_url = client.mxcUrlToHttp(event.content.url);
|
||||||
let thumb_url = event.content.url
|
let thumb_url = event.content.url;
|
||||||
|
|
||||||
if (event.content.info != null) {
|
if (event.content.info != null) {
|
||||||
if (event.content.info.thumbnail_url != null) {
|
if (event.content.info.thumbnail_url != null) {
|
||||||
thumb_url = event.content.info.thumbnail_url
|
thumb_url = event.content.info.thumbnail_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.content.info.thumbnail_info != null) {
|
if (event.content.info.thumbnail_info != null) {
|
||||||
h = (event.content.info.thumbnail_info.h < maxHeight) ? event.content.info.thumbnail_info.h : h
|
h = (event.content.info.thumbnail_info.h < maxHeight) ? event.content.info.thumbnail_info.h : h;
|
||||||
w = (event.content.info.thumbnail_info.w < maxWidth) ? event.content.info.thumbnail_info.w : w
|
w = (event.content.info.thumbnail_info.w < maxWidth) ? event.content.info.thumbnail_info.w : w;
|
||||||
} else {
|
} else {
|
||||||
h = (event.content.info.h < maxHeight) ? event.content.info.h : h
|
h = (event.content.info.h < maxHeight) ? event.content.info.h : h;
|
||||||
w = (event.content.info.w < maxWidth) ? event.content.info.w : w
|
w = (event.content.info.w < maxWidth) ? event.content.info.w : w;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
thumb_url = client.mxcUrlToHttp(thumb_url, w, h, 'scale', false)
|
thumb_url = client.mxcUrlToHttp(thumb_url, w, h, 'scale', false);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
full: media_url,
|
full: media_url,
|
||||||
thumb: thumb_url,
|
thumb: thumb_url,
|
||||||
size: {h, w}
|
size: {h, w}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
if (event.content.msgtype == "m.video") {
|
if (event.content.msgtype == "m.video") {
|
||||||
let thumb = null
|
let thumb = null;
|
||||||
let h = maxHeight
|
let h = maxHeight;
|
||||||
let w = maxWidth
|
let w = maxWidth;
|
||||||
|
|
||||||
if (event.content.info != null) {
|
if (event.content.info != null) {
|
||||||
if (event.content.info.thumbnail_url != null) {
|
if (event.content.info.thumbnail_url != null) {
|
||||||
if (event.content.info.thumbnail_info != null) {
|
if (event.content.info.thumbnail_info != null) {
|
||||||
h = (event.content.info.thumbnail_info.h < maxHeight) ? event.content.info.thumbnail_info.h : h
|
h = (event.content.info.thumbnail_info.h < maxHeight) ? event.content.info.thumbnail_info.h : h;
|
||||||
w = (event.content.info.thumbnail_info.w < maxWidth) ? event.content.info.thumbnail_info.w : w
|
w = (event.content.info.thumbnail_info.w < maxWidth) ? event.content.info.thumbnail_info.w : w;
|
||||||
}
|
}
|
||||||
|
|
||||||
thumb = client.mxcUrlToHttp(event.content.thumbnail, w, h, 'scale', false)
|
thumb = client.mxcUrlToHttp(event.content.thumbnail, w, h, 'scale', false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
full: client.mxcUrlToHttp(event.content.url),
|
full: client.mxcUrlToHttp(event.content.url),
|
||||||
thumb: thumb,
|
thumb: thumb,
|
||||||
size: {h, w}
|
size: {h, w}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const urlLib = require("url");
|
||||||
|
|
||||||
|
module.exports = function parseMXC(uri) {
|
||||||
|
let parsed = urlLib.parse(uri);
|
||||||
|
|
||||||
|
if (parsed.protocol === "mxc:" && parsed.slashes === true) {
|
||||||
|
return {
|
||||||
|
homeserver: parsed.host,
|
||||||
|
id: parsed.pathname.replace(/^\/+/, "")
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
throw new Error("Specified URI is not an MXC URI");
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,7 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
module.exports = function isMXC(value) {
|
||||||
|
if (value.homeserver == null || value.id == null) {
|
||||||
|
throw new Error("Must be an MXC object");
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,15 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const React = require("react");
|
||||||
|
|
||||||
|
module.exports = function withElement(callback) {
|
||||||
|
let [ elementRef, setElementRef ] = React.useState();
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (elementRef != null) {
|
||||||
|
callback(elementRef);
|
||||||
|
}
|
||||||
|
}, [ elementRef ]);
|
||||||
|
|
||||||
|
return setElementRef;
|
||||||
|
};
|
Loading…
Reference in New Issue