mirror of
https://github.com/itflow-org/itflow
synced 2026-08-19 22:15:12 +00:00
Migrate fully away from Jquery Stage 1
This commit is contained in:
@@ -1,14 +0,0 @@
|
|||||||
$('#summaryModal').on('shown.bs.modal', function (e) {
|
|
||||||
// Perform AJAX request to get the summary
|
|
||||||
$.ajax({
|
|
||||||
url: 'post.php?ai_ticket_summary',
|
|
||||||
method: 'POST',
|
|
||||||
data: { ticket_id: <?php echo $ticket_id; ?> },
|
|
||||||
success: function(response) {
|
|
||||||
$('#summaryContent').html(response);
|
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
$('#summaryContent').html('Error generating summary.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,53 +1,67 @@
|
|||||||
$(document).ready(function() {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
// Function to load contacts for a given client
|
// Function to load contacts for a given client
|
||||||
function loadContacts(clientId) {
|
function loadContacts(clientId) {
|
||||||
if (!clientId) return;
|
if (!clientId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var $contactSelect = $('#contact_select');
|
const contactSelect = document.getElementById('contact_select');
|
||||||
$contactSelect.html('<option value="">Loading...</option>');
|
if (!contactSelect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
contactSelect.innerHTML = '<option value="">Loading...</option>';
|
||||||
|
|
||||||
$.ajax({
|
const query = new URLSearchParams({
|
||||||
url: 'ajax.php',
|
get_client_contacts: 1,
|
||||||
type: 'GET',
|
client_id: clientId
|
||||||
dataType: 'json',
|
});
|
||||||
data: {
|
|
||||||
get_client_contacts: 1,
|
fetch('ajax.php?' + query.toString(), {
|
||||||
client_id: clientId
|
method: 'GET',
|
||||||
},
|
headers: { 'Accept': 'application/json' },
|
||||||
success: function(response) {
|
credentials: 'same-origin'
|
||||||
$contactSelect.empty();
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error('HTTP ' + res.status);
|
||||||
|
}
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.then(function (response) {
|
||||||
|
contactSelect.innerHTML = '';
|
||||||
if (response.contacts && response.contacts.length > 0) {
|
if (response.contacts && response.contacts.length > 0) {
|
||||||
$contactSelect.append('<option value="">Select a contact</option>');
|
contactSelect.appendChild(new Option('Select a contact', ''));
|
||||||
$.each(response.contacts, function(i, contact) {
|
response.contacts.forEach(function (contact) {
|
||||||
$contactSelect.append(
|
// new Option() sets text content, so contact names are
|
||||||
$('<option>', {
|
// never parsed as markup
|
||||||
value: contact.contact_id,
|
contactSelect.appendChild(
|
||||||
text: contact.contact_name
|
new Option(contact.contact_name, contact.contact_id)
|
||||||
})
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$contactSelect.append('<option value="">No contacts found</option>');
|
contactSelect.appendChild(new Option('No contacts found', ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh Select2
|
// Let Tom Select re-read the replaced option list
|
||||||
refreshTomSelect($contactSelect[0]);
|
refreshTomSelect(contactSelect);
|
||||||
},
|
})
|
||||||
error: function(xhr, status, error) {
|
.catch(function (error) {
|
||||||
console.error('AJAX Error:', error);
|
console.error('AJAX Error:', error);
|
||||||
$contactSelect.html('<option value="">Failed to load contacts</option>');
|
contactSelect.innerHTML = '<option value="">Failed to load contacts</option>';
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
|
const clientSelect = document.getElementById('client_select');
|
||||||
|
if (!clientSelect) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load contacts for the currently selected client when modal opens
|
// Load contacts for the currently selected client when modal opens
|
||||||
var initialClientId = $('#client_select').val();
|
loadContacts(clientSelect.value);
|
||||||
loadContacts(initialClientId);
|
|
||||||
|
|
||||||
// Load contacts when client changes
|
// Load contacts when client changes
|
||||||
$('#client_select').on('change', function() {
|
clientSelect.addEventListener('change', function () {
|
||||||
var clientId = $(this).val();
|
loadContacts(this.value);
|
||||||
loadContacts(clientId);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -86,11 +86,11 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// jQuery parses a data-tasks attribute holding JSON into an array on its own,
|
// dataset always gives a string; jQuery used to auto-parse JSON here, so
|
||||||
// but hand it a string and it stays a string - so handle both
|
// parse it explicitly and still tolerate an already-parsed value
|
||||||
function readTemplateTasks($option) {
|
function readTemplateTasks(option) {
|
||||||
|
|
||||||
const tasks = $option.data('tasks');
|
const tasks = option.dataset.tasks;
|
||||||
|
|
||||||
if (!tasks) {
|
if (!tasks) {
|
||||||
return [];
|
return [];
|
||||||
@@ -107,42 +107,56 @@
|
|||||||
return tasks;
|
return tasks;
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).off('click.ticketTasks').on('click.ticketTasks', '#ticketTaskAdd', function () {
|
document.addEventListener('click', function (e) {
|
||||||
|
if (!e.target.closest('#ticketTaskAdd')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
addTaskRow('', '');
|
addTaskRow('', '');
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).off('click.ticketTaskRemove').on('click.ticketTaskRemove', '.ticket-task-remove', function () {
|
document.addEventListener('click', function (e) {
|
||||||
$(this).closest('.ticket-task-row').remove();
|
const remove = e.target.closest('.ticket-task-remove');
|
||||||
|
if (!remove) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const row = remove.closest('.ticket-task-row');
|
||||||
|
if (row) {
|
||||||
|
row.remove();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ticket template picker - fills in the subject, details and task rows
|
// Ticket template picker - fills in the subject, details and task rows
|
||||||
$(document).off('change.ticketTemplate').on('change.ticketTemplate', '#ticket_template_select', function () {
|
document.addEventListener('change', function (e) {
|
||||||
|
const select = e.target.closest('#ticket_template_select');
|
||||||
const $option = $(this).find(':selected');
|
if (!select) {
|
||||||
|
|
||||||
// Selecting "- No Template -" only unlinks the template - it must not wipe
|
|
||||||
// whatever the user has already written or added
|
|
||||||
if (!parseInt($option.val(), 10)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const templateSubject = $option.data('subject') || '';
|
const option = select.options[select.selectedIndex];
|
||||||
const templateDetails = $option.data('details') || '';
|
|
||||||
|
|
||||||
$('#subjectInput').val(templateSubject);
|
// Selecting "- No Template -" only unlinks the template - it must not wipe
|
||||||
|
// whatever the user has already written or added
|
||||||
|
if (!parseInt(option.value, 10)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const templateSubject = option.dataset.subject || '';
|
||||||
|
const templateDetails = option.dataset.details || '';
|
||||||
|
|
||||||
|
document.getElementById('subjectInput').value = templateSubject;
|
||||||
|
|
||||||
if (window.tinymce) {
|
if (window.tinymce) {
|
||||||
const editor = tinymce.get('detailsInput');
|
const editor = tinymce.get('detailsInput');
|
||||||
if (editor) {
|
if (editor) {
|
||||||
editor.setContent(templateDetails);
|
editor.setContent(templateDetails);
|
||||||
} else {
|
} else {
|
||||||
$('#detailsInput').val(templateDetails);
|
document.getElementById('detailsInput').value = templateDetails;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$('#detailsInput').val(templateDetails);
|
document.getElementById('detailsInput').value = templateDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
setTaskRows(readTemplateTasks($option));
|
setTaskRows(readTemplateTasks(option));
|
||||||
});
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -21,14 +21,14 @@
|
|||||||
// If the client selector is disabled, we must be on a client-specific page instead. Trigger the lists to update.
|
// If the client selector is disabled, we must be on a client-specific page instead. Trigger the lists to update.
|
||||||
if (clientSelectDropdown.disabled) {
|
if (clientSelectDropdown.disabled) {
|
||||||
|
|
||||||
let client_id = $(clientSelectDropdown).find(':selected').val();
|
let client_id = clientSelectDropdown.value;
|
||||||
|
|
||||||
populateLists(client_id);
|
populateLists(client_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listener for client selection. Populate select lists when a client is selected
|
// Listener for client selection. Populate select lists when a client is selected
|
||||||
$(clientSelectDropdown).on('change', function (e) {
|
clientSelectDropdown.addEventListener('change', function () {
|
||||||
let client_id = $(this).find(':selected').val();
|
let client_id = this.value;
|
||||||
|
|
||||||
// Update the dependent dropdown lists
|
// Update the dependent dropdown lists
|
||||||
populateLists(client_id);
|
populateLists(client_id);
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
dropdown.innerHTML = '';
|
dropdown.innerHTML = '';
|
||||||
|
|
||||||
// A multi-select keeps showing its old selections until select2 is told the value changed
|
// A multi-select keeps showing its old selections until select2 is told the value changed
|
||||||
clearTomSelect(dropdown instanceof Element ? dropdown : $(dropdown)[0]);
|
clearTomSelect(dropdown);
|
||||||
|
|
||||||
if (placeholderLabel !== null) {
|
if (placeholderLabel !== null) {
|
||||||
dropdown[dropdown.length] = new Option(placeholderLabel, placeholderValue);
|
dropdown[dropdown.length] = new Option(placeholderLabel, placeholderValue);
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
// Redraws a select2 component after its options have been replaced
|
// Redraws a select2 component after its options have been replaced
|
||||||
function refreshDropdown(dropdown) {
|
function refreshDropdown(dropdown) {
|
||||||
if (dropdown) {
|
if (dropdown) {
|
||||||
refreshTomSelect(dropdown instanceof Element ? dropdown : $(dropdown)[0]);
|
refreshTomSelect(dropdown);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,39 @@
|
|||||||
$(document).ready(function () {
|
/**
|
||||||
|
* $.post replacement. jQuery serialised nested arrays/objects into PHP-style
|
||||||
|
* bracket params (positions[0][status_id]=...), which is what ajax.php parses,
|
||||||
|
* so that encoding is reproduced here rather than sending JSON.
|
||||||
|
*/
|
||||||
|
function itflowPostForm(url, data) {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
|
||||||
|
(function add(prefix, value) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
value.forEach(function (v, i) {
|
||||||
|
add(prefix + '[' + i + ']', v);
|
||||||
|
});
|
||||||
|
} else if (value !== null && typeof value === 'object') {
|
||||||
|
Object.keys(value).forEach(function (k) {
|
||||||
|
add(prefix ? prefix + '[' + k + ']' : k, value[k]);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
params.append(prefix, value === true ? 'true' : String(value));
|
||||||
|
}
|
||||||
|
})('', data);
|
||||||
|
|
||||||
|
return fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||||
|
credentials: 'same-origin',
|
||||||
|
body: params.toString()
|
||||||
|
}).then(function (res) {
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error('HTTP ' + res.status);
|
||||||
|
}
|
||||||
|
return res.text();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
// Drag: Kanban Columns (Statuses)
|
// Drag: Kanban Columns (Statuses)
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
@@ -8,16 +43,16 @@ $(document).ready(function () {
|
|||||||
draggable: '.kanban-column',
|
draggable: '.kanban-column',
|
||||||
onEnd: function () {
|
onEnd: function () {
|
||||||
const columnPositions = Array.from(document.querySelectorAll('#kanban-board .kanban-column')).map((col, index) => ({
|
const columnPositions = Array.from(document.querySelectorAll('#kanban-board .kanban-column')).map((col, index) => ({
|
||||||
status_id: $(col).data('status-id'),
|
status_id: col.dataset.statusId,
|
||||||
status_kanban: index
|
status_kanban: index
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (CONFIG_TICKET_MOVING_COLUMNS === 1) {
|
if (CONFIG_TICKET_MOVING_COLUMNS === 1) {
|
||||||
$.post('ajax.php', {
|
itflowPostForm('ajax.php', {
|
||||||
update_kanban_status_position: true,
|
update_kanban_status_position: true,
|
||||||
positions: columnPositions
|
positions: columnPositions
|
||||||
}).fail((xhr) => {
|
}).catch((err) => {
|
||||||
console.error('Error updating status order:', xhr.responseText);
|
console.error('Error updating status order:', err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,15 +81,15 @@ $(document).ready(function () {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const columnId = $(target).data('status-id');
|
const columnId = target.dataset.statusId;
|
||||||
|
|
||||||
const positions = Array.from(target.querySelectorAll('.task')).map((card, index) => {
|
const positions = Array.from(target.querySelectorAll('.task')).map((card, index) => {
|
||||||
const ticketId = $(card).data('ticket-id');
|
const ticketId = card.dataset.ticketId;
|
||||||
const oldStatus = ticketId === $(movedEl).data('ticket-id')
|
const oldStatus = ticketId === movedEl.dataset.ticketId
|
||||||
? $(movedEl).data('ticket-status-id')
|
? movedEl.dataset.ticketStatusId
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
$(card).data('ticket-status-id', columnId); // update DOM
|
card.dataset.ticketStatusId = columnId; // update DOM
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ticket_id: ticketId,
|
ticket_id: ticketId,
|
||||||
@@ -64,11 +99,11 @@ $(document).ready(function () {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
$.post('ajax.php', {
|
itflowPostForm('ajax.php', {
|
||||||
update_kanban_ticket: true,
|
update_kanban_ticket: true,
|
||||||
positions: positions
|
positions: positions
|
||||||
}).fail((xhr) => {
|
}).catch((err) => {
|
||||||
console.error('Error updating ticket positions:', xhr.responseText);
|
console.error('Error updating ticket positions:', err);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Refresh placeholders after update
|
// Refresh placeholders after update
|
||||||
@@ -81,7 +116,9 @@ $(document).ready(function () {
|
|||||||
// 📱 Touch Support: Show drag handle on mobile
|
// 📱 Touch Support: Show drag handle on mobile
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
if (isTouchDevice()) {
|
if (isTouchDevice()) {
|
||||||
$('.drag-handle-class').css('display', 'inline');
|
document.querySelectorAll('.drag-handle-class').forEach(function (el) {
|
||||||
|
el.style.display = 'inline';
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
|
|||||||
143
js/ajax_modal.js
143
js/ajax_modal.js
@@ -1,61 +1,90 @@
|
|||||||
// Ajax Modal Load Script
|
// Ajax Modal Load Script
|
||||||
$(document).on('click', '.ajax-modal', function (e) {
|
document.addEventListener('click', function (e) {
|
||||||
e.preventDefault();
|
const trigger = e.target.closest('.ajax-modal');
|
||||||
|
if (!trigger) {
|
||||||
const $trigger = $(this);
|
|
||||||
|
|
||||||
// Prefer data-modal-url, fallback to href
|
|
||||||
let modalUrl = $trigger.data('modal-url') || $trigger.attr('href') || '#';
|
|
||||||
const modalSize = $trigger.data('modal-size') || 'md';
|
|
||||||
const modalId = 'ajaxModal_' + Date.now();
|
|
||||||
|
|
||||||
// If no usable URL, bail
|
|
||||||
if (!modalUrl || modalUrl === '#') {
|
|
||||||
console.warn('ajax-modal: No modal URL found on trigger:', this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show loading spinner while fetching content
|
|
||||||
const loadingSpinner = `
|
|
||||||
<div id="modal-loading-spinner" class="text-center p-5">
|
|
||||||
<i class="fas fa-spinner fa-spin fa-2x text-muted"></i>
|
|
||||||
</div>`;
|
|
||||||
$('.app-main').append(loadingSpinner);
|
|
||||||
|
|
||||||
// Make AJAX request
|
|
||||||
$.ajax({
|
|
||||||
url: modalUrl,
|
|
||||||
method: 'GET',
|
|
||||||
dataType: 'json',
|
|
||||||
success: function (response) {
|
|
||||||
$('#modal-loading-spinner').remove();
|
|
||||||
|
|
||||||
if (response.error) {
|
|
||||||
alert(response.error);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const modalHtml = `
|
|
||||||
<div class="modal fade" id="${modalId}" tabindex="-1">
|
|
||||||
<div class="modal-dialog modal-${modalSize}">
|
|
||||||
<div class="modal-content border-dark">
|
|
||||||
${response.content}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
$('.app-main').append(modalHtml);
|
|
||||||
const $modal = $('#' + modalId);
|
|
||||||
bootstrap.Modal.getOrCreateInstance($modal[0]).show();
|
|
||||||
|
|
||||||
$modal.on('hidden.bs.modal', function () {
|
|
||||||
$(this).remove();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
error: function (xhr, status, error) {
|
|
||||||
$('#modal-loading-spinner').remove();
|
|
||||||
alert('Error loading modal content. Please try again.');
|
|
||||||
console.error('Modal AJAX Error:', status, error);
|
|
||||||
}
|
}
|
||||||
});
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Prefer data-modal-url, fallback to href
|
||||||
|
const modalUrl = trigger.dataset.modalUrl || trigger.getAttribute('href') || '#';
|
||||||
|
const modalSize = trigger.dataset.modalSize || 'md';
|
||||||
|
const modalId = 'ajaxModal_' + Date.now();
|
||||||
|
|
||||||
|
// If no usable URL, bail
|
||||||
|
if (!modalUrl || modalUrl === '#') {
|
||||||
|
console.warn('ajax-modal: No modal URL found on trigger:', trigger);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const host = document.querySelector('.app-main') || document.body;
|
||||||
|
|
||||||
|
// Show loading spinner while fetching content
|
||||||
|
const spinner = document.createElement('div');
|
||||||
|
spinner.id = 'modal-loading-spinner';
|
||||||
|
spinner.className = 'text-center p-5';
|
||||||
|
spinner.innerHTML = '<i class="fas fa-spinner fa-spin fa-2x text-muted"></i>';
|
||||||
|
host.appendChild(spinner);
|
||||||
|
|
||||||
|
function clearSpinner() {
|
||||||
|
const el = document.getElementById('modal-loading-spinner');
|
||||||
|
if (el) {
|
||||||
|
el.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(modalUrl, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: { 'Accept': 'application/json' },
|
||||||
|
credentials: 'same-origin'
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error('HTTP ' + res.status);
|
||||||
|
}
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.then(function (response) {
|
||||||
|
clearSpinner();
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
alert(response.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrapper = document.createElement('div');
|
||||||
|
wrapper.className = 'modal fade';
|
||||||
|
wrapper.id = modalId;
|
||||||
|
wrapper.tabIndex = -1;
|
||||||
|
wrapper.innerHTML =
|
||||||
|
'<div class="modal-dialog modal-' + modalSize + '">' +
|
||||||
|
'<div class="modal-content border-dark">' +
|
||||||
|
response.content +
|
||||||
|
'</div>' +
|
||||||
|
'</div>';
|
||||||
|
host.appendChild(wrapper);
|
||||||
|
|
||||||
|
// innerHTML does not execute <script> tags. The modal payload ends
|
||||||
|
// with modal_footer.php, which re-runs app.js to wire up Tom Select,
|
||||||
|
// IMask, flatpickr and friends - so re-inject them by hand.
|
||||||
|
wrapper.querySelectorAll('script').forEach(function (old) {
|
||||||
|
const s = document.createElement('script');
|
||||||
|
for (const attr of old.attributes) {
|
||||||
|
s.setAttribute(attr.name, attr.value);
|
||||||
|
}
|
||||||
|
s.textContent = old.textContent;
|
||||||
|
old.replaceWith(s);
|
||||||
|
});
|
||||||
|
|
||||||
|
bootstrap.Modal.getOrCreateInstance(wrapper).show();
|
||||||
|
|
||||||
|
wrapper.addEventListener('hidden.bs.modal', function () {
|
||||||
|
wrapper.remove();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
clearSpinner();
|
||||||
|
alert('Error loading modal content. Please try again.');
|
||||||
|
console.error('Modal AJAX Error:', error);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,18 +1,25 @@
|
|||||||
// Delegated on document rather than bound to the links present at page load, so
|
// Delegated on document rather than bound to the links present at page load, so
|
||||||
// that confirm-link also works on markup injected by an ajax modal
|
// that confirm-link also works on markup injected by an ajax modal
|
||||||
$(document).ready(function() {
|
document.addEventListener('click', function (e) {
|
||||||
$(document).off('click.itflowConfirm').on('click.itflowConfirm', 'a.confirm-link', function(e) {
|
const link = e.target.closest('a.confirm-link');
|
||||||
e.preventDefault();
|
if (!link) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
// Save the link reference to use after confirmation
|
const modalEl = document.getElementById('confirmationModal');
|
||||||
var linkReference = this;
|
const confirmBtn = document.getElementById('confirmSubmitBtn');
|
||||||
|
if (!modalEl || !confirmBtn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Show the confirmation modal
|
// Replacing the node drops any handler left over from a previous link,
|
||||||
bootstrap.Modal.getOrCreateInstance(document.getElementById('confirmationModal')).show();
|
// which is what .off('click') used to do here.
|
||||||
|
const freshBtn = confirmBtn.cloneNode(true);
|
||||||
|
confirmBtn.replaceWith(freshBtn);
|
||||||
|
freshBtn.addEventListener('click', function () {
|
||||||
|
window.location.href = link.getAttribute('href');
|
||||||
|
});
|
||||||
|
|
||||||
// When the submission is confirmed via the modal
|
bootstrap.Modal.getOrCreateInstance(modalEl).show();
|
||||||
$("#confirmSubmitBtn").off('click').on('click', function() {
|
});
|
||||||
window.location.href = $(linkReference).attr('href');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
$(document).ready(function(){
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
// Add class to tables
|
// Add class to tables
|
||||||
$('div.prettyContent table').addClass('table');
|
document.querySelectorAll('div.prettyContent table').forEach(function (el) {
|
||||||
|
el.classList.add('table');
|
||||||
|
});
|
||||||
|
|
||||||
// Add img-fluid class to img tags
|
// Add img-fluid class to img tags
|
||||||
$('div.prettyContent img').addClass('img-fluid');
|
document.querySelectorAll('div.prettyContent img').forEach(function (el) {
|
||||||
});
|
el.classList.add('img-fluid');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
$(document).ready(function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
$('.modal').each(function () {
|
document.querySelectorAll('.modal').forEach(function (modal) {
|
||||||
const modalId = `#${$(this).attr('id')}`;
|
if (modal.id && window.location.href.indexOf('#' + modal.id) !== -1) {
|
||||||
if (window.location.href.indexOf(modalId) !== -1) {
|
bootstrap.Modal.getOrCreateInstance(modal).show();
|
||||||
bootstrap.Modal.getOrCreateInstance($(modalId)[0]).show();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user