forked from mystiq/hydrogen-web
replace usage of readPath with ?.
This commit is contained in:
parent
6813fd2264
commit
2526198251
5 changed files with 19 additions and 142 deletions
|
@ -15,7 +15,6 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {MessageTile} from "./MessageTile.js";
|
import {MessageTile} from "./MessageTile.js";
|
||||||
import {readPath, Type} from "../../../../../utils/validate.js";
|
|
||||||
|
|
||||||
const MAX_HEIGHT = 300;
|
const MAX_HEIGHT = 300;
|
||||||
const MAX_WIDTH = 400;
|
const MAX_WIDTH = 400;
|
||||||
|
@ -27,40 +26,38 @@ export class ImageTile extends MessageTile {
|
||||||
}
|
}
|
||||||
|
|
||||||
get thumbnailUrl() {
|
get thumbnailUrl() {
|
||||||
try {
|
const mxcUrl = this._getContent()?.url;
|
||||||
const mxcUrl = readPath(this._getContent(), ["url"], Type.String);
|
if (typeof mxcUrl === "string") {
|
||||||
return this._room.mxcUrlThumbnail(mxcUrl, this.thumbnailWidth, this.thumbnailHeight, "scale");
|
return this._room.mxcUrlThumbnail(mxcUrl, this.thumbnailWidth, this.thumbnailHeight, "scale");
|
||||||
} catch (err) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
get url() {
|
get url() {
|
||||||
try {
|
const mxcUrl = this._getContent()?.url;
|
||||||
const mxcUrl = readPath(this._getContent(), ["url"], Type.String);
|
if (typeof mxcUrl === "string") {
|
||||||
return this._room.mxcUrl(mxcUrl);
|
return this._room.mxcUrl(mxcUrl);
|
||||||
} catch (err) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
_scaleFactor() {
|
_scaleFactor() {
|
||||||
const {info} = this._getContent();
|
const info = this._getContent()?.info;
|
||||||
const scaleHeightFactor = MAX_HEIGHT / info.h;
|
const scaleHeightFactor = MAX_HEIGHT / info?.h;
|
||||||
const scaleWidthFactor = MAX_WIDTH / info.w;
|
const scaleWidthFactor = MAX_WIDTH / info?.w;
|
||||||
// take the smallest scale factor, to respect all constraints
|
// take the smallest scale factor, to respect all constraints
|
||||||
// we should not upscale images, so limit scale factor to 1 upwards
|
// we should not upscale images, so limit scale factor to 1 upwards
|
||||||
return Math.min(scaleWidthFactor, scaleHeightFactor, 1);
|
return Math.min(scaleWidthFactor, scaleHeightFactor, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
get thumbnailWidth() {
|
get thumbnailWidth() {
|
||||||
const {info} = this._getContent();
|
const info = this._getContent()?.info;
|
||||||
return Math.round(info.w * this._scaleFactor());
|
return Math.round(info?.w * this._scaleFactor());
|
||||||
}
|
}
|
||||||
|
|
||||||
get thumbnailHeight() {
|
get thumbnailHeight() {
|
||||||
const {info} = this._getContent();
|
const info = this._getContent()?.info;
|
||||||
return Math.round(info.h * this._scaleFactor());
|
return Math.round(info?.h * this._scaleFactor());
|
||||||
}
|
}
|
||||||
|
|
||||||
get label() {
|
get label() {
|
||||||
|
|
|
@ -18,7 +18,6 @@ limitations under the License.
|
||||||
import {AbortError} from "./error.js";
|
import {AbortError} from "./error.js";
|
||||||
import {ObservableValue} from "../observable/ObservableValue.js";
|
import {ObservableValue} from "../observable/ObservableValue.js";
|
||||||
import {createEnum} from "../utils/enum.js";
|
import {createEnum} from "../utils/enum.js";
|
||||||
import {readPath, Type} from "../utils/validate.js";
|
|
||||||
|
|
||||||
const INCREMENTAL_TIMEOUT = 30000;
|
const INCREMENTAL_TIMEOUT = 30000;
|
||||||
const SYNC_EVENT_LIMIT = 10;
|
const SYNC_EVENT_LIMIT = 10;
|
||||||
|
@ -47,8 +46,8 @@ function parseRooms(roomsSection, roomCallback) {
|
||||||
|
|
||||||
function timelineIsEmpty(roomResponse) {
|
function timelineIsEmpty(roomResponse) {
|
||||||
try {
|
try {
|
||||||
const events = readPath(roomResponse, ["timeline", "events"], Type.Array);
|
const events = roomResponse?.timeline?.events;
|
||||||
return events.length === 0;
|
return Array.isArray(events) && events.length === 0;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,7 @@ export class EventEntry extends BaseEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
get prevContent() {
|
get prevContent() {
|
||||||
const unsigned = this._eventEntry.event.unsigned;
|
return this._eventEntry.event.unsigned?.prev_content;
|
||||||
return unsigned && unsigned.prev_content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get eventType() {
|
get eventType() {
|
||||||
|
|
|
@ -15,13 +15,12 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { StorageError } from "../common.js";
|
import { StorageError } from "../common.js";
|
||||||
import { readPath } from "../../../utils/validate.js";
|
|
||||||
|
|
||||||
class WrappedDOMException extends StorageError {
|
class WrappedDOMException extends StorageError {
|
||||||
constructor(request) {
|
constructor(request) {
|
||||||
// protect against browsers not implementing any of these properties by using readPath
|
const source = request?.source;
|
||||||
const storeName = readPath(request, ["source", "name"], "<unknown store>");
|
const storeName = source?.name || "<unknown store>";
|
||||||
const databaseName = readPath(request, ["source", "transaction", "db", "name"], "<unknown db>");
|
const databaseName = source?.transaction?.db?.name || "<unknown db>";
|
||||||
super(`Failed IDBRequest on ${databaseName}.${storeName}`, request.error);
|
super(`Failed IDBRequest on ${databaseName}.${storeName}`, request.error);
|
||||||
this.storeName = storeName;
|
this.storeName = storeName;
|
||||||
this.databaseName = databaseName;
|
this.databaseName = databaseName;
|
||||||
|
|
|
@ -1,117 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export class InvalidPathError extends Error {
|
|
||||||
constructor(obj, path, field) {
|
|
||||||
super(`Could not read path ${path.join("/")}, stopped at ${field}. Base value is ${obj}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
get name() {
|
|
||||||
return "InvalidPathError";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class InvalidTypeError extends Error {
|
|
||||||
constructor(path, fieldValue, validator) {
|
|
||||||
super(`Value ${path.join("/")} is not of type ${getTypeName(validator)} but is: ${fieldValue}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
get name() {
|
|
||||||
return "InvalidTypeError";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTypeName(validator) {
|
|
||||||
if (validator === Type.Array) {
|
|
||||||
return "Array";
|
|
||||||
}
|
|
||||||
if (validator === Type.Integer) {
|
|
||||||
return "Integer";
|
|
||||||
}
|
|
||||||
if (validator === Type.String) {
|
|
||||||
return "String";
|
|
||||||
}
|
|
||||||
if (validator === Type.Object) {
|
|
||||||
return "Object";
|
|
||||||
}
|
|
||||||
if (typeof validator === "function") {
|
|
||||||
return "Custom";
|
|
||||||
}
|
|
||||||
return "None";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readPath(obj, path, typeOrDefaultValue) {
|
|
||||||
if (!obj) {
|
|
||||||
throw new InvalidPathError(obj, path);
|
|
||||||
}
|
|
||||||
const hasDefaultValue = typeof typeOrDefaultValue !== "function";
|
|
||||||
let currentValue = obj;
|
|
||||||
for (const field of path) {
|
|
||||||
currentValue = currentValue[field];
|
|
||||||
if (typeof currentValue === "undefined") {
|
|
||||||
if (hasDefaultValue) {
|
|
||||||
return typeOrDefaultValue;
|
|
||||||
} else {
|
|
||||||
throw new InvalidPathError(obj, path, field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!hasDefaultValue) {
|
|
||||||
const validator = typeOrDefaultValue;
|
|
||||||
if (!validator(currentValue)) {
|
|
||||||
throw new InvalidTypeError(path, currentValue, validator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return currentValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Type = Object.freeze({
|
|
||||||
"Array": Array.isArray,
|
|
||||||
"Integer": Number.isSafeInteger,
|
|
||||||
"Boolean": value => value === true || value === false,
|
|
||||||
"String": value => typeof value === "string",
|
|
||||||
"Object": value => value !== null && typeof value === "object",
|
|
||||||
});
|
|
||||||
|
|
||||||
export function tests() {
|
|
||||||
return {
|
|
||||||
"readPath value at top level": assert => {
|
|
||||||
assert.strictEqual(readPath({a: 5}, ["a"]), 5);
|
|
||||||
},
|
|
||||||
"readPath value at deep level": assert => {
|
|
||||||
assert.strictEqual(readPath({a: {b: {c: 5}}}, ["a", "b", "c"]), 5);
|
|
||||||
},
|
|
||||||
"readPath value with correct type": assert => {
|
|
||||||
assert.strictEqual(readPath({a: 5}, ["a"], Type.Integer), 5);
|
|
||||||
},
|
|
||||||
"readPath value with failing type": assert => {
|
|
||||||
assert.throws(
|
|
||||||
() => readPath({a: 5}, ["a"], Type.String),
|
|
||||||
{name: "InvalidTypeError"}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
"readPath value with failing path with intermediate field not being an object": assert => {
|
|
||||||
assert.throws(
|
|
||||||
() => readPath({a: {b: "bar"}}, ["a", "b", "c"], Type.Integer),
|
|
||||||
{name: "InvalidPathError"}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
"readPath returns default value for incomplete path": assert => {
|
|
||||||
assert.strictEqual(readPath({a: {b: "bar"}}, ["a", "b", "c"], 5), 5);
|
|
||||||
},
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue