diff --git a/core/src/main/resources/lib/form/filter-menu-button/filter-menu-button.js b/core/src/main/resources/lib/form/filter-menu-button/filter-menu-button.js new file mode 100644 index 000000000000..e81ccc43fe7a --- /dev/null +++ b/core/src/main/resources/lib/form/filter-menu-button/filter-menu-button.js @@ -0,0 +1,70 @@ +// prettier-ignore +window.createFilterMenuButton = function ( + button, + menu, + menuAlignment, + menuMinScrollHeight +) { + var MIN_NUM_OPTIONS = 5; + var menuButton = new YAHOO.widget.Button(button, { + type: "menu", + menu: menu, + menualignment: menuAlignment, + menuminscrollheight: menuMinScrollHeight, + }); + + var filter = _createFilterMenuButton(menuButton._menu); + + menuButton._menu.element.appendChild(filter); + menuButton._menu.showEvent.subscribe(function () { + _applyFilterKeyword(menuButton._menu, filter.firstElementChild); + filter.style.display = + _getItemList(menuButton._menu).children.length >= MIN_NUM_OPTIONS + ? "" + : "NONE"; + }); + menuButton._menu.setInitialFocus = function () { + setTimeout(function () { + filter.firstElementChild.focus(); + }, 0); + }; + + return menuButton; +}; + +function _createFilterMenuButton(menu) { + const filterInput = document.createElement("input"); + filterInput.classList.add("jenkins-input"); + filterInput.setAttribute("placeholder", "Filter"); + filterInput.setAttribute("spellcheck", "false"); + filterInput.setAttribute("type", "search"); + + filterInput.addEventListener("input", (event) => + _applyFilterKeyword(menu, event.currentTarget), + ); + filterInput.addEventListener("keypress", (event) => { + if (event.key === "Enter") { + event.preventDefault(); + } + }); + + const filterContainer = document.createElement("div"); + filterContainer.appendChild(filterInput); + + return filterContainer; +} + +function _applyFilterKeyword(menu, filterInput) { + const filterKeyword = (filterInput.value || "").toLowerCase(); + const itemList = _getItemList(menu); + let item, match; + for (item of itemList.children) { + match = item.innerText.toLowerCase().includes(filterKeyword); + item.style.display = match ? "" : "NONE"; + } + menu.align(); +} + +function _getItemList(menu) { + return menu.body.children[0]; +} diff --git a/core/src/main/resources/lib/form/hetero-list.jelly b/core/src/main/resources/lib/form/hetero-list.jelly index b817c936c4e8..66fe2dd91773 100644 --- a/core/src/main/resources/lib/form/hetero-list.jelly +++ b/core/src/main/resources/lib/form/hetero-list.jelly @@ -107,6 +107,8 @@ THE SOFTWARE. + +
@@ -154,8 +156,7 @@ THE SOFTWARE.
- +
diff --git a/core/src/main/resources/lib/form/hetero-list/hetero-list.js b/core/src/main/resources/lib/form/hetero-list/hetero-list.js new file mode 100644 index 000000000000..a51423bf6e0b --- /dev/null +++ b/core/src/main/resources/lib/form/hetero-list/hetero-list.js @@ -0,0 +1,201 @@ +// @include lib.form.filter-menu-button.filter-menu-button + +// do the ones that extract innerHTML so that they can get their original HTML before +// other behavior rules change them (like YUI buttons.) +Behaviour.specify( + "DIV.hetero-list-container", + "hetero-list", + -100, + function (e) { + if (isInsideRemovable(e)) { + return; + } + + // components for the add button + var menu = document.createElement("SELECT"); + // In case nested content also uses hetero-list + var btn = Array.from(e.querySelectorAll("INPUT.hetero-list-add")).pop(); + if (!btn) { + return; + } + YAHOO.util.Dom.insertAfter(menu, btn); + + var prototypes = e.lastElementChild; + while (!prototypes.classList.contains("prototypes")) { + prototypes = prototypes.previousElementSibling; + } + var insertionPoint = prototypes.previousElementSibling; // this is where the new item is inserted. + + // extract templates + var templates = []; + var children = prototypes.children; + for (var i = 0; i < children.length; i++) { + var n = children[i]; + var name = n.getAttribute("name"); + var tooltip = n.getAttribute("tooltip"); + var descriptorId = n.getAttribute("descriptorId"); + // YUI Menu interprets this