diff --git a/Rakefile b/Rakefile index 0eecafcd..048e4ce9 100644 --- a/Rakefile +++ b/Rakefile @@ -1,13 +1,13 @@ require "bundler/setup" task :test do - Dir.chdir("test/rails/dummy") { system("bundle exec rails test:all") } + Dir.chdir("test/rails/dummy") { sh("bundle exec rails test:all") } end namespace :ci do task :test do Dir.chdir("test/rails/dummy") do - system("bundle exec rails db:prepare && bundle exec rails test:all") + sh("bundle exec rails db:prepare && bundle exec rails test:all") end end end diff --git a/src/clickHandler.ts b/src/clickHandler.ts index 1b2c43c0..3a55ed7c 100644 --- a/src/clickHandler.ts +++ b/src/clickHandler.ts @@ -3,28 +3,37 @@ import { preventInsignificantClick } from './utils/misc' import { EventQueryInterface, MrujsPluginInterface } from './types' export function ClickHandler (): MrujsPluginInterface { + const callbacks = [preventInsignificantClick] as EventListener[] + let queries: EventQueryInterface[] = [] + + function initialize (): void { + queries = getQueries() + } + + function connect (): void { + addListeners(queries, callbacks) + } + + function disconnect (): void { + removeListeners(queries, callbacks) + } + + function observerCallback (nodeList: Node[]): void { + attachObserverCallback(queries, nodeList, callbacks) + } + return { name: 'ClickHandler', + initialize, connect, disconnect, observerCallback, - queries + queries, + callbacks } } -function connect (): void { - addListeners(queries(), [preventInsignificantClick] as EventListener[]) -} - -function disconnect (): void { - removeListeners(queries(), [preventInsignificantClick] as EventListener[]) -} - -function observerCallback (nodeList: Node[]): void { - attachObserverCallback(queries(), nodeList, [preventInsignificantClick] as EventListener[]) -} - -function queries (): EventQueryInterface[] { +function getQueries (): EventQueryInterface[] { const { querySelectors } = window.mrujs return [ { diff --git a/src/confirm.ts b/src/confirm.ts index 18e17048..29fc224d 100644 --- a/src/confirm.ts +++ b/src/confirm.ts @@ -3,9 +3,28 @@ import { addListeners, removeListeners, attachObserverCallback } from './utils/d import { EventQueryInterface, MrujsPluginInterface } from './types' export function Confirm (): MrujsPluginInterface { - const callbacks = [handleConfirm] + const callbacks = [handleConfirm] as EventListener[] + let queries: EventQueryInterface[] = [] + + function initialize (): void { + queries = getQueries() + } + + function connect (): void { + addListeners(queries, callbacks) + } + + function disconnect (): void { + removeListeners(queries, callbacks) + } + + function observerCallback (nodeList: Node[]): void { + attachObserverCallback(queries, nodeList, callbacks) + } + return { name: 'Confirm', + initialize, connect, disconnect, observerCallback, @@ -14,18 +33,6 @@ export function Confirm (): MrujsPluginInterface { } } -function connect (): void { - addListeners(queries(), window.mrujs.confirmClass.callbacks as EventListener[]) -} - -function disconnect (): void { - removeListeners(queries(), window.mrujs.confirmClass.callbacks as EventListener[]) -} - -function observerCallback (nodeList: Node[]): void { - attachObserverCallback(queries(), nodeList, window.mrujs.confirmClass.callbacks as EventListener[]) -} - function handleConfirm (event: Event | CustomEvent): void { if (event.currentTarget == null) return @@ -50,7 +57,7 @@ function handleConfirm (event: Event | CustomEvent): void { stopEverything(event) } -function queries (): EventQueryInterface[] { +function getQueries (): EventQueryInterface[] { const { querySelectors } = window.mrujs return [ { diff --git a/src/csrf.ts b/src/csrf.ts index cb579bf4..ed121ce4 100644 --- a/src/csrf.ts +++ b/src/csrf.ts @@ -18,11 +18,9 @@ function connect (): void { function disconnect (): void {} function observerCallback (nodeList: Node[]): void { - nodeList.forEach((node) => { - if (isCsrfToken(node)) { - refresh() - } - }) + for (const node of Array.from(nodeList)) { + if (isCsrfToken(node)) refresh() + } } // Make sure that all forms have actual up-to-date tokens (cached forms contain old ones) @@ -41,11 +39,7 @@ function refresh (): void { } function isCsrfToken (node: Node): boolean { - if (node instanceof HTMLMetaElement) { - return node.matches('meta[name="csrf-token]"') - } - - return false + return (node as Element)?.matches('meta[name="csrf-token]"') ?? false } // Up-to-date Cross-Site Request Forgery token diff --git a/src/disabledElementChecker.ts b/src/disabledElementChecker.ts index 143081d6..c1f9f0da 100644 --- a/src/disabledElementChecker.ts +++ b/src/disabledElementChecker.ts @@ -3,28 +3,37 @@ import { addListeners, removeListeners, attachObserverCallback } from './utils/d import { stopEverything } from './utils/events' export function DisabledElementChecker (): MrujsPluginInterface { + const callbacks = [handleDisabledElement] as EventListener[] + let queries: EventQueryInterface[] = [] + + function initialize (): void { + queries = getQueries() + } + + function connect (): void { + addListeners(queries, callbacks) + } + + function disconnect (): void { + removeListeners(queries, callbacks) + } + + function observerCallback (nodeList: Node[]): void { + attachObserverCallback(queries, nodeList, callbacks) + } + return { name: 'DisabledElementChecker', + initialize, connect, disconnect, observerCallback, - queries + queries, + callbacks } } -function connect (): void { - addListeners(queries(), [handleDisabledElement]) -} - -function disconnect (): void { - removeListeners(queries(), [handleDisabledElement]) -} - -function observerCallback (nodeList: Node[]): void { - attachObserverCallback(queries(), nodeList, [handleDisabledElement]) -} - -function queries (): EventQueryInterface[] { +function getQueries (): EventQueryInterface[] { const { linkClickSelector, buttonClickSelector, inputChangeSelector, formSubmitSelector, formInputClickSelector } = window.mrujs.querySelectors return [ diff --git a/src/elementDisabler.ts b/src/elementDisabler.ts index 2fcb3fd7..9abf57d1 100644 --- a/src/elementDisabler.ts +++ b/src/elementDisabler.ts @@ -3,8 +3,28 @@ import { attachObserverCallback, addListeners, removeListeners, findFormElements import { stopEverything } from './utils/events' export function ElementDisabler (): MrujsPluginInterface { + const callbacks = [disableElement] as EventListener[] + let queries: EventQueryInterface[] = [] + + function initialize (): void { + queries = getQueries() + } + + function connect (): void { + addListeners(queries, callbacks) + } + + function disconnect (): void { + removeListeners(queries, callbacks) + } + + function observerCallback (nodeList: Node[]): void { + attachObserverCallback(queries, nodeList, callbacks) + } + return { name: 'ElementDisabler', + initialize, connect, disconnect, observerCallback, @@ -12,7 +32,7 @@ export function ElementDisabler (): MrujsPluginInterface { } } -function queries (): EventQueryInterface[] { +function getQueries (): EventQueryInterface[] { const { formSubmitSelector, linkClickSelector, buttonClickSelector, inputChangeSelector } = window.mrujs.querySelectors return [ @@ -22,18 +42,6 @@ function queries (): EventQueryInterface[] { ] } -function connect (): void { - addListeners(queries(), [disableElement]) -} - -function disconnect (): void { - removeListeners(queries(), [disableElement]) -} - -function observerCallback (nodeList: Node[]): void { - attachObserverCallback(queries(), nodeList, [disableElement]) -} - /** * Unified function to disable an element (link, button and form) */ diff --git a/src/elementEnabler.ts b/src/elementEnabler.ts index e7e55854..b2faa0e6 100644 --- a/src/elementEnabler.ts +++ b/src/elementEnabler.ts @@ -3,15 +3,36 @@ import { stopEverything, AJAX_EVENTS } from './utils/events' import { EventQueryInterface, MrujsPluginInterface } from './types' export function ElementEnabler (): MrujsPluginInterface { + const callbacks = [enableElement] as EventListener[] + let queries: EventQueryInterface[] = [] + + function initialize (): void { + queries = getQueries() + } + + function connect (): void { + addListeners(queries, callbacks) + } + + function disconnect (): void { + removeListeners(queries, callbacks) + } + + function observerCallback (nodeList: Node[]): void { + attachObserverCallback(queries, nodeList, callbacks) + } + return { name: 'ElementEnabler', + initialize, connect, disconnect, - observerCallback + observerCallback, + callbacks } } -function queries (): EventQueryInterface[] { +function getQueries (): EventQueryInterface[] { const { formSubmitSelector, buttonDisableSelector, linkDisableSelector, inputChangeSelector } = window.mrujs.querySelectors const selectors = [linkDisableSelector.selector, buttonDisableSelector.selector, @@ -22,18 +43,6 @@ function queries (): EventQueryInterface[] { ] } -function connect (): void { - addListeners(queries(), [enableElement]) -} - -function disconnect (): void { - removeListeners(queries(), [enableElement]) -} - -function observerCallback (nodeList: Node[]): void { - attachObserverCallback(queries(), nodeList, [enableElement]) -} - // Unified function to enable an element (link, button and form) export function enableElement (trigger: Event | HTMLElement): void { let element = trigger as HTMLElement diff --git a/src/mrujs.ts b/src/mrujs.ts index ef1bd2b7..e634fca1 100644 --- a/src/mrujs.ts +++ b/src/mrujs.ts @@ -16,7 +16,6 @@ import { FetchRequest } from './http/fetchRequest' import { addListeners, removeListeners, attachObserverCallback, BASE_SELECTORS } from './utils/dom' import { BASE_ACCEPT_HEADERS } from './utils/headers' import { - MrujsPluginInterface, MrujsConfigInterface, QuerySelectorInterface, MimeTypeInterface, @@ -116,11 +115,10 @@ function start (this: MrujsInterface, config: Partial = {} this.plugins = this.config.plugins this.allPlugins = this.corePlugins.concat(this.plugins) - this.allPlugins.forEach((plugin) => { - if (typeof plugin.initialize === 'function') { - plugin.initialize() - } - }) + for (let i = 0; i < this.allPlugins.length; i++) { + const plugin = this.allPlugins[i] + plugin.initialize?.() + } connect() @@ -144,9 +142,10 @@ function connect (): void { reEnableDisabledElements() window.addEventListener('pageshow', reEnableDisabledElements) - window.mrujs.allPlugins.forEach((plugin: MrujsPluginInterface) => { - plugin?.connect() - }) + for (let i = 0; i < window.mrujs.allPlugins.length; i++) { + const plugin = window.mrujs.allPlugins[i] + plugin.connect?.() + } window.mrujs.connected = true } @@ -154,9 +153,10 @@ function connect (): void { function disconnect (): void { window.removeEventListener('pageshow', reEnableDisabledElements) - window.mrujs.allPlugins.forEach((plugin: MrujsPluginInterface) => { - plugin?.disconnect() - }) + for (let i = 0; i < window.mrujs.allPlugins.length; i++) { + const plugin = window.mrujs.allPlugins[i] + plugin.disconnect?.() + } window.mrujs.connected = false } @@ -176,13 +176,12 @@ function addedNodesCallback (this: MrujsInterface, mutationList: MutationRecord[ } // kick it into an animation frame so we dont delay rendering - window.requestAnimationFrame(() => { - window.mrujs.allPlugins.forEach((plugin: MrujsPluginInterface) => { - if (typeof plugin.observerCallback === 'function') { - plugin.observerCallback(addedNodes) - } - }) - }) + window.setTimeout(() => { + for (let i = 0; i < window.mrujs.allPlugins.length; i++) { + const plugin = window.mrujs.allPlugins[i] + plugin.observerCallback?.(addedNodes) + } + }, 0) } } diff --git a/src/remoteWatcher.ts b/src/remoteWatcher.ts index db7853cd..72756ec1 100644 --- a/src/remoteWatcher.ts +++ b/src/remoteWatcher.ts @@ -2,38 +2,40 @@ import { MrujsPluginInterface } from './types' import { match } from './utils/dom' export function RemoteWatcher (): MrujsPluginInterface { - return { - name: 'RemoteWatcher', - connect, - disconnect, - observerCallback + let query: string + function initialize (): void { + query = window.mrujs.querySelectors.remoteSelector.selector } -} -function query (): string { - return window.mrujs.querySelectors.remoteSelector.selector -} + function connect (): void { + document.querySelectorAll(query).forEach((el): void => { + addTurboFalse(el) + }) + } -function connect (): void { - document.querySelectorAll(query()).forEach((el): void => { - addTurboFalse(el) - }) -} + function disconnect (): void {} -function disconnect (): void {} + function observerCallback (nodeList: Node[]): void { + nodeList.forEach((node) => { + if (match(node, window.mrujs.querySelectors.remoteSelector)) { + addTurboFalse(node as Element) + } -function observerCallback (nodeList: Node[]): void { - nodeList.forEach((node) => { - if (match(node, window.mrujs.querySelectors.remoteSelector)) { - addTurboFalse(node as Element) - } + if (node instanceof Element) { + node.querySelectorAll(query).forEach((el) => { + addTurboFalse(el) + }) + } + }) + } - if (node instanceof Element) { - node.querySelectorAll(query()).forEach((el) => { - addTurboFalse(el) - }) - } - }) + return { + name: 'RemoteWatcher', + initialize, + connect, + disconnect, + observerCallback + } } function addTurboFalse (el: Element): void { diff --git a/src/types.ts b/src/types.ts index e7fa321f..873c5895 100644 --- a/src/types.ts +++ b/src/types.ts @@ -58,10 +58,10 @@ export interface MimeTypeInterface { export interface MrujsPluginInterface { name: string initialize?: () => void - connect: () => void - disconnect: () => void + connect?: () => void + disconnect?: () => void observerCallback?: (addedNodes: Node[]) => void - queries?: () => EventQueryInterface[] + queries?: EventQueryInterface[] callbacks?: Function[] }