Copy positive_prompt from imageElement, select search text on context change, backend improvements
-Move around some functions to be shared -Consolidate some text handling -Select search text when switching contexts -Add hover menu to imageElements (buttonToolbar) -Add button to copy 'positive_prompt' value from metadata (use the positive prompt node for compatibility) -Save metadata to imageElement -Move some element definitions around in imageElements so functions that rely on certain elements work correctly
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { api } from "/scripts/api.js";
|
||||
import { $el } from "/scripts/ui.js";
|
||||
import { copyToClipboard, setSearchTermsOnElement } from "../common/utils.js"
|
||||
import { copyToClipboard, setSearchTermsOnElement, createDarkContainer, getDarkColor } from "../common/utils.js"
|
||||
|
||||
import { setSearchTextAndExecute } from "./imageDrawer.js";
|
||||
|
||||
@@ -34,8 +34,6 @@ export async function createExtraNetworkCard(loraNameText, familiars) {
|
||||
let trainedWords = [];
|
||||
let tags = [];
|
||||
|
||||
const darkColor = 'rgba(0,0,0,0.5)';
|
||||
|
||||
// Load the first image as the object cover image.
|
||||
// If one does not exist, fall back to placeholder image.
|
||||
function getHrefForFamiliarImage(index) {
|
||||
@@ -136,18 +134,6 @@ export async function createExtraNetworkCard(loraNameText, familiars) {
|
||||
});
|
||||
backgroundImage.src = getHrefForFamiliarImage(backgroundImage.lastViewedImageIndex);
|
||||
|
||||
function createDarkContainer(identifier, paddingOverride) {
|
||||
return $el("div", {
|
||||
id: identifier,
|
||||
style: {
|
||||
position: 'absolute',
|
||||
backgroundColor: darkColor,
|
||||
display: 'inline-block', // Size to content, '-block' to allow vertical margin and padding
|
||||
padding: paddingOverride ? paddingOverride : '1%',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let imageCounterLabel;
|
||||
|
||||
function updateImageCounterText() {
|
||||
@@ -200,17 +186,20 @@ export async function createExtraNetworkCard(loraNameText, familiars) {
|
||||
|
||||
return buttonElement;
|
||||
}
|
||||
|
||||
let copyLoraText = `<lora:${loraNameText}:1:1>`;
|
||||
|
||||
if (trainedWords.length > 0) {
|
||||
//Copy all
|
||||
let copyAllText = copyLoraText + ", " + trainedWords;
|
||||
buttonsRow.appendChild(
|
||||
createButton(
|
||||
$el("label", {
|
||||
textContent: "📋",
|
||||
}),
|
||||
`Copy lora as a1111-style text + trained words (${"<lora:" + loraNameText + ":1.0:1.0>, " + trainedWords})`,
|
||||
`Copy lora as a1111-style text + trained words (${copyAllText})`,
|
||||
function(e) {
|
||||
copyToClipboard("<lora:" + loraNameText + ":1.0:1.0>, " + trainedWords)
|
||||
copyToClipboard(copyAllText)
|
||||
e.preventDefault();
|
||||
}
|
||||
)
|
||||
@@ -237,9 +226,9 @@ export async function createExtraNetworkCard(loraNameText, familiars) {
|
||||
$el("label", {
|
||||
textContent: "📜",
|
||||
}),
|
||||
`Copy lora as a1111-style text (${"<lora:" + loraNameText + ":1.0:1.0>"})`,
|
||||
`Copy lora as a1111-style text (${copyLoraText})`,
|
||||
function(e) {
|
||||
copyToClipboard("<lora:" + loraNameText + ":1.0:1.0>")
|
||||
copyToClipboard(copyLoraText)
|
||||
e.preventDefault();
|
||||
}
|
||||
)
|
||||
@@ -311,7 +300,7 @@ export async function createExtraNetworkCard(loraNameText, familiars) {
|
||||
top: '85%',
|
||||
left: 0,
|
||||
width: "100%",
|
||||
backgroundColor: darkColor,
|
||||
backgroundColor: getDarkColor(),
|
||||
height: '15%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
|
||||
@@ -3,7 +3,7 @@ import { getPngMetadata } from "/scripts/pnginfo.js";
|
||||
|
||||
import { defaultKeyList, getVal } from "./imageDrawer.js";
|
||||
// getValue only prepends 'JNodes.', getVal also prepends 'ImageDrawer.'.
|
||||
import { getValue, setSearchTermsOnElement, getMaxZIndex, getLastMousePosition } from "../common/utils.js"
|
||||
import { getValue, setSearchTermsOnElement, getMaxZIndex, getLastMousePosition, createDarkContainer, copyToClipboard } from "../common/utils.js"
|
||||
import ExifReader from '../common/ExifReader-main/src/exif-reader.js';
|
||||
import { createModal } from "../common/modal.js";
|
||||
|
||||
@@ -74,6 +74,121 @@ export async function createImageElementFromImgSrc(src) {
|
||||
const href = `/view?filename=${encodeURIComponent(src.filename)}&type=${src.type}&subfolder=${encodeURIComponent(src.subfolder)}&t=${+new Date()}`;
|
||||
const bIsVideoFormat = src.format?.startsWith("video");
|
||||
|
||||
const imageElement =
|
||||
$el("div.imageElement", {
|
||||
style: {
|
||||
// textAlign: 'center',
|
||||
// objectFit: 'var(--div-fit, contain)',
|
||||
// height: 'calc(var(--max-size) * 1vh)',
|
||||
// borderRadius: '4px',
|
||||
// position: "relative",
|
||||
maxWidth: 'fit-content',
|
||||
}
|
||||
});
|
||||
|
||||
function createButtonToolbar() {
|
||||
|
||||
function createButtons() {
|
||||
if (!buttonsRow) { return; }
|
||||
|
||||
function createButton(foregroundElement, tooltipText, onClickFunction) {
|
||||
const buttonElement = $el("button", {
|
||||
title: tooltipText,
|
||||
style: {
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
padding: 0,
|
||||
}
|
||||
}, [
|
||||
foregroundElement
|
||||
]);
|
||||
|
||||
buttonElement.addEventListener('click', onClickFunction);
|
||||
|
||||
return buttonElement;
|
||||
}
|
||||
|
||||
// Options button
|
||||
buttonsRow.appendChild(
|
||||
createButton(
|
||||
$el("label", {
|
||||
textContent: "📋",
|
||||
}),
|
||||
`Copy positive prompt`,
|
||||
function(e) {
|
||||
let positive_prompt = imageElement?.metadata?.positive_prompt;
|
||||
if (positive_prompt.startsWith('"')) { positive_prompt = positive_prompt.slice(1); }
|
||||
if (positive_prompt.endsWith('"')) { positive_prompt = positive_prompt.slice(0, positive_prompt.length - 1); }
|
||||
copyToClipboard(positive_prompt);
|
||||
e.preventDefault();
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const buttonsRow = $el("div", {
|
||||
style: {
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
}
|
||||
});
|
||||
|
||||
const buttonToolbarContainerElement = createDarkContainer();
|
||||
|
||||
buttonToolbarContainerElement.style.top = '2%';
|
||||
buttonToolbarContainerElement.style.left = '2%';
|
||||
buttonToolbarContainerElement.style.visibility = "hidden";
|
||||
buttonToolbarContainerElement.appendChild(buttonsRow);
|
||||
|
||||
createButtons();
|
||||
|
||||
return buttonToolbarContainerElement;
|
||||
}
|
||||
|
||||
const aElement = $el("a", {
|
||||
target: "_blank",
|
||||
href,
|
||||
onclick: async (e) => {
|
||||
|
||||
function createModalContent() {
|
||||
const modalImg = $el(bIsVideoFormat ? "video" : "img", {
|
||||
src: href,
|
||||
// Store the image source as a data attribute for easy access
|
||||
'data-src': href,
|
||||
style: {
|
||||
position: 'relative',
|
||||
width: '99vw',
|
||||
height: '99vh',
|
||||
maxWidth: 'fit-content',
|
||||
maxHeight: 'fit-content',
|
||||
display: "block",
|
||||
margin: "auto",
|
||||
},
|
||||
});
|
||||
|
||||
// Create modal content
|
||||
const modalContent = document.createElement("div");
|
||||
modalContent.style.position = 'absolute';
|
||||
modalContent.style.display = "inline-block";
|
||||
modalContent.style.left = "50%";
|
||||
modalContent.style.top = "50%";
|
||||
modalContent.style.transform = "translate(-50%, -50%)";
|
||||
modalContent.style.maxWidth = "99%";
|
||||
modalContent.style.maxHeight = "99%";
|
||||
modalContent.style.overflow = "hidden";
|
||||
|
||||
modalContent.appendChild(modalImg);
|
||||
|
||||
return modalContent;
|
||||
}
|
||||
e.preventDefault();
|
||||
createModal(createModalContent());
|
||||
}
|
||||
});
|
||||
|
||||
imageElement.appendChild(aElement);
|
||||
|
||||
const img = $el(bIsVideoFormat ? "video" : "img", {
|
||||
src: href,
|
||||
// Store the image source as a data attribute for easy access
|
||||
@@ -229,23 +344,32 @@ export async function createImageElementFromImgSrc(src) {
|
||||
if (widget) {
|
||||
|
||||
imageElement.tooltipWidget = widget;
|
||||
|
||||
function mouseOverEvent() {
|
||||
|
||||
updateAndShowTooltip(imageElement.tooltipWidget, imageElement);
|
||||
buttonToolbar.style.visibility = "visible";
|
||||
}
|
||||
|
||||
function mouseOutEvent() {
|
||||
|
||||
if (!toolTip) { return; }
|
||||
toolTip.style.visibility = "hidden";
|
||||
toolTip.style.opacity = "0";
|
||||
|
||||
buttonToolbar.style.visibility = "hidden";
|
||||
}
|
||||
|
||||
const lastMousePosition = getLastMousePosition();
|
||||
const elementUnderMouse = document.elementFromPoint(lastMousePosition[0], lastMousePosition[1]);
|
||||
if (elementUnderMouse && elementUnderMouse == img) {
|
||||
updateAndShowTooltip(imageElement.tooltipWidget, imageElement);
|
||||
mouseOverEvent();
|
||||
}
|
||||
|
||||
// Show/Hide tooltip
|
||||
imageElement.addEventListener("mouseover", () => {
|
||||
updateAndShowTooltip(imageElement.tooltipWidget, imageElement);
|
||||
});
|
||||
imageElement.addEventListener("mouseover", mouseOverEvent);
|
||||
|
||||
imageElement.addEventListener("mouseout", () => {
|
||||
if (!toolTip) { return; }
|
||||
toolTip.style.visibility = "hidden";
|
||||
toolTip.style.opacity = "0";
|
||||
});
|
||||
imageElement.addEventListener("mouseout", mouseOutEvent);
|
||||
|
||||
imageElement.onpointermove = e => {
|
||||
if (toolTip?.style?.visibility === "visible") {
|
||||
@@ -272,6 +396,8 @@ export async function createImageElementFromImgSrc(src) {
|
||||
const blob = await response.blob();
|
||||
const pnginfo = await getPngMetadata(blob);
|
||||
|
||||
imageElement.metadata = pnginfo;
|
||||
|
||||
const toolTipWidget = makeTooltipWidgetFromMetadata(pnginfo);
|
||||
|
||||
setTooltipFromWidget(toolTipWidget);
|
||||
@@ -304,6 +430,9 @@ export async function createImageElementFromImgSrc(src) {
|
||||
const jsonReadyString = cleanedString.replace("UNICODE", "")
|
||||
|
||||
const asJson = JSON.parse(jsonReadyString);
|
||||
|
||||
imageElement.metadata = asJson;
|
||||
|
||||
const toolTipWidget = makeTooltipWidgetFromMetadata(asJson);
|
||||
|
||||
setTooltipFromWidget(toolTipWidget);
|
||||
@@ -325,55 +454,9 @@ export async function createImageElementFromImgSrc(src) {
|
||||
img.loop = true;
|
||||
}
|
||||
|
||||
const imageElement =
|
||||
$el("div.imageElement", {
|
||||
style: {
|
||||
display: 'inline-block',
|
||||
}
|
||||
}, [
|
||||
$el("a", {
|
||||
target: "_blank",
|
||||
href,
|
||||
onclick: async (e) => {
|
||||
|
||||
function createModalContent() {
|
||||
const modalImg = $el(bIsVideoFormat ? "video" : "img", {
|
||||
src: href,
|
||||
// Store the image source as a data attribute for easy access
|
||||
'data-src': href,
|
||||
style: {
|
||||
position: 'relative',
|
||||
width: '99vw',
|
||||
height: '99vh',
|
||||
maxWidth: 'fit-content',
|
||||
maxHeight: 'fit-content',
|
||||
display: "block",
|
||||
margin: "auto",
|
||||
},
|
||||
});
|
||||
|
||||
// Create modal content
|
||||
const modalContent = document.createElement("div");
|
||||
modalContent.style.position = 'absolute';
|
||||
modalContent.style.display = "inline-block";
|
||||
modalContent.style.left = "50%";
|
||||
modalContent.style.top = "50%";
|
||||
modalContent.style.transform = "translate(-50%, -50%)";
|
||||
modalContent.style.maxWidth = "99%";
|
||||
modalContent.style.maxHeight = "99%";
|
||||
modalContent.style.overflow = "hidden";
|
||||
|
||||
modalContent.appendChild(modalImg);
|
||||
|
||||
return modalContent;
|
||||
}
|
||||
e.preventDefault();
|
||||
createModal(createModalContent());
|
||||
}
|
||||
}, [
|
||||
img,
|
||||
]),
|
||||
]);
|
||||
aElement.appendChild(img);
|
||||
const buttonToolbar = createButtonToolbar(imageElement)
|
||||
imageElement.appendChild(buttonToolbar);
|
||||
|
||||
return imageElement;
|
||||
}
|
||||
@@ -359,8 +359,8 @@ const createContextSelector = () => {
|
||||
// Set up lastSelectedContextOption to accommodate future context switching
|
||||
lastSelectedContextOption = selectedValue;
|
||||
|
||||
// Automatically focus search bar to save user a click
|
||||
focusSearch();
|
||||
// Automatically focus search bar and select text to save user a click
|
||||
focusAndSelectSearchText();
|
||||
});
|
||||
};
|
||||
|
||||
@@ -408,6 +408,10 @@ export function focusSearch() {
|
||||
SearchBar.focus();
|
||||
}
|
||||
|
||||
export function focusAndSelectSearchText() {
|
||||
SearchBar.select(); // Select focuses already
|
||||
}
|
||||
|
||||
// Function to execute seach with an explicit searchTerm
|
||||
export function executeSearch(searchTerm) {
|
||||
|
||||
|
||||
+17
-1
@@ -70,6 +70,22 @@ export function setValue(name, val) {
|
||||
localStorage.setItem("JNodes.Settings." + name, val);
|
||||
};
|
||||
|
||||
export function getDarkColor() {
|
||||
return 'rgba(0,0,0,0.5)';
|
||||
}
|
||||
|
||||
export function createDarkContainer(identifier, paddingOverride) {
|
||||
return $el("div", {
|
||||
id: identifier,
|
||||
style: {
|
||||
position: 'absolute',
|
||||
backgroundColor: getDarkColor(),
|
||||
display: 'inline-block', // Size to content, '-block' to allow vertical margin and padding
|
||||
padding: paddingOverride ? paddingOverride : '1%',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function setSearchTermsOnElement(element, searchTerms) {
|
||||
element.setAttribute('searchTerms', searchTerms);
|
||||
}
|
||||
@@ -81,7 +97,7 @@ export function getMaxZIndex(element) {
|
||||
maxZIndex = Math.max(maxZIndex, parent.style.zIndex);
|
||||
parent = parent.parentElement;
|
||||
}
|
||||
|
||||
|
||||
return maxZIndex;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user