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'
|
||||
const React = require('react')
|
||||
const ReactDOM = require('react-dom')
|
||||
const create = require('create-react-class')
|
||||
'use strict';
|
||||
const React = require('react');
|
||||
const create = require('create-react-class');
|
||||
|
||||
let Event = create({
|
||||
displayName: "genericStateEvent",
|
||||
|
||||
render: function() {
|
||||
let event = this.props.event
|
||||
let event = this.props.event;
|
||||
return (
|
||||
<div className="body">
|
||||
{event.plaintext()}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
module.exports = Event
|
||||
module.exports = Event;
|
||||
|
@ -1,43 +1,39 @@
|
||||
'use strict'
|
||||
const React = require('react')
|
||||
const ReactDOM = require('react-dom')
|
||||
const create = require('create-react-class')
|
||||
const Promise = require('bluebird')
|
||||
|
||||
const riot = require('../../lib/riot-utils.js')
|
||||
'use strict';
|
||||
const React = require('react');
|
||||
const create = require('create-react-class');
|
||||
|
||||
let Event = create({
|
||||
displayName: "m.text",
|
||||
|
||||
render: function() {
|
||||
let event = this.props.event
|
||||
let formattedEvent = this.props.formattedEvent
|
||||
let event = this.props.event;
|
||||
let formattedEvent = this.props.formattedEvent;
|
||||
|
||||
let eventBody
|
||||
let eventBody;
|
||||
|
||||
if (formattedEvent.html) {
|
||||
eventBody = <div
|
||||
className="body"
|
||||
dangerouslySetInnerHTML={{__html: formattedEvent.body}}
|
||||
/>
|
||||
/>;
|
||||
} else {
|
||||
eventBody =
|
||||
<div className="body">
|
||||
{formattedEvent.body}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
|
||||
let eventClass = ""
|
||||
let eventClass = "";
|
||||
if (event.local) {
|
||||
eventClass += " local"
|
||||
eventClass += " local";
|
||||
}
|
||||
|
||||
return <div className={eventClass}>
|
||||
{eventBody}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
module.exports = Event
|
||||
module.exports = Event;
|
||||
|
@ -1,46 +1,44 @@
|
||||
'use strict'
|
||||
const React = require('react')
|
||||
const ReactDOM = require('react-dom')
|
||||
const create = require('create-react-class')
|
||||
'use strict';
|
||||
|
||||
let fileUpload = create({
|
||||
displayName: "FileUpload",
|
||||
const Promise = require("bluebird");
|
||||
const React = require('react');
|
||||
|
||||
setFileRef: function(e) {
|
||||
if (e != null) {
|
||||
e.addEventListener('change', this.startUpload)
|
||||
this.setState({
|
||||
fileRef: e
|
||||
})
|
||||
}
|
||||
},
|
||||
const withElement = require("../lib/with-element");
|
||||
const fileToDataUrl = require("../lib/file-to-data-url");
|
||||
|
||||
startUpload: function(e) {
|
||||
Array.from(e.target.files).forEach((file) => {
|
||||
module.exports = function FileUpload({ addUpload }) {
|
||||
function handleChange(event) {
|
||||
return Promise.map(Array.from(event.target.files), (file) => {
|
||||
if (file.type.startsWith("image/")) {
|
||||
let reader = new FileReader()
|
||||
reader.onloadend = () => {
|
||||
let fileObject = {
|
||||
return Promise.try(() => {
|
||||
return fileToDataUrl(file);
|
||||
}).then((url) => {
|
||||
return addUpload({
|
||||
file: file,
|
||||
preview: reader.result
|
||||
}
|
||||
this.props.addUpload(fileObject)
|
||||
}
|
||||
reader.readAsDataURL(file)
|
||||
preview: url
|
||||
});
|
||||
});
|
||||
} 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 (
|
||||
<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>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = fileUpload
|
||||
);
|
||||
};
|
||||
|
@ -1,19 +1,17 @@
|
||||
'use strict'
|
||||
const React = require('react')
|
||||
const ReactDOM = require('react-dom')
|
||||
const create = require('create-react-class')
|
||||
const Promise = require('bluebird')
|
||||
'use strict';
|
||||
const React = require('react');
|
||||
const create = require('create-react-class');
|
||||
|
||||
let info = create({
|
||||
displayName: "Info",
|
||||
render: function() {
|
||||
let title = ""
|
||||
let title = "";
|
||||
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
|
||||
|
||||
module.exports = {
|
||||
parseEvent: function(client, event, maxHeight, maxWidth) {
|
||||
if (event.content.msgtype == "m.image") {
|
||||
let h = maxHeight
|
||||
let w = maxWidth
|
||||
let h = maxHeight;
|
||||
let w = maxWidth;
|
||||
|
||||
let media_url = client.mxcUrlToHttp(event.content.url)
|
||||
let thumb_url = event.content.url
|
||||
let media_url = client.mxcUrlToHttp(event.content.url);
|
||||
let thumb_url = event.content.url;
|
||||
|
||||
if (event.content.info != 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) {
|
||||
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
|
||||
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;
|
||||
} else {
|
||||
h = (event.content.info.h < maxHeight) ? event.content.info.h : h
|
||||
w = (event.content.info.w < maxWidth) ? event.content.info.w : w
|
||||
h = (event.content.info.h < maxHeight) ? event.content.info.h : h;
|
||||
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 {
|
||||
full: media_url,
|
||||
thumb: thumb_url,
|
||||
size: {h, w}
|
||||
}
|
||||
};
|
||||
}
|
||||
if (event.content.msgtype == "m.video") {
|
||||
let thumb = null
|
||||
let h = maxHeight
|
||||
let w = maxWidth
|
||||
let thumb = null;
|
||||
let h = maxHeight;
|
||||
let w = maxWidth;
|
||||
|
||||
if (event.content.info != null) {
|
||||
if (event.content.info.thumbnail_url != null) {
|
||||
if (event.content.info.thumbnail_info != null) {
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
thumb = client.mxcUrlToHttp(event.content.thumbnail, w, h, 'scale', false)
|
||||
thumb = client.mxcUrlToHttp(event.content.thumbnail, w, h, 'scale', false);
|
||||
}
|
||||
}
|
||||
return {
|
||||
full: client.mxcUrlToHttp(event.content.url),
|
||||
thumb: thumb,
|
||||
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