Merge aea2b5fa2513a141c4636998f9a6dba5f77cf35b into 4290ea753912378913b1f3f54e0fc5720afeda5d
This commit is contained in:
commit
d23b365044
@ -27,6 +27,7 @@ class HTMLOperation {
|
||||
this.manager = manager;
|
||||
|
||||
this.name = name;
|
||||
this.originalName = name;
|
||||
this.description = config.description;
|
||||
this.infoURL = config.infoURL;
|
||||
this.manualBake = config.manualBake || false;
|
||||
@ -56,7 +57,8 @@ class HTMLOperation {
|
||||
|
||||
if (this.description) {
|
||||
const infoLink = this.infoURL ? `<hr>${titleFromWikiLink(this.infoURL)}` : "";
|
||||
const content = Utils.escapeHtml(this.description + infoLink);
|
||||
const categoryInfo = this.getCategoryInfo();
|
||||
const content = Utils.escapeHtml(this.description + infoLink + categoryInfo);
|
||||
|
||||
html += ` data-container='body' data-toggle='popover' data-placement='right'
|
||||
data-content="${content}" data-html='true' data-trigger='hover'
|
||||
@ -75,6 +77,40 @@ class HTMLOperation {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the category information for this operation as an HTML string.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
getCategoryInfo() {
|
||||
if (!this.app.options.showOpCategories) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Use originalName because this.name may have been modified by highlightSearchStrings
|
||||
const categories = [];
|
||||
for (let i = 0; i < this.app.categories.length; i++) {
|
||||
const cat = this.app.categories[i];
|
||||
if (cat.name !== "Favourites" && cat.ops.includes(this.originalName)) {
|
||||
categories.push(cat.name);
|
||||
}
|
||||
}
|
||||
|
||||
if (categories.length === 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Build the category links. Note that Bootstrap's popover sanitizer strips
|
||||
// custom data-* attributes, so the category name is carried in the link text
|
||||
// and resolved to a category ID by OperationsWaiter.categoryLinkClick.
|
||||
const categoryLinks = categories.map(catName =>
|
||||
`<a href='#' class='op-category-link'>${Utils.escapeHtml(catName)}</a>`
|
||||
).join(", ");
|
||||
|
||||
return `<hr>Category: ${categoryLinks}`;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders the operation in HTML as a full operation with ingredients.
|
||||
*
|
||||
|
||||
@ -232,6 +232,8 @@ class Manager {
|
||||
this.addDynamicListener(".option-item input[type=checkbox]#wordWrap", "change", this.options.setWordWrap, this.options);
|
||||
this.addDynamicListener(".option-item input[type=checkbox]#useMetaKey", "change", this.bindings.updateKeybList, this.bindings);
|
||||
this.addDynamicListener(".option-item input[type=checkbox]#showCatCount", "change", this.ops.setCatCount, this.ops);
|
||||
this.addDynamicListener(".option-item input[type=checkbox]#showOpCategories", "change", this.ops.toggleOpCategories, this.ops);
|
||||
this.addDynamicListener(".op-category-link", "click", this.ops.categoryLinkClick, this.ops);
|
||||
this.addDynamicListener(".option-item input[type=number]", "keyup", this.options.numberChange, this.options);
|
||||
this.addDynamicListener(".option-item input[type=number]", "change", this.options.numberChange, this.options);
|
||||
this.addDynamicListener(".option-item select", "change", this.options.selectChange, this.options);
|
||||
|
||||
@ -529,6 +529,13 @@
|
||||
Show the number of operations in each category
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="checkbox option-item">
|
||||
<label for="showOpCategories">
|
||||
<input type="checkbox" option="showOpCategories" id="showOpCategories" checked>
|
||||
Show operation category in popover
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" id="reset-options">Reset options to default</button>
|
||||
|
||||
@ -53,6 +53,7 @@ function main() {
|
||||
imagePreview: true,
|
||||
syncTabs: true,
|
||||
showCatCount: false,
|
||||
showOpCategories: true,
|
||||
};
|
||||
|
||||
document.removeEventListener("DOMContentLoaded", main, false);
|
||||
|
||||
@ -326,6 +326,85 @@ class OperationsWaiter {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for toggling the display of operation categories in popovers.
|
||||
* Repopulates the operations list to show/hide category information.
|
||||
*/
|
||||
toggleOpCategories() {
|
||||
// Repopulate operations list to apply the option change
|
||||
this.app.populateOperationsList();
|
||||
this.manager.recipe.initialiseOperationDragNDrop();
|
||||
|
||||
// Refresh search results if search is active
|
||||
const searchInput = document.getElementById("search");
|
||||
if (searchInput && searchInput.value) {
|
||||
this.searchOperations({target: searchInput});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for clicking a category link in an operation popover.
|
||||
* Clears the search and opens the clicked category.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
categoryLinkClick(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
// Bootstrap's popover sanitizer strips custom data-* attributes, so the
|
||||
// category ID is derived from the link text using the same scheme as
|
||||
// HTMLCategory.toHtml()
|
||||
const catName = e.target.textContent;
|
||||
if (!catName) return;
|
||||
const categoryId = "cat" + catName.replace(/[\s/\-:_]/g, "");
|
||||
|
||||
// Hide all popovers
|
||||
$("[data-toggle=popover]").popover("hide");
|
||||
|
||||
// Clear search
|
||||
const searchInput = document.getElementById("search");
|
||||
if (searchInput) {
|
||||
searchInput.value = "";
|
||||
}
|
||||
|
||||
// Clear search results
|
||||
const searchResults = document.getElementById("search-results");
|
||||
if (searchResults) {
|
||||
while (searchResults.firstChild) {
|
||||
try {
|
||||
$(searchResults.firstChild).popover("dispose");
|
||||
} catch (err) {}
|
||||
searchResults.removeChild(searchResults.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
// Open the target category. The accordion behaviour (data-parent) closes
|
||||
// any other open category automatically. Calling "show" on an already
|
||||
// open category would toggle-close it mid-transition, so skip it.
|
||||
const categoryElement = document.getElementById(categoryId);
|
||||
if (!categoryElement) return;
|
||||
|
||||
const showCategory = function() {
|
||||
if (!categoryElement.classList.contains("show")) {
|
||||
$(categoryElement).collapse("show");
|
||||
}
|
||||
categoryElement.scrollIntoView({behavior: "smooth", block: "nearest"});
|
||||
};
|
||||
|
||||
// Bootstrap ignores "show" while another panel in the accordion is still
|
||||
// mid-transition (e.g. a category collapsed by the search box a moment
|
||||
// earlier), so wait for any in-progress transition to finish first.
|
||||
const transitioning = document.querySelector("#categories .collapsing");
|
||||
if (transitioning) {
|
||||
$(transitioning).one("hidden.bs.collapse shown.bs.collapse", showCategory);
|
||||
} else {
|
||||
showCategory();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default OperationsWaiter;
|
||||
|
||||
@ -252,6 +252,80 @@ module.exports = {
|
||||
.waitForElementVisible("//ul[@id='search-results']//b[text()='MD5']", 1000);
|
||||
},
|
||||
|
||||
"Operation category in popover": browser => {
|
||||
const op = "//ul[@id='search-results']//li[contains(@class, 'operation') and contains(., 'MD5')]";
|
||||
|
||||
// Search for an operation
|
||||
browser
|
||||
.useCss()
|
||||
.clearValue("#search")
|
||||
.setValue("#search", "md5")
|
||||
.useXpath()
|
||||
.waitForElementVisible(op, 1000);
|
||||
|
||||
// Hover over the operation to show popover
|
||||
browser
|
||||
.moveToElement(op, 10, 10)
|
||||
.useCss()
|
||||
.waitForElementVisible(".popover-body", 1000);
|
||||
|
||||
// Assert that Category line appears in popover
|
||||
browser
|
||||
.expect.element(".popover-body").text.to.contain("Category:");
|
||||
|
||||
// Click the category link
|
||||
browser
|
||||
.click(".popover-body .op-category-link");
|
||||
|
||||
// Assert that search is cleared
|
||||
browser
|
||||
.useCss()
|
||||
.expect.element("#search").value.to.equal("");
|
||||
|
||||
// Assert that the Hashing category is now visible
|
||||
browser
|
||||
.expect.element("#catHashing").to.be.visible;
|
||||
|
||||
// Toggle the option off. The checkbox input is restyled by Bootstrap
|
||||
// Material Design and is not directly interactable, so click its label.
|
||||
browser
|
||||
.click("#options");
|
||||
|
||||
browser
|
||||
.waitForElementVisible("#options-modal", 1000)
|
||||
.click("label[for='showOpCategories']")
|
||||
.pause(500)
|
||||
.click("#options-modal .modal-footer .btn-secondary[data-dismiss='modal']")
|
||||
.waitForElementNotVisible("#options-modal", 1000);
|
||||
|
||||
// Search again and verify category line doesn't appear
|
||||
browser
|
||||
.clearValue("#search")
|
||||
.setValue("#search", "md5")
|
||||
.useXpath()
|
||||
.waitForElementVisible(op, 1000)
|
||||
.moveToElement(op, 10, 10)
|
||||
.useCss()
|
||||
.waitForElementVisible(".popover-body", 1000);
|
||||
|
||||
// Assert that Category line does not appear
|
||||
browser
|
||||
.expect.element(".popover-body").text.to.not.contain("Category:");
|
||||
|
||||
// Reset option back to enabled
|
||||
browser
|
||||
.click("#options")
|
||||
.waitForElementVisible("#options-modal", 1000)
|
||||
.click("label[for='showOpCategories']")
|
||||
.pause(500)
|
||||
.click("#options-modal .modal-footer .btn-secondary[data-dismiss='modal']")
|
||||
.waitForElementNotVisible("#options-modal", 1000);
|
||||
|
||||
// Clear search
|
||||
browser
|
||||
.clearValue("#search");
|
||||
},
|
||||
|
||||
"Alert bar": browser => {
|
||||
// Bake nothing to create an empty output which can be copied
|
||||
utils.clear(browser);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user