You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
293 lines
12 KiB
293 lines
12 KiB
/** |
|
* edit_globals.js is responsible for instantiating any of the javascript that is needed by the individual data types |
|
* that are contained in edit_globals.php page. |
|
* |
|
* @package openemr |
|
* @link http://www.open-emr.org |
|
* @author Stephen Nielson <snielson@discoverandchange.com> |
|
* @copyright Copyright (c) 2022 Discover and Change <snielson@discoverandchange.com> |
|
* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 |
|
*/ |
|
|
|
/** |
|
* The following Immediately Invoked Function (IFF) is for the multiSortedListWidget |
|
* It has two inner classes Widget and WidgetItem |
|
* The Widget represents a list select box and WidgetItem represents the individual list item that is added and sortable |
|
* in the DOM. List items can be moved up, down, and removed. When a new list item is selected with the selection |
|
* picker it is added to the list container. |
|
*/ |
|
(function(window, oeUI) { |
|
|
|
const WIDGET_NAME = "multiSortedListWidget"; |
|
var widgets = []; |
|
|
|
function Widget(widgetContainer) { |
|
var _widget = this; |
|
_widget.picker = null; |
|
_widget.widgetContainer = widgetContainer || null; |
|
widgetContainer = null; // remove the reference |
|
|
|
var widgetItems = []; |
|
|
|
_widget.updateSortOrderInput = function() { |
|
let container = _widget.widgetContainer.querySelector('.gbl-field-multi-sorted-list-container'); |
|
|
|
if (!container) { |
|
console.error("Failed to find DOM Node with class .gbl-field-multi-sorted-list-container for widget " + WIDGET_NAME); |
|
return; |
|
} |
|
|
|
let options = container.querySelectorAll("[data-option-id]"); |
|
let inputText = []; |
|
if (options && options.length) { |
|
options.forEach(function(item) { inputText.push(item.dataset.optionId); }); |
|
} |
|
let sortOrderInput = _widget.widgetContainer.querySelector('.gbl-field-multi-sorted-list-value'); |
|
if (!sortOrderInput) { |
|
console.error("Failed to find DOM Node with class .gbl-field-multi-sorted-list-value for widget " + WIDGET_NAME); |
|
return; |
|
} |
|
sortOrderInput.value = inputText.join(";"); |
|
console.log("sortOrderInput is now '", sortOrderInput.value, ","); |
|
} |
|
|
|
_widget.addSelectedListOption = function(event) { |
|
let target = event.currentTarget; |
|
console.log("Selected option is ", target); |
|
console.log("Value is ", target.value); |
|
|
|
// algorithm is first, check if we already have the element... |
|
// if we do remove it from its current position and append it to the end of the list |
|
let container = _widget.widgetContainer.querySelector('.gbl-field-multi-sorted-list-container'); |
|
if (!container) { |
|
console.error("Failed to find container with class .gbl-field-multi-sorted-list-container in widget " + WIDGET_NAME); |
|
return; |
|
} |
|
|
|
let itemNode = container.querySelector('[data-option-id="' + target.value + '"]'); |
|
if (!itemNode) { |
|
let template = _widget.widgetContainer.querySelector('.gbl-field-multi-sorted-list-item-template'); |
|
if (!template) { |
|
console.error("Failed to find template with class .gbl-field-multi-sorted-list-item-template in widget " + WIDGET_NAME); |
|
return; |
|
} |
|
let fragment = template.content.cloneNode(true); |
|
itemNode = fragment.querySelector('.gbl-field-multi-sorted-list-item'); |
|
if (!itemNode) { |
|
console.error("Failed to find node from template with class .gbl-field-multi-sorted-list-item in widget " + WIDGET_NAME); |
|
return; |
|
} |
|
itemNode.dataset.optionId = target.value; |
|
let textLabel = itemNode.querySelector('.text-label'); |
|
// set up our display text |
|
if (target.options[target.selectedIndex] && textLabel) { |
|
|
|
textLabel.innerText = target.options[target.selectedIndex].innerText; |
|
} else { |
|
console.error("textLabel or selected item was missing in widget " + WIDGET_NAME); |
|
} |
|
} |
|
|
|
// move it to the end of the list |
|
container.appendChild(itemNode); |
|
container.classList.remove('d-none'); |
|
|
|
let emptyList = container.parentNode.querySelector('.gbl-field-multi-sorted-list-empty'); |
|
if (!emptyList) { |
|
console.error("Failed to find DOM Node with class .gbl-field-multi-sorted-list-empty in widget " + WIDGET_NAME); |
|
} else { |
|
emptyList.classList.add('d-none'); |
|
} |
|
|
|
// now reset our selected index |
|
target.selectedIndex = 0; |
|
_widget.reload(); // reload everything and reset up all of our events including the new node. |
|
}; |
|
|
|
_widget.init = function() { |
|
let select = _widget.widgetContainer.querySelector('.gbl-field-multi-sorted-list-picker'); |
|
if (!select) { |
|
console.error("Failed to find select node in DOM to initialize " + WIDGET_NAME); |
|
return; |
|
} |
|
select.addEventListener('change', _widget.addSelectedListOption); |
|
_widget.picker = select; |
|
|
|
// now grab all of our items and init our widgets for them |
|
let container = _widget.widgetContainer.querySelector('.gbl-field-multi-sorted-list-container'); |
|
if (!container) { |
|
console.error("Failed to find container with class .gbl-field-multi-sorted-list-container in widget " + WIDGET_NAME); |
|
return; |
|
} |
|
let emptyList = container.parentNode.querySelector('.gbl-field-multi-sorted-list-empty'); |
|
if (!emptyList) { |
|
console.error("Failed to find DOM Node with class .gbl-field-multi-sorted-list-empty in widget " + WIDGET_NAME); |
|
return; |
|
} |
|
|
|
// whenever we reload it will reset our styles here. |
|
let items = container.querySelectorAll('.gbl-field-multi-sorted-list-item'); |
|
if (items && items.length) { |
|
emptyList.classList.add('d-none'); |
|
container.classList.remove("d-none"); |
|
} else { |
|
container.classList.add("d-none"); |
|
emptyList.classList.remove('d-none'); |
|
} |
|
items.forEach(function(item) { |
|
let widget = new WidgetItem(item, _widget.reload); |
|
widget.init(); |
|
widgetItems.push(widget); |
|
}); |
|
}; |
|
|
|
_widget.reload = function() { |
|
_widget.destroy(); |
|
_widget.init(); |
|
_widget.updateSortOrderInput(); |
|
}; |
|
|
|
_widget.destroy = function () { |
|
if (widgetItems && widgetItems.length) { |
|
widgetItems.forEach(function(w) { w.destroy();}); |
|
widgetItems = []; |
|
} |
|
if (_widget.picker) { |
|
_widget.picker.removeEventListener('change', _widget.addSelectedListOption); |
|
_widget.picker = null; |
|
} |
|
} |
|
} |
|
|
|
function WidgetItem(node, actionCallback) { |
|
var _widgetItem = this; |
|
_widgetItem.node = node; |
|
_widgetItem.btnRemove = null; |
|
_widgetItem.btnMoveUp = null; |
|
_widgetItem.btnMoveDown = null; |
|
|
|
// noop if we don't have a callback |
|
actionCallback = actionCallback || function() {}; |
|
|
|
function moveWidgetUp() { |
|
event.preventDefault(); |
|
if (_widgetItem.node.previousElementSibling) { |
|
// if our next sibling is the last node, it will insert at the end |
|
_widgetItem.node.parentNode.insertBefore(_widgetItem.node, _widgetItem.node.previousElementSibling) |
|
} else { |
|
console.error("moveWidget") |
|
} |
|
actionCallback(); |
|
} |
|
|
|
function moveWidgetDown(event) { |
|
event.preventDefault(); |
|
if (_widgetItem.node.nextElementSibling) { |
|
// if our next sibling is the last node, it will insert at the end |
|
_widgetItem.node.parentNode.insertBefore(_widgetItem.node, _widgetItem.node.nextElementSibling.nextElementSibling) |
|
} else { |
|
console.error("moveWidget") |
|
} |
|
actionCallback(); |
|
} |
|
|
|
function deleteWidget() { |
|
event.preventDefault(); |
|
_widgetItem.node.parentNode.removeChild(_widgetItem.node); |
|
actionCallback(); |
|
} |
|
|
|
_widgetItem.init = function() { |
|
if (!_widgetItem.node) { |
|
throw new Error("DOM node cannot be empty"); |
|
} |
|
// using our node go through and setup all of our event listeners |
|
// setup our remove button |
|
let btnRemove = node.querySelector('.btn-delete'); |
|
if (btnRemove) { |
|
btnRemove.addEventListener('click', deleteWidget); |
|
_widgetItem.btnRemove = btnRemove; |
|
} else { |
|
console.error("Failed to find DOM Node with class .btn-cancel for widget " + WIDGET_NAME); |
|
} |
|
|
|
// setup our move button |
|
|
|
let btnMoveUp = node.querySelector('.btn-uparrow'); |
|
if (btnMoveUp) { |
|
if (node.parentNode.firstElementChild == node) { |
|
btnMoveUp.classList.add("d-none"); |
|
} else { |
|
btnMoveUp.classList.remove("d-none"); |
|
} |
|
btnMoveUp.addEventListener('click', moveWidgetUp); |
|
_widgetItem.btnMoveUp = btnMoveUp; |
|
} else { |
|
console.error("Failed to find DOM Node with class .btn-m-uparrow for widget " + WIDGET_NAME); |
|
} |
|
|
|
let btnMoveDown = node.querySelector('.btn-downarrow'); |
|
if (btnMoveDown) { |
|
if (node.parentNode.lastElementChild == node) { |
|
btnMoveDown.classList.add("d-none"); |
|
} else { |
|
btnMoveDown.classList.remove("d-none"); |
|
} |
|
btnMoveDown.addEventListener('click', moveWidgetDown); |
|
_widgetItem.btnMoveDown = btnMoveDown; |
|
} else { |
|
console.error("Failed to find DOM Node with class .btn-m-uparrow for widget " + WIDGET_NAME); |
|
} |
|
|
|
}; |
|
_widgetItem.destroy = function() { |
|
// if we remove all references to this then we clear it out |
|
_widgetItem.node = null; |
|
if (_widgetItem.btnRemove) { |
|
_widgetItem.btnRemove.removeEventListener('click', deleteWidget); |
|
} |
|
if (_widgetItem.btnMoveUp) { |
|
_widgetItem.btnMoveUp.removeEventListener('click', moveWidgetUp); |
|
} |
|
if (_widgetItem.btnMoveDown) |
|
{ |
|
_widgetItem.btnMoveDown.removeEventListener('click', moveWidgetDown); |
|
} |
|
_widgetItem.btnRemove = null; |
|
_widgetItem.btnMoveDown= null; |
|
_widgetItem.btnMoveUp = null; |
|
}; |
|
} |
|
|
|
function init() { |
|
let widgetNodes = window.document.querySelectorAll('.gbl-field-multi-sorted-list-widget'); |
|
|
|
if (widgetNodes && widgetNodes.length) { |
|
widgetNodes.forEach(function(node) { |
|
let widget = new Widget(node); |
|
widget.init(); |
|
widgets.push(widget); |
|
}); |
|
} |
|
} |
|
function reload() { |
|
destroy(); |
|
init(); |
|
} |
|
function destroy() { |
|
if (widgets && widgets.length) { |
|
widgets.forEach(function(w) { w.destroy();}); |
|
widgets = []; |
|
} |
|
} |
|
let multiSortedListWidget = { |
|
init: init |
|
,reload: reload |
|
,destroy: destroy |
|
}; |
|
oeUI.multiSortedListWidget = multiSortedListWidget; |
|
window.oeUI = oeUI; |
|
})(window, window.oeUI || {}); |
|
|
|
// launch our multi sorted list widget initialization |
|
window.document.addEventListener("DOMContentLoaded", window.oeUI.multiSortedListWidget.init); |