Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove jQuery from 'New item' page #10208

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
276 changes: 155 additions & 121 deletions src/main/js/add-item.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
import $ from "jquery";
import { createElementFromHtml } from "@/util/dom";

var getItems = function () {
var d = $.Deferred();
$.get("itemCategories?depth=3&iconStyle=icon-xlg").done(function (data) {
d.resolve(data);
});
return d.promise();
const getItems = function () {
return fetch("itemCategories?depth=3&iconStyle=icon-xlg").then((response) =>
response.json(),
);
};

var jRoot = $("head").attr("data-rooturl");
const jRoot = document.querySelector("head").getAttribute("data-rooturl");

$.when(getItems()).done(function (data) {
$(function () {
document.addEventListener("DOMContentLoaded", () => {
getItems().then((data) => {
//////////////////////////
// helper functions...

function parseResponseFromCheckJobName(data) {
var html = $.parseHTML(data);
var element = html[0];
if (element !== undefined) {
return $(element).text();
var parser = new DOMParser();
var html = parser.parseFromString(data, "text/html");
var element = html.body.firstChild;
if (element) {
return element.textContent;
}
return undefined;
}
Expand All @@ -38,50 +37,49 @@ $.when(getItems()).done(function (data) {
}

function getCopyFromValue() {
return $('input[type="text"][name="from"]', "#createItem").val();
return document.querySelector(
'#createItem input[type="text"][name="from"]',
).value;
}

function isItemNameEmpty() {
var itemName = $('input[name="name"]', "#createItem").val();
return itemName === "" ? true : false;
var itemName = document.querySelector(
'#createItem input[name="name"]',
).value;
return itemName.trim() === "";
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now prevents names that are just spaces from being submitted.


function getFieldValidationStatus(fieldId) {
return $("#" + fieldId).data("valid");
return document.querySelector("#" + fieldId).dataset.valid === "true";
}

function setFieldValidationStatus(fieldId, status) {
$("#" + fieldId).data("valid", status);
document.querySelector("#" + fieldId).dataset.valid = status;
}

function activateValidationMessage(messageId, context, message) {
if (message !== undefined && message !== "") {
$(messageId, context).text("» " + message);
document.querySelector(context + " " + messageId).textContent =
"» " + message;
}
cleanValidationMessages(context);
$(messageId).removeClass("input-message-disabled");
enableSubmit(false);
document
.querySelector(messageId)
.classList.remove("input-message-disabled");
refreshSubmitButtonState();
}

function cleanValidationMessages(context) {
$(context)
.find(".input-validation-message")
.addClass("input-message-disabled");
document
.querySelectorAll(context + " .input-validation-message")
.forEach((element) => element.classList.add("input-message-disabled"));
}

function enableSubmit(status) {
var btn = $(".bottom-sticker-inner button[type=submit]");
if (status === true) {
if (btn.hasClass("disabled")) {
btn.removeClass("disabled");
btn.prop("disabled", false);
}
} else {
if (!btn.hasClass("disabled")) {
btn.addClass("disabled");
btn.prop("disabled", true);
}
}
function refreshSubmitButtonState() {
const submitButton = document.querySelector(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than accept a true/false parameter lets just have the function handle whether the button should be valid or not.

".bottom-sticker-inner button[type=submit]",
);
submitButton.disabled = !getFormValidationStatus();
}

function getFormValidationStatus() {
Expand All @@ -95,36 +93,44 @@ $.when(getItems()).done(function (data) {
}

function cleanItemSelection() {
$(".categories").find('li[role="radio"]').attr("aria-checked", "false");
$("#createItem")
.find('input[type="radio"][name="mode"]')
.removeAttr("checked");
$(".categories").find(".active").removeClass("active");
document
.querySelector('.categories li[role="radio"]')
.setAttribute("aria-checked", "false");
document
.querySelector('#createItem input[type="radio"][name="mode"]')
.removeAttribute("checked");
document.querySelectorAll(".categories .active").forEach((item) => {
item.classList.remove("active");
});
setFieldValidationStatus("items", false);
}

function cleanCopyFromOption() {
$("#createItem")
.find('input[type="radio"][value="copy"]')
.removeAttr("checked");
$('input[type="text"][name="from"]', "#createItem").val("");
document
.querySelector('#createItem input[type="radio"][value="copy"]')
.removeAttribute("checked");
document.querySelector(
'#createItem input[type="text"][name="from"]',
).value = "";
setFieldValidationStatus("from", false);
}

//////////////////////////////////
// Draw functions

function drawCategory(category) {
var $category = $("<div/>")
.addClass("category")
.attr("id", "j-add-item-type-" + cleanClassName(category.id));
var $items = $("<ul/>").addClass("j-item-options");
var $catHeader = $('<div class="header" />');
var $category = createElementFromHtml("<div class='category' />");
$category.setAttribute(
"id",
"j-add-item-type-" + cleanClassName(category.id),
);
var $items = createElementFromHtml(`<ul class="j-item-options" />`);
var $catHeader = createElementFromHtml(`<div class="header" />`);
var title = "<h2>" + category.name + "</h2>";
var description = "<p>" + category.description + "</p>";

// Add items
$.each(category.items, function (i, elem) {
category.items.forEach((elem) => {
$items.append(drawItem(elem));
});

Expand Down Expand Up @@ -169,17 +175,13 @@ $.when(getItems()).done(function (data) {
cleanCopyFromOption();
cleanItemSelection();

$(this).attr("aria-checked", "true");
$(this).find('input[type="radio"][name="mode"]').prop("checked", true);
$(this).addClass("active");
item.setAttribute("aria-checked", "true");
radio.checked = true;
item.classList.add("active");

setFieldValidationStatus("items", true);
if (!getFieldValidationStatus("name")) {
$('input[name="name"][type="text"]', "#createItem").focus();
} else {
if (getFormValidationStatus()) {
enableSubmit(true);
}
if (getFieldValidationStatus("name")) {
refreshSubmitButtonState();
}
}

Expand Down Expand Up @@ -253,98 +255,130 @@ $.when(getItems()).done(function (data) {
}

// The main panel content is hidden by default via an inline style. We're ready to remove that now.
$("#add-item-panel").removeAttr("style");
document.querySelector("#add-item-panel").removeAttribute("style");

// Render all categories
var $categories = $("div.categories");
$.each(data.categories, function (i, elem) {
drawCategory(elem).appendTo($categories);
var $categories = document.querySelector("div.categories");
data.categories.forEach((elem) => {
$categories.append(drawCategory(elem));
});

// Focus
$("#add-item-panel").find("#name").focus();
document.querySelector("#add-item-panel #name").focus();

// Init NameField
$('input[name="name"]', "#createItem").on("blur input", function () {
function nameFieldEvent() {
if (!isItemNameEmpty()) {
var itemName = $('input[name="name"]', "#createItem").val();
$.get("checkJobName", { value: itemName }).done(function (data) {
var message = parseResponseFromCheckJobName(data);
if (message !== "") {
activateValidationMessage(
"#itemname-invalid",
".add-item-name",
message,
);
} else {
cleanValidationMessages(".add-item-name");
setFieldValidationStatus("name", true);
if (getFormValidationStatus()) {
enableSubmit(true);
}
}
});
var itemName = document.querySelector(
'#createItem input[name="name"]',
).value;

fetch(`checkJobName?value=${encodeURIComponent(itemName)}`).then(
(response) => {
response.text().then((data) => {
var message = parseResponseFromCheckJobName(data);
if (message !== "") {
activateValidationMessage(
"#itemname-invalid",
".add-item-name",
message,
);
} else {
cleanValidationMessages(".add-item-name");
setFieldValidationStatus("name", true);
refreshSubmitButtonState();
}
});
},
);
} else {
enableSubmit(false);
setFieldValidationStatus("name", false);
cleanValidationMessages(".add-item-name");
activateValidationMessage("#itemname-required", ".add-item-name");
refreshSubmitButtonState();
}
});
}

document
.querySelector('#createItem input[name="name"]')
.addEventListener("blur", nameFieldEvent);
document
.querySelector('#createItem input[name="name"]')
.addEventListener("input", nameFieldEvent);

// Init CopyFromField
$('input[name="from"]', "#createItem").on("blur input", function () {
function copyFromFieldEvent() {
if (getCopyFromValue() === "") {
$("#createItem")
.find('input[type="radio"][value="copy"]')
.removeAttr("checked");
document
.querySelector('#createItem input[type="radio"][value="copy"]')
.removeAttribute("checked");
} else {
cleanItemSelection();
$("#createItem")
.find('input[type="radio"][value="copy"]')
.prop("checked", true);
document
.querySelector('#createItem input[type="radio"][value="copy"]')
.setAttribute("checked", true);
setFieldValidationStatus("from", true);
if (!getFieldValidationStatus("name")) {
activateValidationMessage("#itemname-required", ".add-item-name");
setTimeout(function () {
var parentName = $('input[name="from"]', "#createItem").val();
$.get("job/" + parentName + "/api/json?tree=name").done(
function (data) {
if (data.name === parentName) {
//if "name" is invalid, but "from" is a valid job, then switch focus to "name"
$('input[name="name"][type="text"]', "#createItem").focus();
}
var parentName = document.querySelector(
'#createItem input[name="from"]',
).value;

fetch("job/" + parentName + "/api/json?tree=name").then(
(response) => {
response.json().then((data) => {
if (data.name === parentName) {
//if "name" is invalid, but "from" is a valid job, then switch focus to "name"
document
.querySelector(
'#createItem input[name="name"][type="text"]',
)
.focus();
}
});
},
);
}, 400);
} else {
if (getFormValidationStatus()) {
enableSubmit(true);
}
refreshSubmitButtonState();
}
}
});
}

document
.querySelector('#createItem input[name="from"]')
.addEventListener("blur", copyFromFieldEvent);
document
.querySelector('#createItem input[name="from"]')
.addEventListener("input", copyFromFieldEvent);

// Client-side validation
$("#createItem").submit(function (event) {
if (!getFormValidationStatus()) {
event.preventDefault();
if (!getFieldValidationStatus("name")) {
activateValidationMessage("#itemname-required", ".add-item-name");
$('input[name="name"][type="text"]', "#createItem").focus();
} else {
if (
!getFieldValidationStatus("items") &&
!getFieldValidationStatus("from")
) {
activateValidationMessage("#itemtype-required", ".add-item-name");
$('input[name="name"][type="text"]', "#createItem").focus();
document
.querySelector("#createItem")
.addEventListener("submit", function (event) {
if (!getFormValidationStatus()) {
event.preventDefault();
if (!getFieldValidationStatus("name")) {
activateValidationMessage("#" + "", ".add-item-name");
document
.querySelector('#createItem input[name="name"][type="text"]')
.focus();
} else {
if (
!getFieldValidationStatus("items") &&
!getFieldValidationStatus("from")
) {
activateValidationMessage("#itemtype-required", ".add-item-name");
document
.querySelector('#createItem input[name="name"][type="text"]')
.focus();
}
}
}
}
});
});

// Disable the submit button
enableSubmit(false);
refreshSubmitButtonState();
});
});
Loading