export default class DataPicker {
constructor(pickers) {
this.modal = this._createModalContainer();
this.modal.appendTo($("body"));
this.current = null;
pickers.each((_index, picker) => {
this.activate(picker);
});
}
activate(picker) {
let $picker = $(picker);
this._setCurrentPicker($picker, null);
let input = "hidden",
name = this.current.name,
values = this.current.values;
if (this.current.multiple) {
name += "[]";
}
$("div", values).each((_index2, div) => {
let value = $("a", div).data("picker-value");
$(div).prepend($(``));
});
$picker.on("click", "a", (event) => {
event.preventDefault();
if ($picker.hasClass("disabled")) {
return;
}
const isMultiPicker = $picker.hasClass("picker-multiple");
if ($(this._targetFromEvent(event)).hasClass("picker-prompt") || !isMultiPicker) {
this._openPicker($picker, this._targetFromEvent(event));
} else if (this._targetFromEvent(event).tagName === "A") {
this._removeValue($picker, this._targetFromEvent(event).parentNode);
} else {
this._removeValue($picker, this._targetFromEvent(event));
}
});
$picker.on("click", "input", (event) => {
this._removeValue($picker, this._targetFromEvent(event));
});
if (this.current.autosort) {
this._sort();
}
}
enabled(picker, value) {
$(picker).toggleClass("disabled", !value);
$("input", picker).attr("disabled", !value);
}
clear(picker) {
$(".picker-values", picker).html("");
}
save(picker) {
return $(".picker-values div:has(input:checked)", picker).map((_index, div) => {
let $link = $("a", div);
return {
value: $("input", div).val(),
text: $link.text(),
url: $link.attr("href")
};
}).get();
}
load(picker, savedData) {
this._setCurrentPicker($(picker), null);
$.each(savedData, (_index, data) => {
this._choose(data, { interactive: false, modify: false });
});
if (this.current.autosort) {
this._sort();
}
}
_createModalContainer() {
// Add a header because we are referencing the title element with
// `aria-labelledby`. If the title doesn't exist, the "labelled by"
// reference is incorrect.
const headerHtml = '
';
return $(``);
}
_openPicker($picker, target) {
this._setCurrentPicker($picker, target);
this._load($("a", target).attr("href"));
}
_setCurrentPicker($picker, target) {
let $target = false;
if (target && !$(target).hasClass("picker-prompt")) {
$target = $(target);
}
this.current = {
picker: $picker,
name: $picker.data("picker-name"),
values: $picker.find(".picker-values"),
multiple: $picker.hasClass("picker-multiple"),
autosort: $picker.hasClass("picker-multiple") && $picker.hasClass("picker-autosort"),
target: $target
};
}
_load(url) {
$.ajax(url).done((resp) => {
let modalContent = $(".data_picker-modal-content", this.modal);
modalContent.html(resp);
this._handleLinks(modalContent);
this._handleCheckboxes(modalContent);
this.modal.foundation("open");
});
}
_handleLinks(content) {
$("a", content).each((_index, link) => {
let $link = $(link);
$link.click((event) => {
event.preventDefault();
if ($link.data("close") || $link.data("close") === "") {
return;
}
let chooseUrl = $link.attr("href");
if (chooseUrl) {
if (typeof $link.data("picker-choose") === "undefined") {
this._load(chooseUrl);
} else {
this._choose(
{ url: chooseUrl, value: $link.data("picker-value") || "", text: $link.data("picker-text") || "" }
);
}
}
});
});
}
_handleCheckboxes(content) {
$("input[type=checkbox][data-picker-choose]", content).each((_index, checkbox) => {
const $checkbox = $(checkbox);
checkbox.checked = this._targetFromValue($checkbox.val()) !== null;
}).change((event) => {
const $checkbox = $(event.target);
if (event.target.checked) {
this._choose(
{ url: $checkbox.data("picker-url"), value: $checkbox.val() || "", text: $checkbox.data("picker-text") || "" },
{ modify: false, close: false }
);
}
else {
this._removeValue(this.current.picker, this._targetFromValue($checkbox.val()));
}
});
}
_choose(data, opts = {}) {
const options = Object.assign({ interactive: true, modify: true, close: true }, opts);
let dataText = this._escape(data.text);
let choosenOption = null;
if (!this.current.target && options.modify) {
this.current.target = this._targetFromValue(data.value);
}
// Add or update value appearance
if (this.current.target && options.modify) {
let link = $("a", this.current.target);
link.data("picker-value", data.value);
link.attr("href", data.url);
choosenOption = this.current.target;
if (this.current.multiple) {
link.html(`× ${dataText}`);
} else {
link.text(dataText);
}
} else {
let input = "hidden",
name = this.current.name;
if (this.current.multiple) {
name += "[]";
choosenOption = $(``);
} else {
choosenOption = $(``);
}
choosenOption.appendTo(this.current.values);
if (!this.current.target) {
this.current.target = choosenOption;
}
}
// Set input value
let $input = $("input", choosenOption);
$input.attr("value", data.value);
if (this.current.autosort) {
this._sort();
}
if (options.interactive) {
// Raise changed event
$input.trigger("change");
this._removeErrors();
if (options.close) {
this._close();
}
}
}
_sort() {
const values = $(".picker-values", this.current.picker);
values.children().sort((item1, item2) => $("input", item1).val() - $("input", item2).val()).detach().appendTo(values);
}
_close() {
// Close modal and unset target element
this.modal.foundation("close");
this.current.target = null;
}
_removeValue($picker, target) {
if (target) {
this._setCurrentPicker($picker, target);
// Fadeout (with time) doesn't work in system tests
let fadeoutTime = 500;
if (navigator && navigator.webdriver) {
fadeoutTime = 0;
}
this.current.target.fadeOut(fadeoutTime, () => {
this.current.target.remove();
this.current.target = null;
});
}
}
_removeErrors() {
let parent = this.current.picker.parent();
$(".is-invalid-input", parent).removeClass("is-invalid-input");
$(".is-invalid-label", parent).removeClass("is-invalid-label");
$(".form-error.is-visible", parent).removeClass("is-visible");
}
_escape(str) {
return str.replace(/[\u00A0-\u9999<>&]/gim, function (char) {
return `${char.charCodeAt(0)};`;
});
}
_targetFromEvent(event) {
return event.target.parentNode;
}
_targetFromValue(value) {
return $(`[data-picker-value=${value}]`, this.current.picker).parent()[0] || null;
}
}