Compare commits
No commits in common. "061df73df8993db5c08f477af0daae0fd7e0eb4b" and "99180035e3d974aa4adfcb15d9d516b705e5089d" have entirely different histories.
061df73df8
...
99180035e3
|
@ -9,6 +9,5 @@ export * from "./jump-to-new-comment.js";
|
||||||
export * from "./markdown-toolbar.js";
|
export * from "./markdown-toolbar.js";
|
||||||
export * from "./themed-logo.js";
|
export * from "./themed-logo.js";
|
||||||
export * from "./topic-info-ignore.js";
|
export * from "./topic-info-ignore.js";
|
||||||
export * from "./unignore-all-button.js";
|
|
||||||
export * from "./user-labels.js";
|
export * from "./user-labels.js";
|
||||||
export * from "./username-colors.js";
|
export * from "./username-colors.js";
|
||||||
|
|
|
@ -1,114 +0,0 @@
|
||||||
import {Component, render} from "preact";
|
|
||||||
import {log, querySelectorAll, sleep} from "../../utilities/exports.js";
|
|
||||||
|
|
||||||
export function runUnignoreAllButtonFeature(): void {
|
|
||||||
if (addUnignoreAllButton()) {
|
|
||||||
log("Added Unignore All button.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addUnignoreAllButton(): boolean {
|
|
||||||
// Only add the button when we're on the ignore list page and the ignore list
|
|
||||||
// isn't empty.
|
|
||||||
if (
|
|
||||||
window.location.pathname !== "/ignored_topics" &&
|
|
||||||
document.querySelector("main > .empty") === null
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const heading = document.querySelector(".heading-main") ?? undefined;
|
|
||||||
if (heading === undefined) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const button = document.createDocumentFragment();
|
|
||||||
render(<UnignoreAllButton />, button);
|
|
||||||
heading.after(button);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = Record<string, unknown>;
|
|
||||||
|
|
||||||
type State = {
|
|
||||||
isRunning: boolean;
|
|
||||||
remaining: number;
|
|
||||||
total: number;
|
|
||||||
wasCanceled: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
class UnignoreAllButton extends Component<Props, State> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
isRunning: false,
|
|
||||||
remaining: 0,
|
|
||||||
total: 0,
|
|
||||||
wasCanceled: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
click = () => {
|
|
||||||
if (this.state.isRunning) {
|
|
||||||
// If we're already running, cancel the run.
|
|
||||||
this.setState({isRunning: false, wasCanceled: true});
|
|
||||||
window.setTimeout(() => {
|
|
||||||
// And after 5 seconds, return back to the default state.
|
|
||||||
this.setState({wasCanceled: false});
|
|
||||||
}, 5000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select the ignore buttons that have a HTTP DELETE method set. Since we're
|
|
||||||
// going to have Intercooler do all the work for us, we don't want to
|
|
||||||
// accidentally also select ignore buttons that would ignore the topics
|
|
||||||
// again.
|
|
||||||
const unignoreButtons = querySelectorAll<HTMLButtonElement>(
|
|
||||||
'button[name="topic-actions-ignore"][data-ic-delete-from]',
|
|
||||||
);
|
|
||||||
this.setState({
|
|
||||||
isRunning: true,
|
|
||||||
remaining: unignoreButtons.length,
|
|
||||||
total: unignoreButtons.length,
|
|
||||||
});
|
|
||||||
void this.unignoreAll(unignoreButtons);
|
|
||||||
};
|
|
||||||
|
|
||||||
unignoreAll = async (buttons: HTMLButtonElement[]) => {
|
|
||||||
let remaining = buttons.length;
|
|
||||||
for (const ignoreButton of buttons) {
|
|
||||||
// Stop the loop if the user canceled it.
|
|
||||||
if (!this.state.isRunning && this.state.wasCanceled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ignoreButton.click();
|
|
||||||
remaining--;
|
|
||||||
this.setState({remaining});
|
|
||||||
await sleep(250);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({isRunning: false});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {isRunning, remaining, total, wasCanceled} = this.state;
|
|
||||||
let text = "Unignore All";
|
|
||||||
|
|
||||||
if (isRunning) {
|
|
||||||
// When we're running show how many topics are remaining.
|
|
||||||
text = `Unignoring topics, ${remaining} out of ${total} remaining`;
|
|
||||||
} else if (wasCanceled) {
|
|
||||||
// If the user canceled, say that.
|
|
||||||
text = "Canceled unignoring all topics";
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button class="btn" onClick={this.click}>
|
|
||||||
{text}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -24,7 +24,6 @@ import {
|
||||||
runMarkdownToolbarFeature,
|
runMarkdownToolbarFeature,
|
||||||
runThemedLogoFeature,
|
runThemedLogoFeature,
|
||||||
runTopicInfoIgnore,
|
runTopicInfoIgnore,
|
||||||
runUnignoreAllButtonFeature,
|
|
||||||
runUsernameColorsFeature,
|
runUsernameColorsFeature,
|
||||||
} from "./features/exports.js";
|
} from "./features/exports.js";
|
||||||
|
|
||||||
|
@ -177,13 +176,6 @@ async function initialize() {
|
||||||
runTopicInfoIgnore();
|
runTopicInfoIgnore();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
miscEnabled.value.has(MiscellaneousFeature.UnignoreAllButton) &&
|
|
||||||
isLoggedIn
|
|
||||||
) {
|
|
||||||
runUnignoreAllButtonFeature();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert a placeholder at the end of the body first, then render the rest
|
// Insert a placeholder at the end of the body first, then render the rest
|
||||||
// and use that as the replacement element. Otherwise render() would put it
|
// and use that as the replacement element. Otherwise render() would put it
|
||||||
// at the beginning of the body which causes a bunch of different issues.
|
// at the beginning of the body which causes a bunch of different issues.
|
||||||
|
|
|
@ -42,14 +42,6 @@ function FeatureDescription({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (feature === MiscellaneousFeature.UnignoreAllButton) {
|
|
||||||
return (
|
|
||||||
<p class="description">
|
|
||||||
Add an "Unignore All" button to your list of ignored topics.
|
|
||||||
</p>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ export enum MiscellaneousFeature {
|
||||||
CommentAnchorFix = "comment-anchor-fix",
|
CommentAnchorFix = "comment-anchor-fix",
|
||||||
GroupListSubscribeButtons = "group-list-subscribe-buttons",
|
GroupListSubscribeButtons = "group-list-subscribe-buttons",
|
||||||
TopicInfoIgnore = "topic-info-ignore",
|
TopicInfoIgnore = "topic-info-ignore",
|
||||||
UnignoreAllButton = "unignore-all-button",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,7 +7,6 @@ export * from "./http.js";
|
||||||
export * from "./logging.js";
|
export * from "./logging.js";
|
||||||
export * from "./query-selectors.js";
|
export * from "./query-selectors.js";
|
||||||
export * from "./report-a-bug.js";
|
export * from "./report-a-bug.js";
|
||||||
export * from "./sleep.js";
|
|
||||||
export * from "./text.js";
|
export * from "./text.js";
|
||||||
export * from "./user.js";
|
export * from "./user.js";
|
||||||
export * from "./validators.js";
|
export * from "./validators.js";
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
/**
|
|
||||||
* Promisified {@linkcode window.setTimeout}.
|
|
||||||
* @param timeout The amount of time in milliseconds to sleep for.
|
|
||||||
*/
|
|
||||||
export async function sleep(timeout: number): Promise<void> {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
window.setTimeout(resolve, timeout);
|
|
||||||
});
|
|
||||||
}
|
|
Loading…
Reference in New Issue