mirror of
https://github.com/jenkinsci/jenkins.git
synced 2024-10-23 08:45:06 +08:00
Use standard dropdowns for combobox (#9462)
Co-authored-by: Zbynek Konecny <zbynek1729@gmail.com>
This commit is contained in:
parent
2c92eae462
commit
d7eda6a7c7
@ -70,11 +70,6 @@ THE SOFTWARE.
|
||||
</st:documentation>
|
||||
<f:prepareDatabinding/>
|
||||
${descriptor.calcFillSettings(field,attrs)} <!-- this figures out the 'fillUrl' and 'fillDependsOn' attribute -->
|
||||
<st:once>
|
||||
<script type="text/javascript" src="${request.contextPath}/scripts/utilities.js"/>
|
||||
<script type="text/javascript" src="${request.contextPath}/scripts/combobox.js"/>
|
||||
</st:once>
|
||||
<st:adjunct includes="lib.form.combobox.combobox"/>
|
||||
|
||||
<!-- mostly pass-through all the attributes -->
|
||||
<j:set var="name" value="${attrs.name ?: '_.'+attrs.field}"/>
|
||||
|
@ -5,7 +5,6 @@ import Tooltips from "@/components/tooltips";
|
||||
import StopButtonLink from "@/components/stop-button-link";
|
||||
import ConfirmationLink from "@/components/confirmation-link";
|
||||
import Dialogs from "@/components/dialogs";
|
||||
import Autocomplete from "@/components/autocomplete";
|
||||
|
||||
Dropdowns.init();
|
||||
Notifications.init();
|
||||
@ -14,4 +13,3 @@ Tooltips.init();
|
||||
StopButtonLink.init();
|
||||
ConfirmationLink.init();
|
||||
Dialogs.init();
|
||||
Autocomplete.init();
|
||||
|
@ -9,32 +9,20 @@ function init() {
|
||||
return prev + item + delimiter + " ";
|
||||
}
|
||||
|
||||
function validate(e) {
|
||||
if (e.targetUrl) {
|
||||
var method = e.getAttribute("checkMethod") || "post";
|
||||
try {
|
||||
FormChecker.delayedCheck(e.targetUrl(), method, e.targetElement);
|
||||
} catch (x) {
|
||||
console.warn(x);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function convertSuggestionToItem(suggestion, e) {
|
||||
const delimiter = e.getAttribute("autoCompleteDelimChar");
|
||||
const confirm = () => {
|
||||
e.value = delimiter
|
||||
? addValue(e.value, suggestion.name, delimiter)
|
||||
: suggestion.name;
|
||||
validate(e);
|
||||
Utils.validateDropdown(e);
|
||||
e.focus();
|
||||
};
|
||||
return {
|
||||
label: suggestion.name,
|
||||
onClick: confirm,
|
||||
onKeyPress: (evt) => {
|
||||
if (evt.key == "Tab") {
|
||||
if (evt.key === "Tab") {
|
||||
confirm();
|
||||
e.dropdown.hide();
|
||||
evt.preventDefault();
|
||||
@ -43,13 +31,9 @@ function init() {
|
||||
};
|
||||
}
|
||||
|
||||
function getMaxSuggestionCount(e) {
|
||||
return parseInt(e.dataset["maxsuggestions"]) || 10;
|
||||
}
|
||||
|
||||
function createAndShowDropdown(e, suggestions) {
|
||||
const items = suggestions
|
||||
.splice(0, getMaxSuggestionCount(e))
|
||||
.splice(0, Utils.getMaxSuggestionCount(e, 10))
|
||||
.map((s) => convertSuggestionToItem(s, e));
|
||||
if (!e.dropdown) {
|
||||
Utils.generateDropdown(
|
||||
@ -82,19 +66,6 @@ function init() {
|
||||
.then((response) => createAndShowDropdown(e, response.suggestions || []));
|
||||
}
|
||||
|
||||
function debounce(callback) {
|
||||
callback.running = false;
|
||||
return () => {
|
||||
if (!callback.running) {
|
||||
callback.running = true;
|
||||
setTimeout(() => {
|
||||
callback();
|
||||
callback.running = false;
|
||||
}, 300);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
behaviorShim.specify(
|
||||
"INPUT.auto-complete",
|
||||
"input-auto-complete",
|
||||
@ -111,7 +82,7 @@ function init() {
|
||||
);
|
||||
e.addEventListener(
|
||||
"input",
|
||||
debounce(() => {
|
||||
Utils.debounce(() => {
|
||||
updateSuggestions(e);
|
||||
}),
|
||||
);
|
93
src/main/js/components/dropdowns/combo-box.js
Normal file
93
src/main/js/components/dropdowns/combo-box.js
Normal file
@ -0,0 +1,93 @@
|
||||
import behaviorShim from "@/util/behavior-shim";
|
||||
import Utils from "@/components/dropdowns/utils";
|
||||
|
||||
function init() {
|
||||
function convertSuggestionToItem(suggestion, e) {
|
||||
const confirm = () => {
|
||||
e.value = suggestion.name;
|
||||
Utils.validateDropdown(e);
|
||||
e.focus();
|
||||
};
|
||||
return {
|
||||
label: suggestion.name,
|
||||
onClick: confirm,
|
||||
onKeyPress: (evt) => {
|
||||
if (evt.key === "Tab") {
|
||||
confirm();
|
||||
e.dropdown.hide();
|
||||
evt.preventDefault();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function createAndShowDropdown(e, div, suggestions) {
|
||||
const items = suggestions
|
||||
.splice(0, Utils.getMaxSuggestionCount(e, 20))
|
||||
.map((s) => convertSuggestionToItem(s, e));
|
||||
if (!e.dropdown) {
|
||||
Utils.generateDropdown(
|
||||
div,
|
||||
(instance) => {
|
||||
e.dropdown = instance;
|
||||
},
|
||||
true,
|
||||
);
|
||||
}
|
||||
e.dropdown.setContent(Utils.generateDropdownItems(items, true));
|
||||
e.dropdown.show();
|
||||
}
|
||||
|
||||
function updateSuggestions(e, div, items) {
|
||||
const text = e.value.trim();
|
||||
|
||||
let filteredItems = text
|
||||
? items.filter((item) => item.indexOf(text) === 0)
|
||||
: items;
|
||||
|
||||
const suggestions = filteredItems
|
||||
.filter((item) => item.indexOf(text) === 0)
|
||||
.map((item) => {
|
||||
return { name: item };
|
||||
});
|
||||
createAndShowDropdown(e, div, suggestions || []);
|
||||
}
|
||||
|
||||
behaviorShim.specify("INPUT.combobox2", "combobox", 100, function (e) {
|
||||
// form field with auto-completion support
|
||||
// insert the auto-completion container
|
||||
refillOnChange(e, function (params) {
|
||||
const div = document.createElement("DIV");
|
||||
e.parentNode.insertBefore(div, e.nextElementSibling);
|
||||
e.style.position = "relative";
|
||||
|
||||
const url = e.getAttribute("fillUrl");
|
||||
fetch(url, {
|
||||
headers: crumb.wrap({
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
}),
|
||||
method: "post",
|
||||
body: new URLSearchParams(params),
|
||||
})
|
||||
.then((rsp) => (rsp.ok ? rsp.json() : {}))
|
||||
.then((items) => {
|
||||
e.addEventListener("focus", () => updateSuggestions(e, div, items));
|
||||
|
||||
// otherwise menu won't hide on tab with nothing selected
|
||||
// needs delay as without that it blocks click selection of an item
|
||||
e.addEventListener("focusout", () =>
|
||||
setTimeout(() => e.dropdown.hide(), 200),
|
||||
);
|
||||
|
||||
e.addEventListener(
|
||||
"input",
|
||||
Utils.debounce(() => {
|
||||
updateSuggestions(e, div, items);
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default { init };
|
@ -2,12 +2,16 @@ import Jumplists from "@/components/dropdowns/jumplists";
|
||||
import InpageJumplist from "@/components/dropdowns/inpage-jumplist";
|
||||
import OverflowButton from "@/components/dropdowns/overflow-button";
|
||||
import HeteroLists from "@/components/dropdowns/hetero-list";
|
||||
import ComboBox from "@/components/dropdowns/combo-box";
|
||||
import Autocomplete from "@/components/dropdowns/autocomplete";
|
||||
|
||||
function init() {
|
||||
Jumplists.init();
|
||||
InpageJumplist.init();
|
||||
OverflowButton.init();
|
||||
HeteroLists.init();
|
||||
ComboBox.init();
|
||||
Autocomplete.init();
|
||||
}
|
||||
|
||||
export default { init };
|
||||
|
@ -206,8 +206,39 @@ function convertHtmlToItems(children) {
|
||||
return items;
|
||||
}
|
||||
|
||||
function validateDropdown(e) {
|
||||
if (e.targetUrl) {
|
||||
const method = e.getAttribute("checkMethod") || "post";
|
||||
try {
|
||||
FormChecker.delayedCheck(e.targetUrl(), method, e.targetElement);
|
||||
} catch (x) {
|
||||
console.warn(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getMaxSuggestionCount(e, defaultValue) {
|
||||
return parseInt(e.dataset["maxsuggestions"]) || defaultValue;
|
||||
}
|
||||
|
||||
function debounce(callback) {
|
||||
callback.running = false;
|
||||
return () => {
|
||||
if (!callback.running) {
|
||||
callback.running = true;
|
||||
setTimeout(() => {
|
||||
callback();
|
||||
callback.running = false;
|
||||
}, 300);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
convertHtmlToItems,
|
||||
generateDropdown,
|
||||
generateDropdownItems,
|
||||
validateDropdown,
|
||||
getMaxSuggestionCount,
|
||||
debounce,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user