diff --git a/app/assets/javascripts/components/annotations/annotation_tooltip.ts b/app/assets/javascripts/components/annotations/annotation_tooltip.ts index e97d3f0a5c..ec9023ec88 100644 --- a/app/assets/javascripts/components/annotations/annotation_tooltip.ts +++ b/app/assets/javascripts/components/annotations/annotation_tooltip.ts @@ -3,7 +3,7 @@ import { render, html, LitElement, TemplateResult, css } from "lit"; import tippy, { Instance as Tippy, createSingleton } from "tippy.js"; import { AnnotationData, annotationState, compareAnnotationOrders, isUserAnnotation } from "state/Annotations"; import { StateController } from "state/state_system/StateController"; -import { createDelayer } from "util.js"; +import { createDelayer } from "utilities"; const setInstancesDelayer = createDelayer(); /** diff --git a/app/assets/javascripts/components/annotations/annotations_toggles.ts b/app/assets/javascripts/components/annotations/annotations_toggles.ts index 6e3bdb14e2..670ca8fd41 100644 --- a/app/assets/javascripts/components/annotations/annotations_toggles.ts +++ b/app/assets/javascripts/components/annotations/annotations_toggles.ts @@ -3,7 +3,7 @@ import { ShadowlessLitElement } from "components/meta/shadowless_lit_element"; import { html, TemplateResult, PropertyValues } from "lit"; import { annotationState } from "state/Annotations"; import { i18nMixin } from "components/meta/i18n_mixin"; -import { initTooltips } from "util.js"; +import { initTooltips } from "utilities"; /** * This component represents the toggles to show/hide annotations. diff --git a/app/assets/javascripts/components/annotations/code_listing_row.ts b/app/assets/javascripts/components/annotations/code_listing_row.ts index 9a99ee8c73..f2d31d1596 100644 --- a/app/assets/javascripts/components/annotations/code_listing_row.ts +++ b/app/assets/javascripts/components/annotations/code_listing_row.ts @@ -4,7 +4,7 @@ import { html, TemplateResult } from "lit"; import "components/annotations/annotations_cell"; import "components/annotations/hidden_annotations_dot"; import { i18nMixin } from "components/meta/i18n_mixin"; -import { initTooltips } from "util.js"; +import { initTooltips } from "utilities"; import { PropertyValues } from "@lit/reactive-element"; import { userState } from "state/Users"; import { annotationState } from "state/Annotations"; diff --git a/app/assets/javascripts/components/annotations/create_annotation_button.ts b/app/assets/javascripts/components/annotations/create_annotation_button.ts index 22d99b8bf8..ac1cbed99a 100644 --- a/app/assets/javascripts/components/annotations/create_annotation_button.ts +++ b/app/assets/javascripts/components/annotations/create_annotation_button.ts @@ -2,7 +2,7 @@ import { ShadowlessLitElement } from "components/meta/shadowless_lit_element"; import { customElement, property } from "lit/decorators.js"; import { html, PropertyValues, TemplateResult } from "lit"; import { userAnnotationState } from "state/UserAnnotations"; -import { initTooltips } from "util.js"; +import { initTooltips } from "utilities"; // The image has to be created before the event is fired // otherwise safari will not create the drag image diff --git a/app/assets/javascripts/components/annotations/hidden_annotations_dot.ts b/app/assets/javascripts/components/annotations/hidden_annotations_dot.ts index ff656cb30c..40fea7ef6e 100644 --- a/app/assets/javascripts/components/annotations/hidden_annotations_dot.ts +++ b/app/assets/javascripts/components/annotations/hidden_annotations_dot.ts @@ -5,7 +5,7 @@ import { MachineAnnotationData, machineAnnotationState } from "state/MachineAnno import { UserAnnotationData, userAnnotationState } from "state/UserAnnotations"; import { i18nMixin } from "components/meta/i18n_mixin"; import { PropertyValues } from "@lit/reactive-element/development/reactive-element"; -import { initTooltips } from "util.js"; +import { initTooltips } from "utilities"; import { annotationState, compareAnnotationOrders } from "state/Annotations"; /** diff --git a/app/assets/javascripts/components/annotations/user_annotation.ts b/app/assets/javascripts/components/annotations/user_annotation.ts index 5f61cc10e4..7e4ab6c393 100644 --- a/app/assets/javascripts/components/annotations/user_annotation.ts +++ b/app/assets/javascripts/components/annotations/user_annotation.ts @@ -7,7 +7,7 @@ import { i18nMixin } from "components/meta/i18n_mixin"; import { AnnotationForm } from "components/annotations/annotation_form"; import { createRef, Ref, ref } from "lit/directives/ref.js"; import "components/saved_annotations/new_saved_annotation"; -import { initTooltips } from "util.js"; +import { initTooltips } from "utilities"; import "components/saved_annotations/saved_annotation_icon"; import { annotationState } from "state/Annotations"; diff --git a/app/assets/javascripts/components/copy_button.ts b/app/assets/javascripts/components/copy_button.ts index 55d06f87f7..27981aea12 100644 --- a/app/assets/javascripts/components/copy_button.ts +++ b/app/assets/javascripts/components/copy_button.ts @@ -1,7 +1,7 @@ import { ShadowlessLitElement } from "components/meta/shadowless_lit_element"; import { html, PropertyValues, TemplateResult } from "lit"; import { customElement, property } from "lit/decorators.js"; -import { initTooltips, ready } from "util.js"; +import { initTooltips, ready } from "utilities"; /** * A button that copies the text content of a given element to the clipboard. diff --git a/app/assets/javascripts/components/course_labels_search_bar.ts b/app/assets/javascripts/components/course_labels_search_bar.ts index ebaf694227..51adc732ce 100644 --- a/app/assets/javascripts/components/course_labels_search_bar.ts +++ b/app/assets/javascripts/components/course_labels_search_bar.ts @@ -2,7 +2,7 @@ import { customElement, property } from "lit/decorators.js"; import { html, TemplateResult } from "lit"; import { ShadowlessLitElement } from "components/meta/shadowless_lit_element"; import { Option } from "components/datalist_input"; -import { ready } from "util.js"; +import { ready } from "utilities"; import "components/datalist_input"; /** * This component represents a list of the selected course labels diff --git a/app/assets/javascripts/components/meta/i18n_mixin.ts b/app/assets/javascripts/components/meta/i18n_mixin.ts index 19d4342349..c33dc58759 100644 --- a/app/assets/javascripts/components/meta/i18n_mixin.ts +++ b/app/assets/javascripts/components/meta/i18n_mixin.ts @@ -1,5 +1,5 @@ import { LitElement } from "lit"; -import { ready } from "util.js"; +import { ready } from "utilities"; type Constructor = new (...args: any[]) => LitElement; diff --git a/app/assets/javascripts/components/progress_bar.ts b/app/assets/javascripts/components/progress_bar.ts index 65e821f64e..377bb953f6 100644 --- a/app/assets/javascripts/components/progress_bar.ts +++ b/app/assets/javascripts/components/progress_bar.ts @@ -1,7 +1,7 @@ import { html, TemplateResult } from "lit"; import { customElement, property } from "lit/decorators.js"; import { ShadowlessLitElement } from "components/meta/shadowless_lit_element"; -import { initTooltips, ready } from "../util"; +import { initTooltips, ready } from "../utilities"; /** * This component displays a progress bar consisting of consecutive divs diff --git a/app/assets/javascripts/components/search/filter_button.ts b/app/assets/javascripts/components/search/filter_button.ts index d1043c698a..d9eae32c78 100644 --- a/app/assets/javascripts/components/search/filter_button.ts +++ b/app/assets/javascripts/components/search/filter_button.ts @@ -1,7 +1,7 @@ import { customElement, property } from "lit/decorators.js"; import { css, html, LitElement, PropertyValues, TemplateResult } from "lit"; import { ShadowlessLitElement } from "components/meta/shadowless_lit_element"; -import { initTooltips } from "util.js"; +import { initTooltips } from "utilities"; import { searchQueryState } from "state/SearchQuery"; import { StateController } from "state/state_system/StateController"; diff --git a/app/assets/javascripts/components/search/search_actions.ts b/app/assets/javascripts/components/search/search_actions.ts index edb2baaee7..a843e116bb 100644 --- a/app/assets/javascripts/components/search/search_actions.ts +++ b/app/assets/javascripts/components/search/search_actions.ts @@ -1,7 +1,7 @@ import { html, TemplateResult } from "lit"; import { customElement, property } from "lit/decorators.js"; import { Toast } from "toast"; -import { fetch, ready } from "util.js"; +import { fetch, ready } from "utilities"; import { ShadowlessLitElement } from "components/meta/shadowless_lit_element"; import { searchQueryState } from "state/SearchQuery"; diff --git a/app/assets/javascripts/components/search/search_field.ts b/app/assets/javascripts/components/search/search_field.ts index 758f6a7358..0cbd501cce 100644 --- a/app/assets/javascripts/components/search/search_field.ts +++ b/app/assets/javascripts/components/search/search_field.ts @@ -1,6 +1,6 @@ import { customElement, property } from "lit/decorators.js"; import { html, TemplateResult } from "lit"; -import { createDelayer } from "util.js"; +import { createDelayer } from "utilities"; import { unsafeHTML } from "lit/directives/unsafe-html.js"; import { ref } from "lit/directives/ref.js"; import { ShadowlessLitElement } from "components/meta/shadowless_lit_element"; diff --git a/app/assets/javascripts/components/sign_in_search_bar.ts b/app/assets/javascripts/components/sign_in_search_bar.ts index 86c29fb4c9..526df09144 100644 --- a/app/assets/javascripts/components/sign_in_search_bar.ts +++ b/app/assets/javascripts/components/sign_in_search_bar.ts @@ -2,7 +2,7 @@ import { customElement, property } from "lit/decorators.js"; import { html, TemplateResult } from "lit"; import { ShadowlessLitElement } from "components/meta/shadowless_lit_element"; import { Option } from "components/datalist_input"; -import { ready } from "util.js"; +import { ready } from "utilities"; import "components/datalist_input"; /** diff --git a/app/assets/javascripts/copy.ts b/app/assets/javascripts/copy.ts index 9c4404639e..fb7ca317ad 100644 --- a/app/assets/javascripts/copy.ts +++ b/app/assets/javascripts/copy.ts @@ -1,14 +1,13 @@ import ClipboardJS from "clipboard"; -import { ready, tooltip } from "util.js"; +import { ready, tooltip } from "utilities"; export async function initClipboard(): Promise { await ready; const selector = ".btn"; - const delay = 1000; const clip = new ClipboardJS(selector); - const targetOf = (e): any => $($(e.trigger).data("clipboard-target")); - clip.on("success", e => tooltip(targetOf(e), I18n.t("js.copy-success"), delay)); - clip.on("error", e => tooltip(targetOf(e), I18n.t("js.copy-fail"), delay)); + const targetOf = (e): Element => document.querySelector(e.trigger.dataset["clipboard-target"]); + clip.on("success", e => tooltip(targetOf(e), I18n.t("js.copy-success"))); + clip.on("error", e => tooltip(targetOf(e), I18n.t("js.copy-fail"))); } /** diff --git a/app/assets/javascripts/course.ts b/app/assets/javascripts/course.ts index 5d7e92ec26..bf3c057449 100644 --- a/app/assets/javascripts/course.ts +++ b/app/assets/javascripts/course.ts @@ -1,5 +1,5 @@ import { initDragAndDrop } from "./drag_and_drop"; -import { fetch, getURLParameter } from "./util.js"; +import { fetch, getURLParameter } from "utilities"; import { ScrollSpy } from "./scrollspy"; import { html, render } from "lit"; import { Modal } from "bootstrap"; diff --git a/app/assets/javascripts/drag_and_drop.ts b/app/assets/javascripts/drag_and_drop.ts index a2a9c5f46b..4e69f6f897 100644 --- a/app/assets/javascripts/drag_and_drop.ts +++ b/app/assets/javascripts/drag_and_drop.ts @@ -1,5 +1,5 @@ import dragula from "dragula"; -import { fetch, getParentByClassName } from "util.js"; +import { fetch, getParentByClassName } from "utilities"; /** * Custom type for arguments of the drag and drop initialization diff --git a/app/assets/javascripts/evaluation.ts b/app/assets/javascripts/evaluation.ts index 28505fd3d2..0955aa1076 100644 --- a/app/assets/javascripts/evaluation.ts +++ b/app/assets/javascripts/evaluation.ts @@ -1,4 +1,4 @@ -import { fetch } from "util.js"; +import { fetch } from "utilities"; export function initCheckboxes(): void { document.querySelectorAll(".evaluation-users-table .user-row") diff --git a/app/assets/javascripts/exercise.ts b/app/assets/javascripts/exercise.ts index 94661974e5..c012dd02c8 100644 --- a/app/assets/javascripts/exercise.ts +++ b/app/assets/javascripts/exercise.ts @@ -1,5 +1,5 @@ /* globals ace */ -import { initTooltips, updateURLParameter, fetch } from "util.js"; +import { initTooltips, updateURLParameter, fetch } from "utilities"; import { Toast } from "./toast"; import GLightbox from "glightbox"; import { IFrameMessageData } from "iframe-resizer"; diff --git a/app/assets/javascripts/favorite_course_buttons.ts b/app/assets/javascripts/favorite_course_buttons.ts index fb37258f59..002b289f09 100644 --- a/app/assets/javascripts/favorite_course_buttons.ts +++ b/app/assets/javascripts/favorite_course_buttons.ts @@ -1,5 +1,5 @@ import { Toast } from "./toast"; -import { fetch, getParentByClassName } from "util.js"; +import { fetch, getParentByClassName } from "utilities"; function initFavoriteButtons(doc: Document | HTMLElement = document): void { function init(): void { diff --git a/app/assets/javascripts/feedback/actions.ts b/app/assets/javascripts/feedback/actions.ts index 5842ffa969..a194b778b5 100644 --- a/app/assets/javascripts/feedback/actions.ts +++ b/app/assets/javascripts/feedback/actions.ts @@ -1,4 +1,4 @@ -import { fetch, updateURLParameter } from "util.js"; +import { fetch, updateURLParameter } from "utilities"; import ScoreForm from "feedback/score"; interface ActionOptions { diff --git a/app/assets/javascripts/feedback/score.ts b/app/assets/javascripts/feedback/score.ts index 5b52e6c0ba..86bda2ac4c 100644 --- a/app/assets/javascripts/feedback/score.ts +++ b/app/assets/javascripts/feedback/score.ts @@ -1,4 +1,4 @@ -import { fetch, createDelayer } from "util.js"; +import { fetch, createDelayer } from "utilities"; import FeedbackActions from "feedback/actions"; /** diff --git a/app/assets/javascripts/institution.ts b/app/assets/javascripts/institution.ts index 4cd16ba44e..a941159e62 100644 --- a/app/assets/javascripts/institution.ts +++ b/app/assets/javascripts/institution.ts @@ -1,4 +1,4 @@ -import { fetch } from "./util.js"; +import { fetch } from "utilities"; function initInstitutionSelectionTable(institutionId: number): void { const institutionPanel = document.querySelector("#institution-panel"); diff --git a/app/assets/javascripts/lti.ts b/app/assets/javascripts/lti.ts index 3e94f93931..29e4655bcb 100644 --- a/app/assets/javascripts/lti.ts +++ b/app/assets/javascripts/lti.ts @@ -1,5 +1,5 @@ // Identifiers. -import { fetch, makeInvisible, makeVisible } from "util.js"; +import { fetch, makeInvisible, makeVisible } from "utilities"; import { isInIframe } from "iframe"; const redirectButtonId = "lti_redirect_button"; diff --git a/app/assets/javascripts/notification.ts b/app/assets/javascripts/notification.ts index 86483bcc0d..7866e111d1 100644 --- a/app/assets/javascripts/notification.ts +++ b/app/assets/javascripts/notification.ts @@ -1,5 +1,5 @@ import { FaviconManager } from "favicon"; -import { fetch } from "util.js"; +import { fetch } from "utilities"; import { InactiveTimeout } from "auto_reload"; /** diff --git a/app/assets/javascripts/pythia_submission.ts b/app/assets/javascripts/pythia_submission.ts index 04b6713fb5..a04d9fbdd5 100644 --- a/app/assets/javascripts/pythia_submission.ts +++ b/app/assets/javascripts/pythia_submission.ts @@ -1,6 +1,6 @@ import fscreen from "fscreen"; import { showInfoModal } from "./modal"; -import { fetch } from "./util.js"; +import { fetch } from "utilities"; import { html } from "lit"; function initPythiaSubmissionShow(submissionCode: string, activityPath: string): void { diff --git a/app/assets/javascripts/question_table.ts b/app/assets/javascripts/question_table.ts index d6aa443c8c..ea8554bf9a 100644 --- a/app/assets/javascripts/question_table.ts +++ b/app/assets/javascripts/question_table.ts @@ -1,4 +1,4 @@ -import { fetch } from "util.js"; +import { fetch } from "utilities"; import { InactiveTimeout } from "auto_reload"; const questionContainerId = "question-container"; diff --git a/app/assets/javascripts/repository.ts b/app/assets/javascripts/repository.ts index e10e85eb91..dcac3402b1 100644 --- a/app/assets/javascripts/repository.ts +++ b/app/assets/javascripts/repository.ts @@ -1,4 +1,4 @@ -import { fetch } from "./util.js"; +import { fetch } from "utilities"; import { Toast } from "./toast"; function initAdminsEdit(): void { diff --git a/app/assets/javascripts/score_item.ts b/app/assets/javascripts/score_item.ts index 52fc6fe5f1..d7554b4aaf 100644 --- a/app/assets/javascripts/score_item.ts +++ b/app/assets/javascripts/score_item.ts @@ -1,4 +1,4 @@ -import { fetch } from "util.js"; +import { fetch } from "utilities"; function commonCheckboxInit( element: HTMLElement, diff --git a/app/assets/javascripts/search.ts b/app/assets/javascripts/search.ts index 28e4090d91..20869e73c3 100644 --- a/app/assets/javascripts/search.ts +++ b/app/assets/javascripts/search.ts @@ -1,4 +1,4 @@ -import { createDelayer, fetch, getURLParameter, updateArrayURLParameter, updateURLParameter } from "util.js"; +import { createDelayer, fetch, getURLParameter, updateArrayURLParameter, updateURLParameter } from "utilities"; import { InactiveTimeout } from "auto_reload"; import { LoadingBar } from "components/search/loading_bar"; import { searchQueryState } from "state/SearchQuery"; diff --git a/app/assets/javascripts/series.ts b/app/assets/javascripts/series.ts index 2462017275..134373684b 100644 --- a/app/assets/javascripts/series.ts +++ b/app/assets/javascripts/series.ts @@ -1,6 +1,6 @@ import { Toast } from "./toast"; import { initDragAndDrop } from "./drag_and_drop"; -import { fetch } from "./util.js"; +import { fetch } from "utilities"; import { ViolinGraph } from "visualisations/violin"; import { StackedStatusGraph } from "visualisations/stacked_status"; diff --git a/app/assets/javascripts/state/SavedAnnotations.ts b/app/assets/javascripts/state/SavedAnnotations.ts index 8e7575a48f..9870c2d405 100644 --- a/app/assets/javascripts/state/SavedAnnotations.ts +++ b/app/assets/javascripts/state/SavedAnnotations.ts @@ -1,4 +1,4 @@ -import { updateArrayURLParameter, updateURLParameter, fetch, createDelayer } from "util.js"; +import { updateArrayURLParameter, updateURLParameter, fetch, createDelayer } from "utilities"; import { MapWithDefault } from "map_with_default"; import { userAnnotationState } from "state/UserAnnotations"; import { State } from "state/state_system/State"; diff --git a/app/assets/javascripts/state/SearchQuery.ts b/app/assets/javascripts/state/SearchQuery.ts index f997b3775e..1fe27bc8fb 100644 --- a/app/assets/javascripts/state/SearchQuery.ts +++ b/app/assets/javascripts/state/SearchQuery.ts @@ -1,6 +1,6 @@ import { State } from "state/state_system/State"; import { StateMap } from "state/state_system/StateMap"; -import { updateArrayURLParameter, updateURLParameter } from "util.js"; +import { updateArrayURLParameter, updateURLParameter } from "utilities"; class SearchQueryState extends State { readonly arrayQueryParams: StateMap = new StateMap(); diff --git a/app/assets/javascripts/state/Theme.ts b/app/assets/javascripts/state/Theme.ts index 8db605a1ce..fe32cda1c1 100644 --- a/app/assets/javascripts/state/Theme.ts +++ b/app/assets/javascripts/state/Theme.ts @@ -1,6 +1,6 @@ import { stateProperty } from "state/state_system/StateProperty"; import { State } from "state/state_system/State"; -import { getURLParameter, updateURLParameter } from "util.js"; +import { getURLParameter, updateURLParameter } from "utilities"; // The actual theme applied to the page export type Theme = "light" | "dark"; diff --git a/app/assets/javascripts/state/UserAnnotations.ts b/app/assets/javascripts/state/UserAnnotations.ts index c34e4a3328..aa0d3af25d 100644 --- a/app/assets/javascripts/state/UserAnnotations.ts +++ b/app/assets/javascripts/state/UserAnnotations.ts @@ -1,4 +1,4 @@ -import { createDelayer, fetch } from "util.js"; +import { createDelayer, fetch } from "utilities"; import { Notification } from "notification"; import { savedAnnotationState } from "state/SavedAnnotations"; import { State } from "state/state_system/State"; diff --git a/app/assets/javascripts/state/Users.ts b/app/assets/javascripts/state/Users.ts index 25d0a75bb5..a0341fb691 100644 --- a/app/assets/javascripts/state/Users.ts +++ b/app/assets/javascripts/state/Users.ts @@ -1,7 +1,7 @@ import { State } from "state/state_system/State"; import { stateProperty } from "state/state_system/StateProperty"; import { ThemeOption } from "state/Theme"; -import { fetch } from "util.js"; +import { fetch } from "utilities"; export type Permission = "annotation.create" diff --git a/app/assets/javascripts/submission.ts b/app/assets/javascripts/submission.ts index 904b3c3a3b..dd1d94575e 100644 --- a/app/assets/javascripts/submission.ts +++ b/app/assets/javascripts/submission.ts @@ -1,4 +1,4 @@ -import { getParentByClassName } from "util.js"; +import { getParentByClassName } from "utilities"; function initSubmissionShow(parentClass: string, mediaPath: string, token: string): void { function init(): void { diff --git a/app/assets/javascripts/util.js b/app/assets/javascripts/utilities.ts similarity index 69% rename from app/assets/javascripts/util.js rename to app/assets/javascripts/utilities.ts index 72dae4addd..f3939e4adb 100644 --- a/app/assets/javascripts/util.js +++ b/app/assets/javascripts/utilities.ts @@ -1,5 +1,6 @@ import { isInIframe } from "iframe"; import { Dutch } from "flatpickr/dist/l10n/nl"; +import { CustomLocale } from "flatpickr/dist/types/locale"; import flatpickr from "flatpickr"; /** @@ -25,9 +26,9 @@ import flatpickr from "flatpickr"; * * @return {function(TimerHandler, number): void} */ -function createDelayer() { - let timer = 0; - return function (callback, ms) { +function createDelayer(): (callback: () => void, ms: number) => void { + let timer; + return (callback, ms) => { clearTimeout(timer); timer = setTimeout(callback, ms); }; @@ -42,7 +43,7 @@ function createDelayer() { */ const delay = createDelayer(); -function updateURLParameter(_url, param, paramVal) { +function updateURLParameter(_url: string, param: string, paramVal: string): string { const url = new URL(_url, window.location.origin); if (paramVal) { url.searchParams.set(param, paramVal); @@ -52,7 +53,7 @@ function updateURLParameter(_url, param, paramVal) { return url.toString(); } -function updateArrayURLParameter(_url, param, _paramVals) { +function updateArrayURLParameter(_url: string, param: string, _paramVals: string[]): string { const paramVals = new Set(_paramVals); // remove duplicate items // convert "%5B%5D" back to "[]" const url = new URL(_url.replace(/%5B%5D/g, "[]"), window.location.origin); @@ -63,42 +64,32 @@ function updateArrayURLParameter(_url, param, _paramVals) { return url.toString(); } -function getURLParameter(name, _url) { +function getURLParameter(name: string, _url?: string): string { const url = new URL(_url ?? window.location.href, window.location.origin); return url.searchParams.get(name); } -function getArrayURLParameter(name, _url) { +function getArrayURLParameter(name: string, _url?: string): string[] { const url = new URL(_url ?? window.location.href, window.location.origin); return url.searchParams.getAll(`${name}[]`); } -function checkTimeZone(offset) { +function checkTimeZone(offset: number): void { if (offset !== new Date().getTimezoneOffset()) { - $("#time-zone-warning").removeClass("hidden"); + document.querySelector("#time-zone-warning").classList.remove("hidden"); } } -function checkIframe() { +function checkIframe(): void { if (isInIframe()) { - $("#iframe-warning").removeClass("hidden"); + document.querySelector("#iframe-warning").classList.remove("hidden"); } } -// add CSRF token to each ajax-request -async function initCSRF() { - await ready; - $.ajaxSetup({ - "headers": { - "X-CSRF-Token": $("meta[name='csrf-token']").attr("content"), - }, - }); -} - /** * @param {Document | Element} root */ -function initTooltips(root = document) { +function initTooltips(root: Document | Element = document): void { // First remove dead tooltips const tooltips = root.querySelectorAll(".tooltip"); for (const tooltip of tooltips) { @@ -106,7 +97,7 @@ function initTooltips(root = document) { } // Then reinitialize tooltips - const elements = root.querySelectorAll("[data-bs-toggle=\"tooltip\"]"); + const elements = root.querySelectorAll("[data-bs-toggle=\"tooltip\"]") as NodeListOf; for (const element of elements) { const tooltip = window.bootstrap.Tooltip.getOrCreateInstance(element); if (element.title) { @@ -116,19 +107,26 @@ function initTooltips(root = document) { } } -function tooltip(target, message, disappearAfter=1000) { - const $target = $(target); - const originalTitle = $target.attr("data-original-title"); - $target.attr("data-original-title", message).tooltip("show"); - $target.attr("title", message).tooltip("show"); - setTimeout(() => { - $target.attr("title", originalTitle).attr("data-original-title", originalTitle).tooltip(); - }, disappearAfter); +function tooltip(target: Element | null, message: string, disappearAfter = 3000): void { + if (target) { + const originalTitle = target.getAttribute("data-original-title"); + target.setAttribute("data-original-title", message); + target.setAttribute("title", message); + setTimeout(() => { + if (originalTitle) { + target.setAttribute("title", originalTitle); + target.setAttribute("data-original-title", originalTitle); + } else { + target.removeAttribute("title"); + target.removeAttribute("data-original-title"); + } + }, disappearAfter); + } } -function fetch(url, options = {}) { +function fetch(url: URL | RequestInfo, options: RequestInit = {}): Promise { const headers = options.headers || {}; - headers["x-csrf-token"] = headers["x-csrf-token"] || document.querySelector("meta[name=\"csrf-token\"]").content; + headers["x-csrf-token"] = headers["x-csrf-token"] || (document.querySelector("meta[name=\"csrf-token\"]") as HTMLMetaElement).content; headers["x-requested-with"] = headers["x-requested-with"] || "XMLHttpRequest"; options["headers"] = headers; return window.fetch(url, options); @@ -139,7 +137,7 @@ function fetch(url, options = {}) { * * @param {HTMLElement} element The element to hide. */ -function makeInvisible(element) { +function makeInvisible(element: HTMLElement): void { element.style.visibility = "hidden"; } @@ -148,7 +146,7 @@ function makeInvisible(element) { * * @param {HTMLElement} element The element to show. */ -function makeVisible(element) { +function makeVisible(element: HTMLElement): void { element.style.visibility = "visible"; } @@ -157,18 +155,27 @@ function makeVisible(element) { * * @param {string} title The new title. */ -function setDocumentTitle(title) { +function setDocumentTitle(title: string): void { document.title = title; } +type DatePickerOptions = { + wrap?: boolean, + enableTime?: boolean, + dateFormat?: string, + altInput?: boolean, + altFormat?: string, + locale?: CustomLocale +}; + /** * Initiates a datepicker using flatpicker * @param {string} selector - The selector of div containing the input field and buttons * @param {object} options - optional, Options object as should be provided to the flatpicker creation method * @return {flatpickr} the created flatpicker */ -function initDatePicker(selector, options = {}) { - function init() { +function initDatePicker(selector: string, options: DatePickerOptions = {}): object { + function init(): object { if (I18n.locale === "nl") { options.locale = Dutch; } @@ -182,7 +189,7 @@ function initDatePicker(selector, options = {}) { * This promise will resolve when the dom content is fully loaded * This could mean immediately if the dom is already loaded */ -const ready = new Promise(resolve => { +const ready = new Promise(resolve => { if (document.readyState !== "loading") { resolve(); } else { @@ -197,7 +204,7 @@ const ready = new Promise(resolve => { * @param {string} classNames - The class names to search for, separated by white space * @return {?Element} The parent containing the classes */ -function getParentByClassName(element, classNames) { +function getParentByClassName(element: Element, classNames: string): Element { let parent = element.parentElement; while (parent) { if (classNames.split(/\s+/).every(className => parent.classList.contains(className))) { @@ -218,7 +225,6 @@ export { getArrayURLParameter, checkTimeZone, checkIframe, - initCSRF, tooltip, initTooltips, makeInvisible, diff --git a/app/assets/javascripts/visualisations/series_graph.ts b/app/assets/javascripts/visualisations/series_graph.ts index 3b5463d514..d9b4a4edd5 100644 --- a/app/assets/javascripts/visualisations/series_graph.ts +++ b/app/assets/javascripts/visualisations/series_graph.ts @@ -1,7 +1,7 @@ // eslint-disable-next-line // @ts-nocheck import * as d3 from "d3"; -import { initDatePicker } from "util.js"; +import { initDatePicker } from "utilities"; import { themeState } from "state/Theme"; export type RawData = { diff --git a/app/javascript/packs/announcement.js b/app/javascript/packs/announcement.js index a927a1dcd3..3aa75bd503 100644 --- a/app/javascript/packs/announcement.js +++ b/app/javascript/packs/announcement.js @@ -1,4 +1,4 @@ -import { initDatePicker } from "util.js"; +import { initDatePicker } from "utilities.ts"; import "components/datalist_input"; dodona.initDatePicker = initDatePicker; diff --git a/app/javascript/packs/application_pack.js b/app/javascript/packs/application_pack.js index 7f1d518751..15863f8150 100644 --- a/app/javascript/packs/application_pack.js +++ b/app/javascript/packs/application_pack.js @@ -32,7 +32,7 @@ window.bootstrap = bootstrap; import { Drawer } from "drawer"; import { Toast } from "toast"; import { Notification } from "notification"; -import { checkTimeZone, checkIframe, initCSRF, initTooltips, ready } from "util.js"; +import { checkTimeZone, checkIframe, initTooltips, ready } from "utilities.ts"; import { initClipboard } from "copy"; import { FaviconManager } from "favicon"; import { themeState } from "state/Theme"; @@ -50,10 +50,6 @@ if (!window.dodona.hideDrawer) { ready.then(() => new Drawer()); } - -// Adds the CSRF token to each ajax request -initCSRF(); - ready.then(initTooltips); // Use a global dodona object to prevent polluting the global na diff --git a/app/javascript/packs/course.js b/app/javascript/packs/course.js index b35d0c7c82..b13a1432b3 100644 --- a/app/javascript/packs/course.js +++ b/app/javascript/packs/course.js @@ -11,7 +11,7 @@ import { RefreshingQuestionTable, toggleQuestionNavDot } from "question_table.ts"; -import { setDocumentTitle } from "util.js"; +import { setDocumentTitle } from "utilities.ts"; window.dodona.initSeriesReorder = initSeriesReorder; window.dodona.initCourseForm = initCourseForm; diff --git a/app/javascript/packs/evaluation.js b/app/javascript/packs/evaluation.js index 226029cdd8..d14b4a2e38 100644 --- a/app/javascript/packs/evaluation.js +++ b/app/javascript/packs/evaluation.js @@ -1,6 +1,6 @@ import { initCheckboxes, initCheckbox, initEvaluationStepper } from "evaluation.ts"; import FeedbackActions from "feedback/actions"; -import { initDatePicker } from "util.js"; +import { initDatePicker } from "utilities.ts"; window.dodona.initDeadlinePicker = initDatePicker; window.dodona.initCheckbox = initCheckbox; diff --git a/app/javascript/packs/frame.js b/app/javascript/packs/frame.js index 2074c4648d..d6530d30be 100644 --- a/app/javascript/packs/frame.js +++ b/app/javascript/packs/frame.js @@ -13,7 +13,7 @@ import { Alert, Button, Collapse, Dropdown, Modal, Popover, Tab, Tooltip } from const bootstrap = { Alert, Button, Collapse, Dropdown, Modal, Popover, Tab, Tooltip }; window.bootstrap = bootstrap; -import { initTooltips, ready } from "util.js"; +import { initTooltips, ready } from "utilities.ts"; import { initClipboard } from "copy"; import { themeState } from "state/Theme"; diff --git a/app/javascript/packs/series.js b/app/javascript/packs/series.js index 24e4456805..76b75efa9d 100644 --- a/app/javascript/packs/series.js +++ b/app/javascript/packs/series.js @@ -1,5 +1,5 @@ import { initSeriesEdit, initSeriesShow } from "series.ts"; -import { initDatePicker } from "util.js"; +import { initDatePicker } from "utilities.ts"; window.dodona.initDeadlinePicker = initDatePicker; window.dodona.initSeriesEdit = initSeriesEdit; diff --git a/test/javascript/components/search/search_actions.test.ts b/test/javascript/components/search/search_actions.test.ts index 137fe5951c..a357cde1a2 100644 --- a/test/javascript/components/search/search_actions.test.ts +++ b/test/javascript/components/search/search_actions.test.ts @@ -4,7 +4,7 @@ import { fixture, nextFrame } from "@open-wc/testing-helpers"; import userEvent from "@testing-library/user-event"; import { screen } from "@testing-library/dom"; import { html } from "lit"; -import * as util from "util.js"; +import * as util from "utilities"; import { searchQueryState } from "state/SearchQuery"; describe("SearchActions", () => { diff --git a/test/javascript/util.test.js b/test/javascript/utilities.test.js similarity index 98% rename from test/javascript/util.test.js rename to test/javascript/utilities.test.js index 3ed6c30eb5..5f73cbae4a 100644 --- a/test/javascript/util.test.js +++ b/test/javascript/utilities.test.js @@ -1,7 +1,7 @@ import { updateArrayURLParameter, updateURLParameter, getURLParameter, getArrayURLParameter, delay, createDelayer -} from "../../app/assets/javascripts/util"; +} from "utilities.ts"; jest.useFakeTimers();