diff --git a/src/controllers/DallEFieldController.php b/src/controllers/DallEFieldController.php index 8acd7f3..38e1d7a 100644 --- a/src/controllers/DallEFieldController.php +++ b/src/controllers/DallEFieldController.php @@ -43,7 +43,7 @@ public function actionGenerateImages() 'message' => "There was an error communicating with the Open AI API.", ])->setStatusCode(500); } - + return $this->asJson([ 'result' => 'error', 'message' => $response->error->message ?? "There was an error communicating with the Open AI API.", @@ -91,7 +91,7 @@ public function actionGenerateVariants() 'message' => "There was an error communicating with the Open AI API.", ])->setStatusCode(500); } - + return $this->asJson([ 'result' => 'error', 'message' => $response->error->message ?? "There was an error communicating with the Open AI API.", @@ -141,7 +141,7 @@ public function actionExtendHorizontally() 'message' => "There was an error communicating with the Open AI API.", ])->setStatusCode(500); } - + return $this->asJson([ 'result' => 'error', 'message' => $response->error->message ?? "There was an error communicating with the Open AI API.", @@ -199,7 +199,7 @@ public function actionRepaint() 'urls' => $urls, ]); - } + } public function actionUseImage() { @@ -235,7 +235,9 @@ public function actionUseImage() 'assetId' => $asset->id, 'title' => $asset->title, 'siteId' => '1', - 'imageUrl' => $asset->getUrl() + 'imageUrl' => $asset->getUrl(), + 'height' => $asset->getHeight(), + 'width' => $asset->getWidth() ]); } @@ -262,7 +264,7 @@ public function actionUseImagePair() /** @var DallE $dalle */ $dalle = Plugin::$plugin->dalle; try{ - $asset = $dalle->saveImagePairAsAsset($leftUrl, $rightUrl, $folder); + $asset = $dalle->saveImagePairAsAsset($leftUrl, $rightUrl, $folder); } catch(\Exception $e) { return $this->asJson([ 'result' => 'error', @@ -275,7 +277,9 @@ public function actionUseImagePair() 'assetId' => $asset->id, 'title' => $asset->title, 'siteId' => '1', - 'imageUrl' => $asset->getUrl() + 'imageUrl' => $asset->getUrl(), + 'height' => $asset->getHeight(), + 'width' => $asset->getWidth() ]); } diff --git a/src/templates/field/input.twig b/src/templates/field/input.twig index c921dc8..2e3f42c 100644 --- a/src/templates/field/input.twig +++ b/src/templates/field/input.twig @@ -44,16 +44,16 @@
- {{ forms.button({ - label: "Generate Image with Dall-E", - class: [ - 'btn', - 'icon', - 'add', - 'dashed', - 'dalle-generate-button', - ] - }) }} + {{ forms.button({ + label: "Generate Image with Dall-E", + class: [ + 'btn', + 'icon', + 'add', + 'dashed', + 'dalle-generate-button', + ] + }) }}
@@ -85,8 +85,8 @@ } %} {% js %} - if(!window.dalle){ - window.dalle = {}; + if(!window.dalle) { + window.dalle = []; } - window.dalle[{{ fieldId }}] = new {{ jsClass }}({{ jsSettings|json_encode|raw }}); -{% endjs %} \ No newline at end of file + window.dalle.push( new {{ jsClass }}({{ jsSettings|json_encode|raw }}) ); +{% endjs %} diff --git a/src/web/assets/dallefieldtype.js b/src/web/assets/dallefieldtype.js index 79f1b53..0d864c2 100644 --- a/src/web/assets/dallefieldtype.js +++ b/src/web/assets/dallefieldtype.js @@ -1,4 +1,19 @@ -(function(){ +(function() { + // add jQuery bindFirst function + if (!($.fn.bindFirst)) { + $.fn.bindFirst = function (events, fn) { + let elem, handlers, i, _len; + this.on(events, fn); + for (i = 0, _len = this.length; i < _len; i++) { + elem = this[i]; + events.split(' ').forEach(function (event) { + handlers = jQuery._data(elem).events[event.split('.')[0]]; + handlers.unshift(handlers.pop()); + }) + } + }; + } + let globalAjaxAborter = new AbortController(); let allImageUrls = []; @@ -48,7 +63,7 @@ `); @@ -59,21 +74,21 @@ let $editModalDetailsLhsImgZoom = $editModalDetailsWrapper.find('.modal-details-lhs-zoom').first(); let $editModalDetailsLhsImgZoomInner = $editModalDetailsLhsImgZoom.find('.modal-details-lhs-zoom-inner').first(); - if($(window).width() >= 520) { - $editModalDetailsLhsImg.hover(function(e){ + if ($(window).width() >= 520) { + $editModalDetailsLhsImg.hover(function (e) { $editModalDetailsLhsImgZoom.show(); - }, function(e){ + }, function (e) { $editModalDetailsLhsImgZoom.hide(); }); - $editModalDetailsLhsImg.mousemove(function(e){ + $editModalDetailsLhsImg.mousemove(function (e) { let target = $(e.currentTarget); let mouseX = e.originalEvent.x; let mouseY = e.originalEvent.y; let offsetX = (mouseX - target.offset().left) / target.width(); let offsetY = (mouseY - target.offset().top) / target.height(); - + let zoomX = (-100) * offsetX; let zoomY = (-100) * offsetY; @@ -83,28 +98,28 @@ }) } - $editModalDetailsWrapper.find('.modal-details-back').click(function(e){ + $editModalDetailsWrapper.find('.modal-details-back').click(function (e) { cancelInflight(); populateResults(); }); - $editModalDetailsWrapper.find('.modal-details-use').click(function(e){ + $editModalDetailsWrapper.find('.modal-details-use').click(function (e) { cancelInflight(); selectImage($editModalDetailsWrapper.attr('data-url')); }); - $editModalDetailsWrapper.find('.modal-details-variants').click(function(e){ + $editModalDetailsWrapper.find('.modal-details-variants').click(function (e) { cancelInflight(); generateVariants($editModalDetailsWrapper.attr('data-url')); }); - $editModalDetailsWrapper.find('.modal-details-extend').click(function(e){ + $editModalDetailsWrapper.find('.modal-details-extend').click(function (e) { cancelInflight(); generateExtensions($editModalDetailsWrapper.attr('data-url')); }); - $editModalDetailsWrapper.find('.modal-details-repaint').click(function(e){ + $editModalDetailsWrapper.find('.modal-details-repaint').click(function (e) { cancelInflight(); gotoRepaint($editModalDetailsWrapper.attr('data-url')); }); @@ -115,51 +130,90 @@ let $editModalPromptInput = $editModalContent.find('.dalle-prompt'); let $editModalPromptButton = $editModalContent.find('.dalle-generate-button'); - $editModalPromptButton.click(function(e){ + $editModalPromptButton.click(function (e) { clearModal(); - setTimeout(function(){ + setTimeout(function () { performNewGeneration($editModalPromptInput.val()); }, 100) - }) + }); let editModal = new Garnish.Modal($editModalWrapper, { - autoShow: false + autoShow: false, + onHide: jumpToSavedPosition }); - let activeGenerator = null; + let savedScrollTopPosition = 0; - let generators = document.getElementsByClassName('dalle-generator'); - for (generator of generators) { - let launchButton = generator.getElementsByClassName('dalle-generate-button')[0]; - if(!launchButton) continue; - - launchButton.addEventListener('click', function(e){ - triggerModal($(this).parents('.dalle-generator')[0]); - }); + function jumpToSavedPosition() { + $(document).scrollTop(savedScrollTopPosition); + } + + $(document).ready(function () { + checkAndSetOptions(); + }); + checkAndSetOptions(); + + $(document).on('click', '.dalle-generate-button', function () { + const generator = this.closest('.dalle-generator'); + if (!generator) return; + + savedScrollTopPosition = $(document).scrollTop(); + triggerModal(generator); + }); + + function getGeneratorId(generator) { + return generator.closest('.elementselect').id; + } + + function getDalleById(id) { + return window.dalle.find(generator => id == generator.settings.id); + } + + function checkAndSetOptions() { + setTimeout(() => { + checkLimits(); + setClickEventOnRemoveImageButton(); + }, 200); + } + + function checkLimits() { + window.dalle.forEach(generator => { + const $container = generator.$container && generator.$container[0]; + const launchButton = $container && $container.querySelector('.dalle-generate-button'); + if (!launchButton) return; - let fieldId = generator.getAttribute('data-fieldid'); - setInterval(function(){ - let limit = window.dalle[fieldId].settings.limit; - if (limit != null && window.dalle[fieldId].$elements.length >= limit) { + if (generator.settings.limit && generator.$elements.length >= generator.settings.limit) { $(launchButton).hide(); } else { $(launchButton).show(); } - }, 200); + }); + } + + function setClickEventOnRemoveImageButton() { + window.dalle.forEach(generator => { + const $container = generator.$container && generator.$container[0]; + const deleteButton = $container && $container.querySelector('button.delete'); + if (!deleteButton) return; + + $(deleteButton).unbind('click', checkAndSetOptions); + $(deleteButton).bindFirst('click', checkAndSetOptions); + }); } - function cancelInflight(){ + function cancelInflight() { globalAjaxAborter.abort(); globalAjaxAborter = new AbortController(); } - function showModal(){ + function showModal() { editModal.show(); } - function hideModal(){ + function hideModal() { cancelInflight(); editModal.hide(); + setTimeout(checkAndSetOptions, 200); } function resetModal() { @@ -250,28 +304,30 @@ headers: { 'Content-Type': 'application/json' }, - redirect: 'follow', - signal: globalAjaxAborter.signal + redirect: 'follow', + signal: globalAjaxAborter.signal }).then(handleFetchErrors) - .then((response) => response.json()).then((data) => { + .then((response) => response.json()).then((data) => { let elementId = data.assetId; let title = data.title; let siteId = data.siteId; let imageUrl = data.imageUrl; - let elementString = `
@@ -291,8 +347,9 @@ id: elementId, $element: element } - ] - window.dalle[fieldId].selectElements(elements) + ]; + const dalle = getDalleById(getGeneratorId(activeGenerator)); + dalle.selectElements(elements); hideModal(); resetModal(); }).catch(error => { @@ -319,29 +376,31 @@ headers: { 'Content-Type': 'application/json' }, - redirect: 'follow', + redirect: 'follow', signal: globalAjaxAborter.signal - + }).then(handleFetchErrors) - .then((response) => response.json()).then((data) => { + .then((response) => response.json()).then((data) => { let elementId = data.assetId; let title = data.title; let siteId = data.siteId; let imageUrl = data.imageUrl; - let elementString = `
@@ -361,8 +420,9 @@ id: elementId, $element: element } - ] - window.dalle[fieldId].selectElements(elements) + ]; + const dalle = getDalleById(getGeneratorId(activeGenerator)); + dalle.selectElements(elements); hideModal(); resetModal(); }).catch(error => { @@ -389,15 +449,15 @@ headers: { 'Content-Type': 'application/json' }, - redirect: 'follow', - signal: globalAjaxAborter.signal + redirect: 'follow', + signal: globalAjaxAborter.signal }).then(handleFetchErrors) - .then((response) => response.json()).then((data) => { + .then((response) => response.json()).then((data) => { allImageUrls = data.urls.concat(allImageUrls); populateResults(); }).catch(error => { displayFetchErrors(error); - setTimeout(function(){ //Gives the XHR request a chance to cleanly close before the abort is fired + setTimeout(function () { //Gives the XHR request a chance to cleanly close before the abort is fired clearModal(true); }, 100); }); @@ -418,24 +478,24 @@
`); - + let fieldId = activeGenerator.getAttribute('data-fieldid'); $editModalResultsWrapper.append($item); - $item.find('.dalle-view-button').click(function(e){ + $item.find('.dalle-view-button').click(function (e) { showDetails($(this).parents('.dalle-preview-item').first().attr('data-url')); }); } } function generateVariants(imageUrl) { - + detailsRHSLoading(); let varyData = { imageUrl, } - + let varyUrl = createActionUrl('craft-dalle/dall-e-field/generate-variants', varyData); fetch(varyUrl, { method: 'GET', @@ -443,15 +503,15 @@ headers: { 'Content-Type': 'application/json' }, - redirect: 'follow', + redirect: 'follow', signal: globalAjaxAborter.signal }).then(handleFetchErrors) - .then((response) => response.json()).then((data) => { + .then((response) => response.json()).then((data) => { allImageUrls = data.urls.concat(allImageUrls); populateVaryResults(data.urls); }).catch(error => { displayFetchErrors(error); - setTimeout(function(){ //Gives the XHR request a chance to cleanly close before the abort is fired + setTimeout(function () { //Gives the XHR request a chance to cleanly close before the abort is fired clearDetailsRHS(); }, 100); }); @@ -471,7 +531,7 @@
`); - $item.find('.dalle-vary-select-button').click(function(e){ + $item.find('.dalle-vary-select-button').click(function (e) { showDetails($(this).data('url')); }) $varyResultsWrapper.append($item); @@ -498,14 +558,14 @@ headers: { 'Content-Type': 'application/json' }, - redirect: 'follow', + redirect: 'follow', signal: globalAjaxAborter.signal }).then(handleFetchErrors) - .then((response) => response.json()).then((data) => { + .then((response) => response.json()).then((data) => { populateExtensions(data.left, data.right); }).catch(error => { displayFetchErrors(error); - setTimeout(function(){ //Gives the XHR request a chance to cleanly close before the abort is fired + setTimeout(function () { //Gives the XHR request a chance to cleanly close before the abort is fired clearDetailsRHS(); }, 100); }); @@ -526,7 +586,7 @@ $selectButton = $(''); $selectButtonWrapper.append($selectButton); - for (let i = 0; i
- +
@@ -598,7 +658,7 @@ $repaintDom.find('img').prop('src', imageUrl); let canvas = $repaintDom.find('canvas')[0]; var ctx = canvas.getContext("2d"); - + let $repaintButton = $repaintDom.find('.dalle-repaint-button'); let $clearButton = $repaintDom.find('.dalle-repaint-clear-button'); @@ -614,17 +674,17 @@ let lastX, lastY = 0; - $repaintCanvas.mousedown(function(e){ + $repaintCanvas.mousedown(function (e) { drawing = true; ctx.beginPath(); }); - $repaintCanvas.mouseup(function(e){ + $repaintCanvas.mouseup(function (e) { drawing = false; lastX = 0, - lastY = 0; + lastY = 0; }); - $repaintCanvas.mousemove(function(e){ + $repaintCanvas.mousemove(function (e) { if (drawing) { let xPos = e.originalEvent.x - $repaintCanvas.offset().left; let yPos = (e.originalEvent.y - $repaintCanvas.offset().top) + $(document).scrollTop(); @@ -642,16 +702,16 @@ ctx.closePath(); } lastX = xPos, - lastY = yPos; + lastY = yPos; } }); - $repaintButton.click(function(e){ + $repaintButton.click(function (e) { let dataUrl = canvas.toDataURL("image/png"); generateRepaint(imageUrl, dataUrl); }); - $clearButton.click(function(e){ + $clearButton.click(function (e) { ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); }) @@ -677,15 +737,15 @@ 'Content-Type': 'application/json' }, body: JSON.stringify(extendData), - redirect: 'follow', + redirect: 'follow', signal: globalAjaxAborter.signal }).then(handleFetchErrors) - .then((response) => response.json()).then((data) => { + .then((response) => response.json()).then((data) => { allImageUrls = data.urls.concat(allImageUrls); populateVaryResults(data.urls); }).catch(error => { displayFetchErrors(error); - setTimeout(function(){ //Gives the XHR request a chance to cleanly close before the abort is fired + setTimeout(function () { //Gives the XHR request a chance to cleanly close before the abort is fired clearDetailsRHS(); }, 100); }); @@ -699,18 +759,18 @@ } function displayFetchErrors(error) { - if (error.name && error.name == 'AbortError') { + if (error.name && error.name == 'AbortError') { Craft.cp.displayError('Request cancelled'); } else if (error.text) { //This is an HTTP reponse error.text().then(text => { - try{ + try { let parsed = JSON.parse(text); //Is it JSON? if (parsed.hasOwnProperty('message')) { //Does it have a message? Craft.cp.displayError(parsed.message); } else { Craft.cp.displayError('An unknown error occurred.'); } - } catch(e) { + } catch (e) { Craft.cp.displayError(text); //Failed parsing JSON, output body } }); @@ -722,7 +782,7 @@ function createActionUrl(path, queryData) { let baseUrl = Craft.actionUrl; let parsedUrl = new URL(baseUrl); - if(parsedUrl.searchParams.get('p') && parsedUrl.searchParams.get('p').length > 0){ + if (parsedUrl.searchParams.get('p') && parsedUrl.searchParams.get('p').length > 0) { let existingPValue = parsedUrl.searchParams.get('p'); let newPValue = existingPValue.replace(/\/+$/, '') + '/' + path; parsedUrl.searchParams.set('p', newPValue) @@ -734,7 +794,8 @@ for (let [key, val] of updatedParams.entries()) { parsedUrl.searchParams.append(key, val); } - + return parsedUrl.toString(); } -})(); \ No newline at end of file + +})();