1
Fork 0

Compare commits

..

No commits in common. "8fb439c98cec38dd9dafe446dc2272f4ed73472d" and "126960ba82ba00e9180bd886603e6b973034efab" have entirely different histories.

9 changed files with 53 additions and 131 deletions

View File

@ -2,11 +2,6 @@
> **The principal enhancement suite for Tildes.** > **The principal enhancement suite for Tildes.**
## Documentation
* If you'd like to know what the differences between Tildes Extended and Tildes ReExtended are, see [DIFFERENCES.md](DIFFERENCES.md).
* To build Tildes ReExtended yourself, see [DEVELOPMENT.md](DEVELOPMENT.md).
## License ## License
Distributed under the [MIT](https://spdx.org/licenses/MIT.html) license, see [LICENSE](https://gitlab.com/tildes-community/tildes-reextended/-/blob/main/LICENSE) for more information. Distributed under the [MIT](https://spdx.org/licenses/MIT.html) license, see [LICENSE](https://gitlab.com/tildes-community/tildes-reextended/-/blob/main/LICENSE) for more information.

View File

@ -80,7 +80,9 @@ export class UserLabelsFeature extends Component<Props, State> {
}); });
for (const element of elements) { for (const element of elements) {
let username: string = element.textContent!.replace(/@/g, ""); let username: string = element
.textContent!.replace(/@/g, "")
.toLowerCase();
if (this.props.anonymizeUsernamesEnabled) { if (this.props.anonymizeUsernamesEnabled) {
username = element.dataset.trxUsername ?? username; username = element.dataset.trxUsername ?? username;
@ -88,7 +90,7 @@ export class UserLabelsFeature extends Component<Props, State> {
const userLabels = sortedLabels.filter( const userLabels = sortedLabels.filter(
({value}) => ({value}) =>
value.username.toLowerCase() === username.toLowerCase() && value.username.toLowerCase() === username &&
(onlyID === undefined ? true : value.id === onlyID), (onlyID === undefined ? true : value.id === onlyID),
); );
@ -259,7 +261,7 @@ export class UserLabelsFeature extends Component<Props, State> {
this.addLabelsToUsernames(querySelectorAll(".link-user"), newId); this.addLabelsToUsernames(querySelectorAll(".link-user"), newId);
} else { } else {
const index = userLabels.findIndex(({value}) => value.id === id); const index = userLabels.findIndex(({value}) => value.id === id);
await userLabels.splice(index, 1)[0].remove(); userLabels.splice(index, 1);
userLabels.push( userLabels.push(
await createValueUserLabel({ await createValueUserLabel({
id, id,

View File

@ -14,9 +14,7 @@ function usernameColors(
anonymizeUsernamesEnabled: boolean, anonymizeUsernamesEnabled: boolean,
): number { ): number {
const usernameColors = new Map<string, string>(); const usernameColors = new Map<string, string>();
for (const { for (const {color, username: usernames} of data) {
value: {color, username: usernames},
} of data) {
for (const username of usernames.split(",")) { for (const username of usernames.split(",")) {
usernameColors.set(username.trim().toLowerCase(), color); usernameColors.set(username.trim().toLowerCase(), color);
} }

View File

@ -86,7 +86,7 @@ async function initialize() {
if (enabledFeatures.value.has(Feature.UsernameColors)) { if (enabledFeatures.value.has(Feature.UsernameColors)) {
observerFeatures.push(async () => { observerFeatures.push(async () => {
const data = await fromStorage(Feature.UsernameColors); const data = await fromStorage(Feature.UsernameColors);
runUsernameColorsFeature(data, anonymizeUsernamesEnabled); runUsernameColorsFeature(data.value, anonymizeUsernamesEnabled);
}); });
} }

View File

@ -1,18 +1,17 @@
import {Component} from "preact"; import {Component} from "preact";
import {type Value} from "@holllo/webextension-storage";
import {log} from "../../utilities/exports.js"; import {log} from "../../utilities/exports.js";
import { import {
type UsernameColorsData, type UsernameColorsData,
type UsernameColor, type UsernameColor,
Feature, Feature,
createValueUsernamecolor,
fromStorage, fromStorage,
} from "../../storage/exports.js"; } from "../../storage/exports.js";
import {Setting, type SettingProps} from "./index.js"; import {Setting, type SettingProps} from "./index.js";
type State = { type State = {
previewChecked: "off" | "foreground" | "background"; previewChecked: "off" | "foreground" | "background";
usernameColors: UsernameColorsData; usernameColors: Value<UsernameColorsData>;
usernameColorsToRemove: UsernameColorsData;
}; };
export class UsernameColorsSetting extends Component<SettingProps, State> { export class UsernameColorsSetting extends Component<SettingProps, State> {
@ -22,7 +21,6 @@ export class UsernameColorsSetting extends Component<SettingProps, State> {
this.state = { this.state = {
previewChecked: "off", previewChecked: "off",
usernameColors: undefined!, usernameColors: undefined!,
usernameColorsToRemove: [],
}; };
} }
@ -30,50 +28,35 @@ export class UsernameColorsSetting extends Component<SettingProps, State> {
this.setState({usernameColors: await fromStorage(Feature.UsernameColors)}); this.setState({usernameColors: await fromStorage(Feature.UsernameColors)});
} }
addNewColor = async () => { addNewColor = () => {
let id = 1; let id = 1;
if (this.state.usernameColors.length > 0) { if (this.state.usernameColors.value.length > 0) {
id = id =
this.state.usernameColors.sort((a, b) => b.value.id - a.value.id)[0] this.state.usernameColors.value.sort((a, b) => b.id - a.id)[0].id + 1;
.value.id + 1;
} }
const newColor = await createValueUsernamecolor({ const newColor: UsernameColor = {
color: "", color: "",
id, id,
username: "", username: "",
}); };
this.state.usernameColors.push(newColor); this.state.usernameColors.value.push(newColor);
this.setState({ this.setState({
usernameColors: this.state.usernameColors, usernameColors: this.state.usernameColors,
}); });
}; };
removeColor = async (targetId: number) => { removeColor = (targetId: number) => {
const targetIndex = this.state.usernameColors.findIndex( const targetIndex = this.state.usernameColors.value.findIndex(
({value}) => value.id === targetId, ({id}) => id === targetId,
); );
const usernameColorsToRemove = this.state.usernameColorsToRemove; this.state.usernameColors.value.splice(targetIndex, 1);
usernameColorsToRemove.push( this.setState({usernameColors: this.state.usernameColors});
...this.state.usernameColors.splice(targetIndex, 1),
);
this.setState({
usernameColors: this.state.usernameColors,
usernameColorsToRemove,
});
}; };
saveChanges = async () => { saveChanges = async () => {
for (const usernameColor of this.state.usernameColorsToRemove) { await this.state.usernameColors.save();
await usernameColor.remove();
}
for (const usernameColor of this.state.usernameColors) {
await usernameColor.save();
}
this.setState({usernameColorsToRemove: []});
}; };
togglePreview = async () => { togglePreview = async () => {
@ -101,8 +84,8 @@ export class UsernameColorsSetting extends Component<SettingProps, State> {
}; };
onInput = (event: Event, id: number, key: "color" | "username") => { onInput = (event: Event, id: number, key: "color" | "username") => {
const colorIndex = this.state.usernameColors.findIndex( const colorIndex = this.state.usernameColors.value.findIndex(
({value}) => value.id === id, (color) => color.id === id,
); );
if (colorIndex === -1) { if (colorIndex === -1) {
log(`Tried to edit unknown UsernameColor ID: ${id}`); log(`Tried to edit unknown UsernameColor ID: ${id}`);
@ -110,7 +93,7 @@ export class UsernameColorsSetting extends Component<SettingProps, State> {
} }
const newValue = (event.target as HTMLInputElement).value; const newValue = (event.target as HTMLInputElement).value;
this.state.usernameColors[colorIndex].value[key] = newValue; this.state.usernameColors.value[colorIndex][key] = newValue;
this.setState({usernameColors: this.state.usernameColors}); this.setState({usernameColors: this.state.usernameColors});
}; };
@ -120,9 +103,9 @@ export class UsernameColorsSetting extends Component<SettingProps, State> {
return; return;
} }
usernameColors.sort((a, b) => a.value.id - b.value.id); usernameColors.value.sort((a, b) => a.id - b.id);
const editors = usernameColors.map(({value: {color, id, username}}) => { const editors = usernameColors.value.map(({color, id, username}) => {
const style: Record<string, string> = {}; const style: Record<string, string> = {};
if (previewChecked === "background") { if (previewChecked === "background") {
style.backgroundColor = color; style.backgroundColor = color;
@ -138,8 +121,8 @@ export class UsernameColorsSetting extends Component<SettingProps, State> {
this.onInput(event, id, "color"); this.onInput(event, id, "color");
}; };
const removeHandler = async () => { const removeHandler = () => {
await this.removeColor(id); this.removeColor(id);
}; };
return ( return (

View File

@ -1,12 +1,10 @@
import {createValue} from "@holllo/webextension-storage"; import {createValue, type Value} from "@holllo/webextension-storage";
import browser from "webextension-polyfill"; import browser from "webextension-polyfill";
import {Data, Feature} from "./enums.js";
import {collectUsernameColors} from "./username-color.js";
import {collectUserLabels} from "./user-label.js"; import {collectUserLabels} from "./user-label.js";
import {Data, Feature} from "./enums.js";
export * from "./enums.js";
export * from "./username-color.js";
export * from "./user-label.js"; export * from "./user-label.js";
export * from "./enums.js";
export type HideVotesData = { export type HideVotesData = {
otherComments: boolean; otherComments: boolean;
@ -15,6 +13,14 @@ export type HideVotesData = {
ownTopics: boolean; ownTopics: boolean;
}; };
export type UsernameColor = {
color: string;
id: number;
username: string;
};
export type UsernameColorsData = UsernameColor[];
export const storageValues = { export const storageValues = {
[Data.EnabledFeatures]: createValue({ [Data.EnabledFeatures]: createValue({
deserialize: (input) => new Set(JSON.parse(input) as Feature[]), deserialize: (input) => new Set(JSON.parse(input) as Feature[]),
@ -57,7 +63,13 @@ export const storageValues = {
storage: browser.storage.sync, storage: browser.storage.sync,
}), }),
[Feature.UserLabels]: collectUserLabels(), [Feature.UserLabels]: collectUserLabels(),
[Feature.UsernameColors]: collectUsernameColors(), [Feature.UsernameColors]: createValue({
deserialize: (input) => JSON.parse(input) as UsernameColorsData,
serialize: (input) => JSON.stringify(Array.from(input)),
key: Feature.UsernameColors,
value: [],
storage: browser.storage.sync,
}),
}; };
type StorageValues = typeof storageValues; type StorageValues = typeof storageValues;

View File

@ -38,15 +38,10 @@ await setup("Migrations", async (group) => {
break; break;
} }
case `${Feature.UsernameColors}-4`: { case Feature.UsernameColors: {
test.equals(value, '{"color":"red","id":4,"username":"Test"}');
break;
}
case `${Feature.UsernameColors}-18`: {
test.equals( test.equals(
value, value,
'{"color":"green","id":18,"username":"AnotherTest"}', '[{"color":"red","id":4,"username":"Test"},{"color":"green","id":18,"username":"AnotherTest"}]',
); );
break; break;
} }

View File

@ -2,13 +2,11 @@ import {type Migration} from "@holllo/migration-helper";
import { import {
Data, Data,
Feature, Feature,
createValueUsernamecolor,
createValueUserLabel, createValueUserLabel,
fromStorage, fromStorage,
saveUsernameColors,
saveUserLabels, saveUserLabels,
} from "../exports.js"; } from "../exports.js";
import {v112DeserializeData, type V112Settings} from "./v1-1-2.js"; import {v112DeserializeData, v112Sample, type V112Settings} from "./v1-1-2.js";
export const migrations: Array<Migration<string>> = [ export const migrations: Array<Migration<string>> = [
{ {
@ -18,18 +16,11 @@ export const migrations: Array<Migration<string>> = [
data.data.userLabels = deserialized.userLabels; data.data.userLabels = deserialized.userLabels;
data.data.usernameColors = deserialized.usernameColors; data.data.usernameColors = deserialized.usernameColors;
const usernameColors = [];
const userLabels = []; const userLabels = [];
for (const usernameColor of data.data.usernameColors) {
usernameColors.push(await createValueUsernamecolor(usernameColor));
}
for (const userLabel of data.data.userLabels) { for (const userLabel of data.data.userLabels) {
userLabels.push(await createValueUserLabel(userLabel)); userLabels.push(await createValueUserLabel(userLabel));
} }
await saveUsernameColors(usernameColors);
await saveUserLabels(userLabels); await saveUserLabels(userLabels);
const hideVotes = await fromStorage(Feature.HideVotes); const hideVotes = await fromStorage(Feature.HideVotes);
@ -49,6 +40,10 @@ export const migrations: Array<Migration<string>> = [
version.value = "2.0.0"; version.value = "2.0.0";
await version.save(); await version.save();
const usernameColors = await fromStorage(Feature.UsernameColors);
usernameColors.value = data.data.usernameColors;
await usernameColors.save();
const enabledFeatures = await fromStorage(Data.EnabledFeatures); const enabledFeatures = await fromStorage(Data.EnabledFeatures);
for (const [key, value] of Object.entries(data.features)) { for (const [key, value] of Object.entries(data.features)) {
if (value) { if (value) {

View File

@ -1,58 +0,0 @@
import {type Value, createValue} from "@holllo/webextension-storage";
import browser from "webextension-polyfill";
import {Feature} from "./enums.js";
export type UsernameColor = {
color: string;
id: number;
username: string;
};
export type UsernameColorsData = Array<Value<UsernameColor>>;
/**
* Create a {@link Value}-wrapped {@link UsernameColor}.
*/
export async function createValueUsernamecolor(
usernameColor: UsernameColor,
): Promise<UsernameColorsData[number]> {
return createValue<UsernameColor>({
deserialize: (input) => JSON.parse(input) as UsernameColor,
serialize: (input) => JSON.stringify(input),
key: `${Feature.UsernameColors}-${usernameColor.id}`,
value: usernameColor,
storage: browser.storage.sync,
});
}
/**
* Get all username colors from storage and combine them into a single array.
*/
export async function collectUsernameColors(): Promise<UsernameColorsData> {
const storage = await browser.storage.sync.get();
const userLabels = [];
for (const [key, value] of Object.entries(storage)) {
if (!key.startsWith(Feature.UsernameColors)) {
continue;
}
userLabels.push(
await createValueUsernamecolor(
JSON.parse(value as string) as UsernameColor,
),
);
}
return userLabels;
}
/**
* Save all username colors to storage under individual keys.
*/
export async function saveUsernameColors(
usernameColors: UsernameColorsData,
): Promise<void> {
for (const usernameColor of usernameColors) {
await usernameColor.save();
}
}