mirror of
https://github.com/easydiffusion/easydiffusion.git
synced 2024-11-23 00:33:28 +01:00
Add undo support
This commit is contained in:
parent
8aead029a8
commit
0f3a3da5ed
@ -282,18 +282,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="preview" class="col-free">
|
<div id="preview" class="col-free">
|
||||||
<div id="initial-text">
|
|
||||||
Type a prompt and press the "Make Image" button.<br/><br/>You can set an "Initial Image" if you want to guide the AI.<br/><br/>
|
|
||||||
You can also add modifiers like "Realistic", "Pencil Sketch", "ArtStation" etc by browsing through the "Image Modifiers" section
|
|
||||||
and selecting the desired modifiers.<br/><br/>
|
|
||||||
Click "Image Settings" for additional settings like seed, image size, number of images to generate etc.<br/><br/>Enjoy! :)
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="preview-content">
|
<div id="preview-content">
|
||||||
<div id="preview-tools">
|
<div id="preview-tools" class="displayNone">
|
||||||
<button id="clear-all-previews" class="secondaryButton"><i class="fa-solid fa-trash-can icon"></i> Clear All</button>
|
<button id="clear-all-previews" class="secondaryButton"><i class="fa-solid fa-trash-can icon"></i> Clear All</button>
|
||||||
<button class="tertiaryButton" id="show-download-popup"><i class="fa-solid fa-download"></i> Download images</button>
|
<button class="tertiaryButton" id="show-download-popup"><i class="fa-solid fa-download"></i> Download images</button>
|
||||||
<div class="display-settings">
|
<div class="display-settings">
|
||||||
|
<button id="undo" class="displayNone tertiaryButton">
|
||||||
|
Undo <i class="fa-solid fa-rotate-left icon"></i>
|
||||||
|
<span class="simple-tooltip left">Undo last remove</span>
|
||||||
|
</button>
|
||||||
<span class="auto-scroll"></span> <!-- hack for Rabbit Hole update -->
|
<span class="auto-scroll"></span> <!-- hack for Rabbit Hole update -->
|
||||||
<button id="auto_scroll_btn" class="tertiaryButton">
|
<button id="auto_scroll_btn" class="tertiaryButton">
|
||||||
<i class="fa-solid fa-arrows-up-to-line icon"></i>
|
<i class="fa-solid fa-arrows-up-to-line icon"></i>
|
||||||
@ -318,6 +316,12 @@
|
|||||||
<div class="clearfix" style="clear: both;"></div>
|
<div class="clearfix" style="clear: both;"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="initial-text">
|
||||||
|
Type a prompt and press the "Make Image" button.<br/><br/>You can set an "Initial Image" if you want to guide the AI.<br/><br/>
|
||||||
|
You can also add modifiers like "Realistic", "Pencil Sketch", "ArtStation" etc by browsing through the "Image Modifiers" section
|
||||||
|
and selecting the desired modifiers.<br/><br/>
|
||||||
|
Click "Image Settings" for additional settings like seed, image size, number of images to generate etc.<br/><br/>Enjoy! :)
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -559,7 +559,6 @@ div.img-preview img {
|
|||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
#preview-tools {
|
#preview-tools {
|
||||||
display: none;
|
|
||||||
padding: 4pt;
|
padding: 4pt;
|
||||||
}
|
}
|
||||||
#preview-tools .display-settings .dropdown-content {
|
#preview-tools .display-settings .dropdown-content {
|
||||||
|
@ -83,6 +83,10 @@ const processOrder = document.querySelector('#process_order_toggle')
|
|||||||
|
|
||||||
let imagePreview = document.querySelector("#preview")
|
let imagePreview = document.querySelector("#preview")
|
||||||
let imagePreviewContent = document.querySelector("#preview-content")
|
let imagePreviewContent = document.querySelector("#preview-content")
|
||||||
|
|
||||||
|
let undoButton = document.querySelector("#undo")
|
||||||
|
let undoBuffer = []
|
||||||
|
|
||||||
imagePreview.addEventListener('drop', function(ev) {
|
imagePreview.addEventListener('drop', function(ev) {
|
||||||
const data = ev.dataTransfer?.getData("text/plain");
|
const data = ev.dataTransfer?.getData("text/plain");
|
||||||
if (!data) {
|
if (!data) {
|
||||||
@ -251,6 +255,39 @@ function playSound() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function undoableRemove(element, doubleUndo=false) {
|
||||||
|
let data = { 'element': element, 'parent': element.parentNode, 'prev': element.previousSibling, 'next': element.nextSibling, 'doubleUndo': doubleUndo }
|
||||||
|
undoBuffer.push(data)
|
||||||
|
if (undoBuffer.length > 10) {
|
||||||
|
// Remove item from memory and also remove it from the data structures
|
||||||
|
let item = undoBuffer.shift()
|
||||||
|
htmlTaskMap.delete(item.element)
|
||||||
|
item.element.querySelectorAll('[data-imagecounter]').forEach( (img) => { delete imageRequest[img.dataset['imagecounter']] })
|
||||||
|
}
|
||||||
|
element.remove()
|
||||||
|
if (undoBuffer.length != 0) {
|
||||||
|
undoButton.classList.remove('displayNone')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function undoRemove() {
|
||||||
|
let data = undoBuffer.pop()
|
||||||
|
if (data.next == null) {
|
||||||
|
data.parent.appendChild(data.element)
|
||||||
|
} else {
|
||||||
|
data.parent.insertBefore(data.element, data.next)
|
||||||
|
}
|
||||||
|
if (data.doubleUndo) {
|
||||||
|
undoRemove()
|
||||||
|
}
|
||||||
|
if (undoBuffer.length == 0) {
|
||||||
|
undoButton.classList.add('displayNone')
|
||||||
|
}
|
||||||
|
updateInitialText()
|
||||||
|
}
|
||||||
|
|
||||||
|
undoButton.addEventListener('click', () => { undoRemove() })
|
||||||
|
|
||||||
function showImages(reqBody, res, outputContainer, livePreview) {
|
function showImages(reqBody, res, outputContainer, livePreview) {
|
||||||
let imageItemElements = outputContainer.querySelectorAll('.imgItem')
|
let imageItemElements = outputContainer.querySelectorAll('.imgItem')
|
||||||
if(typeof res != 'object') return
|
if(typeof res != 'object') return
|
||||||
@ -290,21 +327,19 @@ function showImages(reqBody, res, outputContainer, livePreview) {
|
|||||||
const imageRemoveBtn = imageItemElem.querySelector('.imgPreviewItemClearBtn')
|
const imageRemoveBtn = imageItemElem.querySelector('.imgPreviewItemClearBtn')
|
||||||
let parentTaskContainer = imageRemoveBtn.closest('.imageTaskContainer')
|
let parentTaskContainer = imageRemoveBtn.closest('.imageTaskContainer')
|
||||||
imageRemoveBtn.addEventListener('click', (e) => {
|
imageRemoveBtn.addEventListener('click', (e) => {
|
||||||
shiftOrConfirm(e, "Remove the image from the results?", () => {
|
undoableRemove(imageItemElem)
|
||||||
imageItemElem.style.display = 'none'
|
let allHidden = true;
|
||||||
let allHidden = true;
|
let children = parentTaskContainer.querySelectorAll('.imgItem');
|
||||||
let children = parentTaskContainer.querySelectorAll('.imgItem');
|
for(let x = 0; x < children.length; x++) {
|
||||||
for(let x = 0; x < children.length; x++) {
|
let child = children[x];
|
||||||
let child = children[x];
|
if(child.style.display != "none") {
|
||||||
if(child.style.display != "none") {
|
allHidden = false;
|
||||||
allHidden = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(allHidden === true) {
|
}
|
||||||
const req = htmlTaskMap.get(parentTaskContainer)
|
if(allHidden === true) {
|
||||||
if(!req.isProcessing || req.batchesDone == req.batchCount) {parentTaskContainer.parentNode.removeChild(parentTaskContainer)}
|
const req = htmlTaskMap.get(parentTaskContainer)
|
||||||
}
|
if(!req.isProcessing || req.batchesDone == req.batchCount) { undoableRemove(parentTaskContainer, true) }
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const imageElem = imageItemElem.querySelector('img')
|
const imageElem = imageItemElem.querySelector('img')
|
||||||
@ -566,7 +601,7 @@ function makeImage() {
|
|||||||
}))
|
}))
|
||||||
newTaskRequests.forEach(createTask)
|
newTaskRequests.forEach(createTask)
|
||||||
|
|
||||||
initialText.style.display = 'none'
|
updateInitialText()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onIdle() {
|
async function onIdle() {
|
||||||
@ -864,7 +899,7 @@ async function onTaskStart(task) {
|
|||||||
setStatus('request', 'fetching..')
|
setStatus('request', 'fetching..')
|
||||||
renderButtons.style.display = 'flex'
|
renderButtons.style.display = 'flex'
|
||||||
renameMakeImageButton()
|
renameMakeImageButton()
|
||||||
previewTools.style.display = 'block'
|
updateInitialText()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hover effect for the init image in the task list */
|
/* Hover effect for the init image in the task list */
|
||||||
@ -993,13 +1028,16 @@ function createTask(task) {
|
|||||||
task['stopTask'].addEventListener('click', (e) => {
|
task['stopTask'].addEventListener('click', (e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
||||||
let question = (task['isProcessing'] ? "Stop this task?" : "Remove this task?")
|
if (task['isProcessing']) {
|
||||||
shiftOrConfirm(e, question, async function(e) {
|
shiftOrConfirm(e, "Stop this task?", async function(e) {
|
||||||
if (task.batchesDone <= 0 || !task.isProcessing) {
|
if (task.batchesDone <= 0 || !task.isProcessing) {
|
||||||
removeTask(taskEntry)
|
removeTask(taskEntry)
|
||||||
}
|
}
|
||||||
abortTask(task)
|
abortTask(task)
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
removeTask(taskEntry)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
task['useSettings'] = taskEntry.querySelector('.useSettings')
|
task['useSettings'] = taskEntry.querySelector('.useSettings')
|
||||||
@ -1225,15 +1263,23 @@ async function stopAllTasks() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeTask(taskToRemove) {
|
function updateInitialText() {
|
||||||
taskToRemove.remove()
|
|
||||||
|
|
||||||
if (document.querySelector('.imageTaskContainer') === null) {
|
if (document.querySelector('.imageTaskContainer') === null) {
|
||||||
previewTools.style.display = 'none'
|
if (undoBuffer.length == 0) {
|
||||||
initialText.style.display = 'block'
|
previewTools.classList.add('displayNone')
|
||||||
|
}
|
||||||
|
initialText.classList.remove('displayNone')
|
||||||
|
} else {
|
||||||
|
initialText.classList.add('displayNone')
|
||||||
|
previewTools.classList.remove('displayNone')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeTask(taskToRemove) {
|
||||||
|
undoableRemove(taskToRemove)
|
||||||
|
updateInitialText()
|
||||||
|
}
|
||||||
|
|
||||||
clearAllPreviewsBtn.addEventListener('click', (e) => { shiftOrConfirm(e, "Clear all the results and tasks in this window?", async function() {
|
clearAllPreviewsBtn.addEventListener('click', (e) => { shiftOrConfirm(e, "Clear all the results and tasks in this window?", async function() {
|
||||||
await stopAllTasks()
|
await stopAllTasks()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user