Skip to content

Commit

Permalink
TS: Converted dom and keyboard nav services
Browse files Browse the repository at this point in the history
  • Loading branch information
ssddanbrown committed Oct 11, 2024
1 parent f41c02c commit 209fa04
Show file tree
Hide file tree
Showing 28 changed files with 87 additions and 98 deletions.
2 changes: 1 addition & 1 deletion dev/build/esbuild.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const isProd = process.argv[2] === 'production';

// Gather our input files
const entryPoints = {
app: path.join(__dirname, '../../resources/js/app.js'),
app: path.join(__dirname, '../../resources/js/app.ts'),
code: path.join(__dirname, '../../resources/js/code/index.mjs'),
'legacy-modes': path.join(__dirname, '../../resources/js/code/legacy-modes.mjs'),
markdown: path.join(__dirname, '../../resources/js/markdown/index.mjs'),
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/add-remove-rows.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {onChildEvent} from '../services/dom';
import {onChildEvent} from '../services/dom.ts';
import {uniqueId} from '../services/util.ts';
import {Component} from './component';

Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/ajax-delete-row.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {onSelect} from '../services/dom';
import {onSelect} from '../services/dom.ts';
import {Component} from './component';

export class AjaxDeleteRow extends Component {
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/ajax-form.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {onEnterPress, onSelect} from '../services/dom';
import {onEnterPress, onSelect} from '../services/dom.ts';
import {Component} from './component';

/**
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/attachments.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {showLoading} from '../services/dom';
import {showLoading} from '../services/dom.ts';
import {Component} from './component';

export class Attachments extends Component {
Expand Down
4 changes: 2 additions & 2 deletions resources/js/components/auto-suggest.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {escapeHtml} from '../services/util.ts';
import {onChildEvent} from '../services/dom';
import {onChildEvent} from '../services/dom.ts';
import {Component} from './component';
import {KeyboardNavigationHandler} from '../services/keyboard-navigation';
import {KeyboardNavigationHandler} from '../services/keyboard-navigation.ts';

const ajaxCache = {};

Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/book-sort.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Sortable, {MultiDrag} from 'sortablejs';
import {Component} from './component';
import {htmlToDom} from '../services/dom';
import {htmlToDom} from '../services/dom.ts';

// Auto sort control
const sortOperations = {
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/code-editor.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {onChildEvent, onEnterPress, onSelect} from '../services/dom';
import {onChildEvent, onEnterPress, onSelect} from '../services/dom.ts';
import {Component} from './component';

export class CodeEditor extends Component {
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/confirm-dialog.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {onSelect} from '../services/dom';
import {onSelect} from '../services/dom.ts';
import {Component} from './component';

/**
Expand Down
4 changes: 2 additions & 2 deletions resources/js/components/dropdown.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {onSelect} from '../services/dom';
import {KeyboardNavigationHandler} from '../services/keyboard-navigation';
import {onSelect} from '../services/dom.ts';
import {KeyboardNavigationHandler} from '../services/keyboard-navigation.ts';
import {Component} from './component';

/**
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/dropzone.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {Component} from './component';
import {Clipboard} from '../services/clipboard.ts';
import {
elem, getLoading, onSelect, removeLoading,
} from '../services/dom';
} from '../services/dom.ts';

export class Dropzone extends Component {

Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/entity-permissions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {htmlToDom} from '../services/dom';
import {htmlToDom} from '../services/dom.ts';
import {Component} from './component';

export class EntityPermissions extends Component {
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/entity-search.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {onSelect} from '../services/dom';
import {onSelect} from '../services/dom.ts';
import {Component} from './component';

export class EntitySearch extends Component {
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/entity-selector.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {onChildEvent} from '../services/dom';
import {onChildEvent} from '../services/dom.ts';
import {Component} from './component';

/**
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/event-emit-select.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {onSelect} from '../services/dom';
import {onSelect} from '../services/dom.ts';
import {Component} from './component';

/**
Expand Down
4 changes: 2 additions & 2 deletions resources/js/components/global-search.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {htmlToDom} from '../services/dom';
import {htmlToDom} from '../services/dom.ts';
import {debounce} from '../services/util.ts';
import {KeyboardNavigationHandler} from '../services/keyboard-navigation';
import {KeyboardNavigationHandler} from '../services/keyboard-navigation.ts';
import {Component} from './component';

/**
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/image-manager.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
onChildEvent, onSelect, removeLoading, showLoading,
} from '../services/dom';
} from '../services/dom.ts';
import {Component} from './component';

export class ImageManager extends Component {
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/optional-input.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {onSelect} from '../services/dom';
import {onSelect} from '../services/dom.ts';
import {Component} from './component';

export class OptionalInput extends Component {
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/page-comment.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Component} from './component';
import {getLoading, htmlToDom} from '../services/dom';
import {getLoading, htmlToDom} from '../services/dom.ts';
import {buildForInput} from '../wysiwyg-tinymce/config';

export class PageComment extends Component {
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/page-comments.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Component} from './component';
import {getLoading, htmlToDom} from '../services/dom';
import {getLoading, htmlToDom} from '../services/dom.ts';
import {buildForInput} from '../wysiwyg-tinymce/config';

export class PageComments extends Component {
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/page-display.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as DOM from '../services/dom';
import * as DOM from '../services/dom.ts';
import {scrollAndHighlightElement} from '../services/util.ts';
import {Component} from './component';

Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/page-editor.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {onSelect} from '../services/dom';
import {onSelect} from '../services/dom.ts';
import {debounce} from '../services/util.ts';
import {Component} from './component';
import {utcTimeStampToLocalTime} from '../services/dates.ts';
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/pointer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as DOM from '../services/dom';
import * as DOM from '../services/dom.ts';
import {Component} from './component';
import {copyTextToClipboard} from '../services/clipboard.ts';

Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/popup.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {fadeIn, fadeOut} from '../services/animations.ts';
import {onSelect} from '../services/dom';
import {onSelect} from '../services/dom.ts';
import {Component} from './component';

/**
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/template-manager.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as DOM from '../services/dom';
import * as DOM from '../services/dom.ts';
import {Component} from './component';

export class TemplateManager extends Component {
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/user-select.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {onChildEvent} from '../services/dom';
import {onChildEvent} from '../services/dom.ts';
import {Component} from './component';

export class UserSelect extends Component {
Expand Down
85 changes: 36 additions & 49 deletions resources/js/services/dom.js → resources/js/services/dom.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
/**
* Check if the given param is a HTMLElement
*/
export function isHTMLElement(el: any): el is HTMLElement {
return el instanceof HTMLElement;
}

/**
* Create a new element with the given attrs and children.
* Children can be a string for text nodes or other elements.
* @param {String} tagName
* @param {Object<String, String>} attrs
* @param {Element[]|String[]}children
* @return {*}
*/
export function elem(tagName, attrs = {}, children = []) {
export function elem(tagName: string, attrs: Record<string, string> = {}, children: Element[]|string[] = []): HTMLElement {
const el = document.createElement(tagName);

for (const [key, val] of Object.entries(attrs)) {
Expand All @@ -30,10 +33,8 @@ export function elem(tagName, attrs = {}, children = []) {

/**
* Run the given callback against each element that matches the given selector.
* @param {String} selector
* @param {Function<Element>} callback
*/
export function forEach(selector, callback) {
export function forEach(selector: string, callback: (el: Element) => any) {
const elements = document.querySelectorAll(selector);
for (const element of elements) {
callback(element);
Expand All @@ -42,11 +43,8 @@ export function forEach(selector, callback) {

/**
* Helper to listen to multiple DOM events
* @param {Element} listenerElement
* @param {Array<String>} events
* @param {Function<Event>} callback
*/
export function onEvents(listenerElement, events, callback) {
export function onEvents(listenerElement: Element, events: string[], callback: (e: Event) => any): void {
for (const eventName of events) {
listenerElement.addEventListener(eventName, callback);
}
Expand All @@ -55,10 +53,8 @@ export function onEvents(listenerElement, events, callback) {
/**
* Helper to run an action when an element is selected.
* A "select" is made to be accessible, So can be a click, space-press or enter-press.
* @param {HTMLElement|Array} elements
* @param {function} callback
*/
export function onSelect(elements, callback) {
export function onSelect(elements: HTMLElement|HTMLElement[], callback: (e: Event) => any): void {
if (!Array.isArray(elements)) {
elements = [elements];
}
Expand All @@ -76,16 +72,13 @@ export function onSelect(elements, callback) {

/**
* Listen to key press on the given element(s).
* @param {String} key
* @param {HTMLElement|Array} elements
* @param {function} callback
*/
function onKeyPress(key, elements, callback) {
function onKeyPress(key: string, elements: HTMLElement|HTMLElement[], callback: (e: KeyboardEvent) => any): void {
if (!Array.isArray(elements)) {
elements = [elements];
}

const listener = event => {
const listener = (event: KeyboardEvent) => {
if (event.key === key) {
callback(event);
}
Expand All @@ -96,34 +89,31 @@ function onKeyPress(key, elements, callback) {

/**
* Listen to enter press on the given element(s).
* @param {HTMLElement|Array} elements
* @param {function} callback
*/
export function onEnterPress(elements, callback) {
export function onEnterPress(elements: HTMLElement|HTMLElement[], callback: (e: KeyboardEvent) => any): void {
onKeyPress('Enter', elements, callback);
}

/**
* Listen to escape press on the given element(s).
* @param {HTMLElement|Array} elements
* @param {function} callback
*/
export function onEscapePress(elements, callback) {
export function onEscapePress(elements: HTMLElement|HTMLElement[], callback: (e: KeyboardEvent) => any): void {
onKeyPress('Escape', elements, callback);
}

/**
* Set a listener on an element for an event emitted by a child
* matching the given childSelector param.
* Used in a similar fashion to jQuery's $('listener').on('eventName', 'childSelector', callback)
* @param {Element} listenerElement
* @param {String} childSelector
* @param {String} eventName
* @param {Function} callback
*/
export function onChildEvent(listenerElement, childSelector, eventName, callback) {
listenerElement.addEventListener(eventName, event => {
const matchingChild = event.target.closest(childSelector);
export function onChildEvent(
listenerElement: HTMLElement,
childSelector: string,
eventName: string,
callback: (this: HTMLElement, e: Event, child: HTMLElement) => any
): void {
listenerElement.addEventListener(eventName, (event: Event) => {
const matchingChild = (event.target as HTMLElement|null)?.closest(childSelector) as HTMLElement;
if (matchingChild) {
callback.call(matchingChild, event, matchingChild);
}
Expand All @@ -132,16 +122,13 @@ export function onChildEvent(listenerElement, childSelector, eventName, callback

/**
* Look for elements that match the given selector and contain the given text.
* Is case insensitive and returns the first result or null if nothing is found.
* @param {String} selector
* @param {String} text
* @returns {Element}
* Is case-insensitive and returns the first result or null if nothing is found.
*/
export function findText(selector, text) {
export function findText(selector: string, text: string): Element|null {
const elements = document.querySelectorAll(selector);
text = text.toLowerCase();
for (const element of elements) {
if (element.textContent.toLowerCase().includes(text)) {
if ((element.textContent || '').toLowerCase().includes(text) && isHTMLElement(element)) {
return element;
}
}
Expand All @@ -151,17 +138,15 @@ export function findText(selector, text) {
/**
* Show a loading indicator in the given element.
* This will effectively clear the element.
* @param {Element} element
*/
export function showLoading(element) {
export function showLoading(element: HTMLElement): void {
element.innerHTML = '<div class="loading-container"><div></div><div></div><div></div></div>';
}

/**
* Get a loading element indicator element.
* @returns {Element}
*/
export function getLoading() {
export function getLoading(): HTMLElement {
const wrap = document.createElement('div');
wrap.classList.add('loading-container');
wrap.innerHTML = '<div></div><div></div><div></div>';
Expand All @@ -170,9 +155,8 @@ export function getLoading() {

/**
* Remove any loading indicators within the given element.
* @param {Element} element
*/
export function removeLoading(element) {
export function removeLoading(element: HTMLElement): void {
const loadingEls = element.querySelectorAll('.loading-container');
for (const el of loadingEls) {
el.remove();
Expand All @@ -182,12 +166,15 @@ export function removeLoading(element) {
/**
* Convert the given html data into a live DOM element.
* Initiates any components defined in the data.
* @param {String} html
* @returns {Element}
*/
export function htmlToDom(html) {
export function htmlToDom(html: string): HTMLElement {
const wrap = document.createElement('div');
wrap.innerHTML = html;
window.$components.init(wrap);
return wrap.children[0];
const firstChild = wrap.children[0];
if (!isHTMLElement(firstChild)) {
throw new Error('Could not find child HTMLElement when creating DOM element from HTML');
}

return firstChild;
}
Loading

0 comments on commit 209fa04

Please sign in to comment.