diff --git a/src/shared/components/modlog.tsx b/src/shared/components/modlog.tsx index cd0cfcb9..99f15e50 100644 --- a/src/shared/components/modlog.tsx +++ b/src/shared/components/modlog.tsx @@ -33,7 +33,6 @@ import { FirstLoadService } from "../services/FirstLoadService"; import { HttpService, RequestState } from "../services/HttpService"; import { Choice, - debounce, fetchLimit, fetchUsers, getIdFromString, @@ -43,6 +42,7 @@ import { personToChoice, setIsoData, } from "../utils"; +import { debounce } from "../utils/helpers/debounce"; import { getQueryParams } from "../utils/helpers/get-query-params"; import { getQueryString } from "../utils/helpers/get-query-string"; import { amAdmin } from "../utils/roles/am-admin"; diff --git a/src/shared/components/person/settings.tsx b/src/shared/components/person/settings.tsx index a29f61b0..564daff4 100644 --- a/src/shared/components/person/settings.tsx +++ b/src/shared/components/person/settings.tsx @@ -18,7 +18,6 @@ import { Choice, capitalizeFirstLetter, communityToChoice, - debounce, elementUrl, emDash, enableNsfw, @@ -38,6 +37,7 @@ import { updateCommunityBlock, updatePersonBlock, } from "../../utils"; +import { debounce } from "../../utils/helpers/debounce"; import { HtmlTags } from "../common/html-tags"; import { Icon, Spinner } from "../common/icon"; import { ImageUploadForm } from "../common/image-upload-form"; diff --git a/src/shared/components/post/post-form.tsx b/src/shared/components/post/post-form.tsx index 4640922d..c21a6e2b 100644 --- a/src/shared/components/post/post-form.tsx +++ b/src/shared/components/post/post-form.tsx @@ -18,7 +18,6 @@ import { archiveTodayUrl, capitalizeFirstLetter, communityToChoice, - debounce, fetchCommunities, getIdFromString, ghostArchiveUrl, @@ -33,6 +32,7 @@ import { validURL, webArchiveUrl, } from "../../utils"; +import { debounce } from "../../utils/helpers/debounce"; import { Icon, Spinner } from "../common/icon"; import { LanguageSelect } from "../common/language-select"; import { MarkdownTextArea } from "../common/markdown-textarea"; diff --git a/src/shared/components/post/post.tsx b/src/shared/components/post/post.tsx index 250c08a7..2c61f79e 100644 --- a/src/shared/components/post/post.tsx +++ b/src/shared/components/post/post.tsx @@ -64,7 +64,6 @@ import { buildCommentsTree, commentsToFlatNodes, commentTreeMaxDepth, - debounce, editComment, editWith, enableDownvotes, @@ -84,6 +83,7 @@ import { updatePersonBlock, } from "../../utils"; import { isBrowser } from "../../utils/browser/is-browser"; +import { debounce } from "../../utils/helpers/debounce"; import { CommentForm } from "../comment/comment-form"; import { CommentNodes } from "../comment/comment-nodes"; import { HtmlTags } from "../common/html-tags"; diff --git a/src/shared/components/search.tsx b/src/shared/components/search.tsx index 59bbf616..d32e4087 100644 --- a/src/shared/components/search.tsx +++ b/src/shared/components/search.tsx @@ -29,7 +29,6 @@ import { capitalizeFirstLetter, commentsToFlatNodes, communityToChoice, - debounce, enableDownvotes, enableNsfw, fetchCommunities, @@ -46,6 +45,7 @@ import { setIsoData, showLocal, } from "../utils"; +import { debounce } from "../utils/helpers/debounce"; import { getQueryParams } from "../utils/helpers/get-query-params"; import { getQueryString } from "../utils/helpers/get-query-string"; import type { QueryParams } from "../utils/types/query-params"; diff --git a/src/shared/utils.ts b/src/shared/utils.ts index 54b5a3f4..c0caad88 100644 --- a/src/shared/utils.ts +++ b/src/shared/utils.ts @@ -44,6 +44,7 @@ import { i18n, languages } from "./i18next"; import { CommentNodeI, DataType, IsoData, VoteType } from "./interfaces"; import { HttpService, UserService } from "./services"; import { isBrowser } from "./utils/browser/is-browser"; +import { debounce } from "./utils/helpers/debounce"; import { groupBy } from "./utils/helpers/group-by"; let Tribute: any; @@ -268,51 +269,6 @@ export function getDataTypeString(dt: DataType) { return dt === DataType.Post ? "Post" : "Comment"; } -export function debounce( - func: (...e: T) => R, - wait = 1000, - immediate = false -) { - // 'private' variable for instance - // The returned function will be able to reference this due to closure. - // Each call to the returned function will share this common timer. - let timeout: NodeJS.Timeout | null; - - // Calling debounce returns a new anonymous function - return function () { - // reference the context and args for the setTimeout function - const args = arguments; - - // Should the function be called now? If immediate is true - // and not already in a timeout then the answer is: Yes - const callNow = immediate && !timeout; - - // This is the basic debounce behavior where you can call this - // function several times, but it will only execute once - // [before or after imposing a delay]. - // Each time the returned function is called, the timer starts over. - clearTimeout(timeout ?? undefined); - - // Set the new timeout - timeout = setTimeout(function () { - // Inside the timeout function, clear the timeout variable - // which will let the next execution run when in 'immediate' mode - timeout = null; - - // Check if the function already ran with the immediate flag - if (!immediate) { - // Call the original function with apply - // apply lets you define the 'this' object as well as the arguments - // (both captured before setTimeout) - func.apply(this, args); - } - }, wait); - - // Immediate mode and no wait timer? Execute the function.. - if (callNow) func.apply(this, args); - } as (...e: T) => R; -} - export function getLanguages( override?: string, myUserInfo = UserService.Instance.myUserInfo diff --git a/src/shared/utils/helpers/debounce.ts b/src/shared/utils/helpers/debounce.ts new file mode 100644 index 00000000..7a1e8b19 --- /dev/null +++ b/src/shared/utils/helpers/debounce.ts @@ -0,0 +1,44 @@ +export function debounce( + func: (...e: T) => R, + wait = 1000, + immediate = false +) { + // 'private' variable for instance + // The returned function will be able to reference this due to closure. + // Each call to the returned function will share this common timer. + let timeout: NodeJS.Timeout | null; + + // Calling debounce returns a new anonymous function + return function () { + // reference the context and args for the setTimeout function + const args = arguments; + + // Should the function be called now? If immediate is true + // and not already in a timeout then the answer is: Yes + const callNow = immediate && !timeout; + + // This is the basic debounce behavior where you can call this + // function several times, but it will only execute once + // [before or after imposing a delay]. + // Each time the returned function is called, the timer starts over. + clearTimeout(timeout ?? undefined); + + // Set the new timeout + timeout = setTimeout(function () { + // Inside the timeout function, clear the timeout variable + // which will let the next execution run when in 'immediate' mode + timeout = null; + + // Check if the function already ran with the immediate flag + if (!immediate) { + // Call the original function with apply + // apply lets you define the 'this' object as well as the arguments + // (both captured before setTimeout) + func.apply(this, args); + } + }, wait); + + // Immediate mode and no wait timer? Execute the function.. + if (callNow) func.apply(this, args); + } as (...e: T) => R; +}