Closes #5858: Implement a quick-add UI widget for related objects (#18016)

* WIP

* Misc cleanup

* Add warning re: nested quick-adds
This commit is contained in:
Jeremy Stretch
2024-11-18 14:44:57 -05:00
committed by GitHub
parent 9fe6685562
commit b4f15092db
17 changed files with 236 additions and 76 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,5 @@
import { getElements } from '../util';
/**
* Create a slug from any input string.
*
@@ -15,34 +17,30 @@ function slugify(slug: string, chars: number): string {
}
/**
* If a slug field exists, add event listeners to handle automatically generating its value.
* For any slug fields, add event listeners to handle automatically generating slug values.
*/
export function initReslug(): void {
const slugField = document.getElementById('id_slug') as HTMLInputElement;
const slugButton = document.getElementById('reslug') as HTMLButtonElement;
if (slugField === null || slugButton === null) {
return;
}
const sourceId = slugField.getAttribute('slug-source');
const sourceField = document.getElementById(`id_${sourceId}`) as HTMLInputElement;
for (const slugButton of getElements<HTMLButtonElement>('button#reslug')) {
const form = slugButton.form;
if (form == null) continue;
const slugField = form.querySelector('#id_slug') as HTMLInputElement;
if (slugField == null) continue;
const sourceId = slugField.getAttribute('slug-source');
const sourceField = form.querySelector(`#id_${sourceId}`) as HTMLInputElement;
if (sourceField === null) {
console.error('Unable to find field for slug field.');
return;
}
const slugLengthAttr = slugField.getAttribute('maxlength');
let slugLength = 50;
const slugLengthAttr = slugField.getAttribute('maxlength');
let slugLength = 50;
if (slugLengthAttr) {
slugLength = Number(slugLengthAttr);
}
sourceField.addEventListener('blur', () => {
if (!slugField.value) {
slugField.value = slugify(sourceField.value, slugLength);
if (slugLengthAttr) {
slugLength = Number(slugLengthAttr);
}
});
slugButton.addEventListener('click', () => {
slugField.value = slugify(sourceField.value, slugLength);
});
sourceField.addEventListener('blur', () => {
if (!slugField.value) {
slugField.value = slugify(sourceField.value, slugLength);
}
});
slugButton.addEventListener('click', () => {
slugField.value = slugify(sourceField.value, slugLength);
});
}
}

View File

@@ -4,11 +4,16 @@ import { initSelects } from './select';
import { initObjectSelector } from './objectSelector';
import { initBootstrap } from './bs';
import { initMessages } from './messages';
import { initQuickAdd } from './quickAdd';
function initDepedencies(): void {
for (const init of [initButtons, initClipboard, initSelects, initObjectSelector, initBootstrap, initMessages]) {
init();
}
initButtons();
initClipboard();
initSelects();
initObjectSelector();
initQuickAdd();
initBootstrap();
initMessages();
}
/**

View File

@@ -0,0 +1,39 @@
import { Modal } from 'bootstrap';
function handleQuickAddObject(): void {
const quick_add = document.getElementById('quick-add-object');
if (quick_add == null) return;
const object_id = quick_add.getAttribute('data-object-id');
if (object_id == null) return;
const object_repr = quick_add.getAttribute('data-object-repr');
if (object_repr == null) return;
const target_id = quick_add.getAttribute('data-target-id');
if (target_id == null) return;
const target = document.getElementById(target_id);
if (target == null) return;
//@ts-expect-error tomselect added on init
target.tomselect.addOption({
id: object_id,
display: object_repr,
});
//@ts-expect-error tomselect added on init
target.tomselect.addItem(object_id);
const modal_element = document.getElementById('htmx-modal');
if (modal_element) {
const modal = Modal.getInstance(modal_element);
if (modal) {
modal.hide();
}
}
}
export function initQuickAdd(): void {
const quick_add_modal = document.getElementById('htmx-modal-content');
if (quick_add_modal) {
quick_add_modal.addEventListener('htmx:afterSwap', () => handleQuickAddObject());
}
}