make gifs animate on hover
This commit is contained in:
parent
25817fdaba
commit
4a9a17814e
10 changed files with 127 additions and 47 deletions
|
@ -102,7 +102,7 @@ class Direct extends Guild {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("flexltr", "liststyle");
|
div.classList.add("flexltr", "liststyle");
|
||||||
user.bind(div);
|
user.bind(div);
|
||||||
div.append(user.buildpfp());
|
div.append(user.buildpfp(undefined, div));
|
||||||
|
|
||||||
const userinfos = document.createElement("div");
|
const userinfos = document.createElement("div");
|
||||||
userinfos.classList.add("flexttb");
|
userinfos.classList.add("flexttb");
|
||||||
|
@ -417,7 +417,7 @@ class Group extends Channel {
|
||||||
const myhtml = document.createElement("span");
|
const myhtml = document.createElement("span");
|
||||||
myhtml.classList.add("ellipsis");
|
myhtml.classList.add("ellipsis");
|
||||||
myhtml.textContent = this.name;
|
myhtml.textContent = this.name;
|
||||||
div.appendChild(this.user.buildpfp());
|
div.appendChild(this.user.buildpfp(undefined, div));
|
||||||
div.appendChild(myhtml);
|
div.appendChild(myhtml);
|
||||||
(div as any).myinfo = this;
|
(div as any).myinfo = this;
|
||||||
div.onclick = (_) => {
|
div.onclick = (_) => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Message} from "./message.js";
|
import {Message} from "./message.js";
|
||||||
import {MarkDown} from "./markdown.js";
|
import {MarkDown} from "./markdown.js";
|
||||||
import {embedjson, invitejson} from "./jsontypes.js";
|
import {embedjson, invitejson} from "./jsontypes.js";
|
||||||
import {getapiurls, getBulkUsers, getInstances, Specialuser} from "./utils/utils.js";
|
import {createImg, getapiurls, getBulkUsers, getInstances, Specialuser} from "./utils/utils.js";
|
||||||
import {Guild} from "./guild.js";
|
import {Guild} from "./guild.js";
|
||||||
import {I18n} from "./i18n.js";
|
import {I18n} from "./i18n.js";
|
||||||
import {ImagesDisplay} from "./disimg.js";
|
import {ImagesDisplay} from "./disimg.js";
|
||||||
|
@ -171,7 +171,7 @@ class Embed {
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
generateImage() {
|
generateImage() {
|
||||||
const img = document.createElement("img");
|
const img = createImg(this.json.thumbnail.proxy_url);
|
||||||
img.classList.add("messageimg");
|
img.classList.add("messageimg");
|
||||||
img.onclick = function () {
|
img.onclick = function () {
|
||||||
const full = new ImagesDisplay([
|
const full = new ImagesDisplay([
|
||||||
|
@ -179,7 +179,6 @@ class Embed {
|
||||||
]);
|
]);
|
||||||
full.show();
|
full.show();
|
||||||
};
|
};
|
||||||
img.src = this.json.thumbnail.proxy_url;
|
|
||||||
if (this.json.thumbnail.width) {
|
if (this.json.thumbnail.width) {
|
||||||
let scale = 1;
|
let scale = 1;
|
||||||
const max = 96 * 3;
|
const max = 96 * 3;
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {filejson} from "./jsontypes.js";
|
||||||
import {ImagesDisplay} from "./disimg.js";
|
import {ImagesDisplay} from "./disimg.js";
|
||||||
import {makePlayBox, MediaPlayer} from "./media.js";
|
import {makePlayBox, MediaPlayer} from "./media.js";
|
||||||
import {I18n} from "./i18n.js";
|
import {I18n} from "./i18n.js";
|
||||||
|
import {createImg} from "./utils/utils.js";
|
||||||
class File {
|
class File {
|
||||||
owner: Message | null;
|
owner: Message | null;
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -47,9 +48,10 @@ class File {
|
||||||
this.width /= scale;
|
this.width /= scale;
|
||||||
this.height /= scale;
|
this.height /= scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.content_type.startsWith("image/")) {
|
if (this.content_type.startsWith("image/")) {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
const img = document.createElement("img");
|
const img = createImg(src);
|
||||||
if (!fullScreen) {
|
if (!fullScreen) {
|
||||||
img.classList.add("messageimg");
|
img.classList.add("messageimg");
|
||||||
div.classList.add("messageimgdiv");
|
div.classList.add("messageimgdiv");
|
||||||
|
@ -66,7 +68,6 @@ class File {
|
||||||
full.show();
|
full.show();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
img.src = src;
|
|
||||||
div.append(img);
|
div.append(img);
|
||||||
if (this.width && !fullScreen) {
|
if (this.width && !fullScreen) {
|
||||||
div.style.maxWidth = this.width + "px";
|
div.style.maxWidth = this.width + "px";
|
||||||
|
|
|
@ -19,6 +19,7 @@ import {User} from "./user.js";
|
||||||
import {I18n} from "./i18n.js";
|
import {I18n} from "./i18n.js";
|
||||||
import {Emoji} from "./emoji.js";
|
import {Emoji} from "./emoji.js";
|
||||||
import {webhookMenu} from "./webhooks.js";
|
import {webhookMenu} from "./webhooks.js";
|
||||||
|
import {createImg} from "./utils/utils.js";
|
||||||
|
|
||||||
class Guild extends SnowFlake {
|
class Guild extends SnowFlake {
|
||||||
owner!: Localuser;
|
owner!: Localuser;
|
||||||
|
@ -745,9 +746,8 @@ class Guild extends SnowFlake {
|
||||||
icon = guild.icon;
|
icon = guild.icon;
|
||||||
}
|
}
|
||||||
if (icon !== null) {
|
if (icon !== null) {
|
||||||
const img = document.createElement("img");
|
const img = createImg(guild.info.cdn + "/icons/" + guild.id + "/" + icon + ".png");
|
||||||
img.classList.add("pfp", "servericon");
|
img.classList.add("pfp", "servericon");
|
||||||
img.src = guild.info.cdn + "/icons/" + guild.id + "/" + icon + ".png";
|
|
||||||
divy.appendChild(img);
|
divy.appendChild(img);
|
||||||
if (guild instanceof Guild) {
|
if (guild instanceof Guild) {
|
||||||
img.onclick = () => {
|
img.onclick = () => {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {Channel} from "./channel.js";
|
||||||
import {Direct} from "./direct.js";
|
import {Direct} from "./direct.js";
|
||||||
import {AVoice} from "./audio/voice.js";
|
import {AVoice} from "./audio/voice.js";
|
||||||
import {User} from "./user.js";
|
import {User} from "./user.js";
|
||||||
import {getapiurls, getBulkUsers, SW} from "./utils/utils.js";
|
import {createImg, getapiurls, getBulkUsers, SW} from "./utils/utils.js";
|
||||||
import {getBulkInfo, setTheme, Specialuser} from "./utils/utils.js";
|
import {getBulkInfo, setTheme, Specialuser} from "./utils/utils.js";
|
||||||
import {
|
import {
|
||||||
channeljson,
|
channeljson,
|
||||||
|
@ -88,8 +88,7 @@ class Localuser {
|
||||||
const userInfo = document.createElement("div");
|
const userInfo = document.createElement("div");
|
||||||
userInfo.classList.add("flexltr", "switchtable");
|
userInfo.classList.add("flexltr", "switchtable");
|
||||||
|
|
||||||
const pfp = document.createElement("img");
|
const pfp = createImg(specialUser.pfpsrc);
|
||||||
pfp.src = specialUser.pfpsrc;
|
|
||||||
pfp.classList.add("pfp");
|
pfp.classList.add("pfp");
|
||||||
userInfo.append(pfp);
|
userInfo.append(pfp);
|
||||||
|
|
||||||
|
@ -1244,24 +1243,26 @@ class Localuser {
|
||||||
content.classList.add("discovery-guild");
|
content.classList.add("discovery-guild");
|
||||||
|
|
||||||
if (guild.banner) {
|
if (guild.banner) {
|
||||||
const banner = document.createElement("img");
|
const banner = createImg(
|
||||||
|
this.info.cdn + "/icons/" + guild.id + "/" + guild.banner + ".png?size=256",
|
||||||
|
);
|
||||||
banner.classList.add("banner");
|
banner.classList.add("banner");
|
||||||
banner.crossOrigin = "anonymous";
|
banner.crossOrigin = "anonymous";
|
||||||
banner.src = this.info.cdn + "/icons/" + guild.id + "/" + guild.banner + ".png?size=256";
|
|
||||||
banner.alt = "";
|
banner.alt = "";
|
||||||
content.appendChild(banner);
|
content.appendChild(banner);
|
||||||
}
|
}
|
||||||
|
|
||||||
const nameContainer = document.createElement("div");
|
const nameContainer = document.createElement("div");
|
||||||
nameContainer.classList.add("flex");
|
nameContainer.classList.add("flex");
|
||||||
const img = document.createElement("img");
|
const img = createImg(
|
||||||
|
this.info.cdn +
|
||||||
|
(guild.icon
|
||||||
|
? "/icons/" + guild.id + "/" + guild.icon + ".png?size=48"
|
||||||
|
: "/embed/avatars/3.png"),
|
||||||
|
);
|
||||||
img.classList.add("icon");
|
img.classList.add("icon");
|
||||||
img.crossOrigin = "anonymous";
|
img.crossOrigin = "anonymous";
|
||||||
img.src =
|
|
||||||
this.info.cdn +
|
|
||||||
(guild.icon
|
|
||||||
? "/icons/" + guild.id + "/" + guild.icon + ".png?size=48"
|
|
||||||
: "/embed/avatars/3.png");
|
|
||||||
img.alt = "";
|
img.alt = "";
|
||||||
nameContainer.appendChild(img);
|
nameContainer.appendChild(img);
|
||||||
|
|
||||||
|
@ -1797,6 +1798,20 @@ class Localuser {
|
||||||
initState: !this.perminfo.user.disableColors,
|
initState: !this.perminfo.user.disableColors,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
const gifSettings = ["hover", "always", "never"] as const;
|
||||||
|
accessibility.addSelect(
|
||||||
|
I18n.accessibility.playGif(),
|
||||||
|
(i) => {
|
||||||
|
localStorage.setItem("gifSetting", gifSettings[i]);
|
||||||
|
},
|
||||||
|
gifSettings.map((_) => I18n.accessibility.gifSettings[_]()),
|
||||||
|
{
|
||||||
|
defaultIndex:
|
||||||
|
((gifSettings as readonly string[]).indexOf(
|
||||||
|
localStorage.getItem("gifSetting") as string,
|
||||||
|
) + 1 || 1) - 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const connections = settings.addButton(I18n.getTranslation("localuser.connections"));
|
const connections = settings.addButton(I18n.getTranslation("localuser.connections"));
|
||||||
|
@ -1891,15 +1906,14 @@ class Localuser {
|
||||||
const container = document.createElement("div");
|
const container = document.createElement("div");
|
||||||
|
|
||||||
if (application.cover_image || application.icon) {
|
if (application.cover_image || application.icon) {
|
||||||
const cover = document.createElement("img");
|
const cover = createImg(
|
||||||
cover.crossOrigin = "anonymous";
|
|
||||||
cover.src =
|
|
||||||
this.info.cdn +
|
this.info.cdn +
|
||||||
"/app-icons/" +
|
"/app-icons/" +
|
||||||
application.id +
|
application.id +
|
||||||
"/" +
|
"/" +
|
||||||
(application.cover_image || application.icon) +
|
(application.cover_image || application.icon) +
|
||||||
".png?size=256";
|
".png?size=256",
|
||||||
|
);
|
||||||
cover.alt = "";
|
cover.alt = "";
|
||||||
cover.loading = "lazy";
|
cover.loading = "lazy";
|
||||||
container.appendChild(cover);
|
container.appendChild(cover);
|
||||||
|
|
|
@ -574,7 +574,7 @@ class Message extends SnowFlake {
|
||||||
this.message_reference ||
|
this.message_reference ||
|
||||||
!messageTypes.has(premessage.type);
|
!messageTypes.has(premessage.type);
|
||||||
if (combine) {
|
if (combine) {
|
||||||
const pfp = this.author.buildpfp();
|
const pfp = this.author.buildpfp(undefined, div);
|
||||||
this.author.bind(pfp, this.guild, false);
|
this.author.bind(pfp, this.guild, false);
|
||||||
pfpRow.appendChild(pfp);
|
pfpRow.appendChild(pfp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {I18n} from "./i18n.js";
|
||||||
import {Direct} from "./direct.js";
|
import {Direct} from "./direct.js";
|
||||||
import {Hover} from "./hover.js";
|
import {Hover} from "./hover.js";
|
||||||
import {Dialog} from "./settings.js";
|
import {Dialog} from "./settings.js";
|
||||||
|
import {createImg} from "./utils/utils.js";
|
||||||
|
|
||||||
class User extends SnowFlake {
|
class User extends SnowFlake {
|
||||||
owner: Localuser;
|
owner: Localuser;
|
||||||
|
@ -456,10 +457,9 @@ class User extends SnowFlake {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildpfp(guild: Guild | void | Member | null): HTMLImageElement {
|
buildpfp(guild: Guild | void | Member | null, hoverElm: void | HTMLElement): HTMLImageElement {
|
||||||
const pfp = document.createElement("img");
|
const pfp = createImg(this.getpfpsrc(), undefined, hoverElm);
|
||||||
pfp.loading = "lazy";
|
pfp.loading = "lazy";
|
||||||
pfp.src = this.getpfpsrc();
|
|
||||||
pfp.classList.add("pfp");
|
pfp.classList.add("pfp");
|
||||||
pfp.classList.add("userid:" + this.id);
|
pfp.classList.add("userid:" + this.id);
|
||||||
if (guild) {
|
if (guild) {
|
||||||
|
@ -467,9 +467,9 @@ class User extends SnowFlake {
|
||||||
if (guild instanceof Guild) {
|
if (guild instanceof Guild) {
|
||||||
const memb = await Member.resolveMember(this, guild);
|
const memb = await Member.resolveMember(this, guild);
|
||||||
if (!memb) return;
|
if (!memb) return;
|
||||||
pfp.src = memb.getpfpsrc();
|
pfp.setSrcs(memb.getpfpsrc());
|
||||||
} else {
|
} else {
|
||||||
pfp.src = guild.getpfpsrc();
|
pfp.setSrcs(guild.getpfpsrc());
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
@ -479,7 +479,7 @@ class User extends SnowFlake {
|
||||||
async buildstatuspfp(guild: Guild | void | Member | null): Promise<HTMLDivElement> {
|
async buildstatuspfp(guild: Guild | void | Member | null): Promise<HTMLDivElement> {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("pfpDiv");
|
div.classList.add("pfpDiv");
|
||||||
const pfp = this.buildpfp(guild);
|
const pfp = this.buildpfp(guild, div);
|
||||||
div.append(pfp);
|
div.append(pfp);
|
||||||
const status = document.createElement("div");
|
const status = document.createElement("div");
|
||||||
status.classList.add("statusDiv");
|
status.classList.add("statusDiv");
|
||||||
|
@ -560,9 +560,10 @@ class User extends SnowFlake {
|
||||||
changepfp(update: string | null): void {
|
changepfp(update: string | null): void {
|
||||||
this.avatar = update;
|
this.avatar = update;
|
||||||
this.hypotheticalpfp = false;
|
this.hypotheticalpfp = false;
|
||||||
const src = this.getpfpsrc();
|
//const src = this.getpfpsrc();
|
||||||
Array.from(document.getElementsByClassName("userid:" + this.id)).forEach((element) => {
|
Array.from(document.getElementsByClassName("userid:" + this.id)).forEach((_element) => {
|
||||||
(element as HTMLImageElement).src = src;
|
//(element as HTMLImageElement).src = src;
|
||||||
|
//FIXME
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -719,12 +720,14 @@ class User extends SnowFlake {
|
||||||
for (const badgejson of badges) {
|
for (const badgejson of badges) {
|
||||||
const badge = document.createElement(badgejson.link ? "a" : "div");
|
const badge = document.createElement(badgejson.link ? "a" : "div");
|
||||||
badge.classList.add("badge");
|
badge.classList.add("badge");
|
||||||
const img = document.createElement("img");
|
let src: string;
|
||||||
if (URL.canParse(badgejson.icon)) {
|
if (URL.canParse(badgejson.icon)) {
|
||||||
img.src = badgejson.icon;
|
src = badgejson.icon;
|
||||||
} else {
|
} else {
|
||||||
img.src = this.info.cdn + "/badge-icons/" + badgejson.icon + ".png";
|
src = this.info.cdn + "/badge-icons/" + badgejson.icon + ".png";
|
||||||
}
|
}
|
||||||
|
const img = createImg(src, undefined, badgediv);
|
||||||
|
|
||||||
badge.append(img);
|
badge.append(img);
|
||||||
let hovertxt: string;
|
let hovertxt: string;
|
||||||
if (badgejson.translate) {
|
if (badgejson.translate) {
|
||||||
|
@ -810,11 +813,11 @@ class User extends SnowFlake {
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
getBanner(guild: Guild | null | Member): HTMLImageElement {
|
getBanner(guild: Guild | null | Member): HTMLImageElement {
|
||||||
const banner = document.createElement("img");
|
const banner = createImg(undefined);
|
||||||
|
|
||||||
const bsrc = this.getBannerUrl();
|
const bsrc = this.getBannerUrl();
|
||||||
if (bsrc) {
|
if (bsrc) {
|
||||||
banner.src = bsrc;
|
banner.setSrcs(bsrc);
|
||||||
banner.classList.add("banner");
|
banner.classList.add("banner");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -822,7 +825,7 @@ class User extends SnowFlake {
|
||||||
if (guild instanceof Member) {
|
if (guild instanceof Member) {
|
||||||
const bsrc = guild.getBannerUrl();
|
const bsrc = guild.getBannerUrl();
|
||||||
if (bsrc) {
|
if (bsrc) {
|
||||||
banner.src = bsrc;
|
banner.setSrcs(bsrc);
|
||||||
banner.classList.add("banner");
|
banner.classList.add("banner");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -830,7 +833,7 @@ class User extends SnowFlake {
|
||||||
if (!memb) return;
|
if (!memb) return;
|
||||||
const bsrc = memb.getBannerUrl();
|
const bsrc = memb.getBannerUrl();
|
||||||
if (bsrc) {
|
if (bsrc) {
|
||||||
banner.src = bsrc;
|
banner.setSrcs(bsrc);
|
||||||
banner.classList.add("banner");
|
banner.classList.add("banner");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -583,6 +583,63 @@ export async function getapiurls(str: string): Promise<
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
function isAnimated(src: string) {
|
||||||
|
return src.endsWith(".apng") || src.endsWith(".gif");
|
||||||
|
}
|
||||||
|
const staticImgMap = new Map<string, string | Promise<string>>();
|
||||||
|
export function createImg(
|
||||||
|
src: string | undefined,
|
||||||
|
staticsrc: string | void,
|
||||||
|
elm: HTMLElement | void,
|
||||||
|
) {
|
||||||
|
const settings =
|
||||||
|
localStorage.getItem("gifSetting") || ("hover" as "hover") || "always" || "never";
|
||||||
|
const img = document.createElement("img");
|
||||||
|
elm ||= img;
|
||||||
|
img.crossOrigin = "anonymous";
|
||||||
|
img.onload = async () => {
|
||||||
|
if (settings === "always") return;
|
||||||
|
if (!src) return;
|
||||||
|
if (isAnimated(src) && !staticsrc) {
|
||||||
|
let s = staticImgMap.get(src);
|
||||||
|
if (s) {
|
||||||
|
staticsrc = await s;
|
||||||
|
} else {
|
||||||
|
staticImgMap.set(
|
||||||
|
src,
|
||||||
|
new Promise(async (res) => {
|
||||||
|
const c = new OffscreenCanvas(img.naturalWidth, img.naturalHeight);
|
||||||
|
const ctx = c.getContext("2d");
|
||||||
|
if (!ctx) return;
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
const blob = await c.convertToBlob();
|
||||||
|
res(URL.createObjectURL(blob));
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
staticsrc = (await staticImgMap.get(src)) as string;
|
||||||
|
}
|
||||||
|
img.src = staticsrc;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
elm.onmouseover = () => {
|
||||||
|
if (settings === "never") return;
|
||||||
|
if (img.src !== src && src) {
|
||||||
|
img.src = src;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
elm.onmouseleave = () => {
|
||||||
|
if (staticsrc && settings !== "always") {
|
||||||
|
img.src = staticsrc;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
img.src = settings !== "always" ? staticsrc || src || "" : src || "";
|
||||||
|
return Object.assign(img, {
|
||||||
|
setSrcs: (nsrc: string, nstaticsrc: string | void) => {
|
||||||
|
src = nsrc;
|
||||||
|
staticsrc = nstaticsrc;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* This function takes in a string and checks if the string is a valid instance
|
* This function takes in a string and checks if the string is a valid instance
|
||||||
|
|
|
@ -155,7 +155,7 @@ async function webhookMenu(
|
||||||
const nameBox = document.createElement("div");
|
const nameBox = document.createElement("div");
|
||||||
nameBox.classList.add("flexttb");
|
nameBox.classList.add("flexttb");
|
||||||
nameBox.append(name);
|
nameBox.append(name);
|
||||||
const pfp = user.buildpfp();
|
const pfp = user.buildpfp(undefined, div);
|
||||||
div.append(pfp, nameBox);
|
div.append(pfp, nameBox);
|
||||||
form.addHTMLArea(div);
|
form.addHTMLArea(div);
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,13 @@
|
||||||
"spoiler": "Spoiler",
|
"spoiler": "Spoiler",
|
||||||
"accessibility": {
|
"accessibility": {
|
||||||
"name": "Accessibility",
|
"name": "Accessibility",
|
||||||
"roleColors": "Disable role colors"
|
"roleColors": "Disable role colors",
|
||||||
|
"playGif": "Play gifs:",
|
||||||
|
"gifSettings": {
|
||||||
|
"hover": "Hover",
|
||||||
|
"always": "Always",
|
||||||
|
"never": "Never"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"searchGifs": "Search Tenor",
|
"searchGifs": "Search Tenor",
|
||||||
"channel": {
|
"channel": {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue