-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[4.0] Added Save2Copy in Media Manager #30313
Conversation
Thank you @vlaucht for your PR |
It should be |
I can change that, but then the save2copy option is not visible. I believe some sort of warning should be presented to the user that he is about to permanently overwrite the file if he clicks on save |
There is no warning with the other components. It should be obvious that it is save and close per the label of the button. |
Ok, I have swapped the order of the buttons |
Hm, just retried on a fresh 4.0 installation, and It worked as expected. |
Tested again. The problem is with Firefox Macintosh: |
@Fedik |
I just checked on that, and for some reason, it does not call the method putFile, like it does on Chrome. Possibly an issue with the |
Possibly an issue on Firefox side, or even some new security feature they have? |
Clicking on save does trigger a PUT request tho. Save&Close and Save2Copy seem to send a GET request for some reason |
The issue is with |
who doing "request" (Joomla.UploadFile) and then change window.location? I wonder how it work at all :) |
So how about sending an |
yeap, the navigation should be after the request completed |
Further tests: Normally, Save & Copy does NOT reload the manager. See how it behaves for an article. We stay in edit form with the new article displayed in the form.
Although we have no message telling that the modified image is saved (would be good to have), we stay in the edit form and it now works fine, waiting for a Save (Apply) or Save & Close. I think this is the correct behavior. What do you think? |
as I see, the code (php part) generate a new file name for a copied file, |
This what Joomla.MediaManager.Edit.Reset(true); does, if I do not mistake. EDIT: should do in fact. What happens is that the page url remains stuck to the original file. |
I also tested
and it creates the copy in Firefox, then returns to media manager directly. |
But navigating back right after the request was sent means it will navigate even if the request was unsuccessfull for some reason, and since there is no notification yet, the user wouldn't even notice something went wrong. I think the navigation part should be done once the request completes. |
I agree. This is why I prefer the first solution, (#30313 (comment)) i.e. display a success message forcing to Save/Save & Close. + an error if fails. |
So does this mean if you click save2copy, you will now be editing the new copy instead of the original file? |
@dgrammatiko I'm pretty sure I have tested it correctly.
|
Well that's probably something on your side (do you have any browser plugins?) because I shared images that this works on all browsers. Also please share your workflow how you're testing this, I've tested it both manually and also trying to edit an image using the first image in the article form. I can't help you if I don't know what you did and what expected to happen... |
# Conflicts: # build/media_source/system/js/fields/joomla-field-media.w-c.es6.js
BTW the whole js code is bloated for no reason, you don't need an event for the title, eg in the edit and image.vue you can check if the view is modal (there's a state variable for that AFAIK, I added it) and set the title directly there no need for all this complex ritual... |
Clone this branch into htdocs folder, run |
I think I was pretty clear many comments ago: you need to open the images modal and then check the debugger😉 |
Well thats what I meant with I thought this is self explainatory, since the image modal is what is being tested here and CMS content is just an option list. |
Ok you're missing most of the code replace the media field with: ((customElements, Joomla) => {
if (!Joomla) {
throw new Error('Joomla API is not properly initiated');
}
Joomla.selectedFile = {};
window.document.addEventListener('onMediaFileSelected', (e) => {
Joomla.selectedFile = e.detail;
});
const execTransform = (resp, editor, fieldClass) => {
if (resp.success === true) {
if (resp.data[0].url) {
if (/local-/.test(resp.data[0].adapter)) {
const { rootFull } = Joomla.getOptions('system.paths');
// eslint-disable-next-line prefer-destructuring
Joomla.selectedFile.url = resp.data[0].url.split(rootFull)[1];
if (resp.data[0].thumb_path) {
Joomla.selectedFile.thumb = resp.data[0].thumb_path;
} else {
Joomla.selectedFile.thumb = false;
}
} else if (resp.data[0].thumb_path) {
Joomla.selectedFile.thumb = resp.data[0].thumb_path;
}
} else {
Joomla.selectedFile.url = false;
}
const isElement = (o) => (
typeof HTMLElement === 'object' ? o instanceof HTMLElement
: o && typeof o === 'object' && o !== null && o.nodeType === 1 && typeof o.nodeName === 'string'
);
if (Joomla.selectedFile.url) {
if (!isElement(editor) && (typeof editor !== 'object')) {
Joomla.editors.instances[editor].replaceSelection(`<img loading="lazy" src="${Joomla.selectedFile.url}" alt=""/>`);
} else if (!isElement(editor) && (typeof editor === 'object' && editor.id)) {
window.parent.Joomla.editors.instances[editor.id].replaceSelection(`<img loading="lazy" src="${Joomla.selectedFile.url}" alt=""/>`);
} else {
editor.value = Joomla.selectedFile.url;
fieldClass.updatePreview();
}
}
}
};
/**
* Create and dispatch onMediaFileSelected Event
*
* @param {object} data The data for the detail
*
* @returns {void}
*/
Joomla.getImage = (data, editor, fieldClass) => new Promise((resolve, reject) => {
if (!data || (typeof data === 'object' && (!data.path || data.path === ''))) {
Joomla.selectedFile = {};
resolve({
resp: {
success: false,
},
});
return;
}
const apiBaseUrl = `${Joomla.getOptions('system.paths').rootFull}administrator/index.php?option=com_media&format=json`;
Joomla.request({
url: `${apiBaseUrl}&task=api.files&url=true&path=${data.path}&${Joomla.getOptions('csrf.token')}=1&format=json`,
method: 'GET',
perform: true,
headers: { 'Content-Type': 'application/json' },
onSuccess: (response) => {
const resp = JSON.parse(response);
resolve(execTransform(resp, editor, fieldClass));
},
onError: (err) => {
reject(err);
},
});
});
class JoomlaFieldMedia extends HTMLElement {
constructor() {
super();
this.onSelected = this.onSelected.bind(this);
this.show = this.show.bind(this);
this.clearValue = this.clearValue.bind(this);
this.modalClose = this.modalClose.bind(this);
this.setValue = this.setValue.bind(this);
this.updatePreview = this.updatePreview.bind(this);
this.onMediaFileEdit = this.onMediaFileEdit.bind(this);
this.setTitle = this.setTitle.bind(this);
}
static get observedAttributes() {
return ['type', 'base-path', 'root-folder', 'url', 'modal-container', 'modal-width', 'modal-height', 'input', 'button-select', 'button-clear', 'button-save-selected', 'preview', 'preview-width', 'preview-height'];
}
get type() { return this.getAttribute('type'); }
set type(value) { this.setAttribute('type', value); }
get basePath() { return this.getAttribute('base-path'); }
set basePath(value) { this.setAttribute('base-path', value); }
get rootFolder() { return this.getAttribute('root-folder'); }
set rootFolder(value) { this.setAttribute('root-folder', value); }
get url() { return this.getAttribute('url'); }
set url(value) { this.setAttribute('url', value); }
get modalContainer() { return this.getAttribute('modal-container'); }
set modalContainer(value) { this.setAttribute('modal-container', value); }
get input() { return this.getAttribute('input'); }
set input(value) { this.setAttribute('input', value); }
get buttonSelect() { return this.getAttribute('button-select'); }
set buttonSelect(value) { this.setAttribute('button-select', value); }
get buttonClear() { return this.getAttribute('button-clear'); }
set buttonClear(value) { this.setAttribute('button-clear', value); }
get buttonSaveSelected() { return this.getAttribute('button-save-selected'); }
set buttonSaveSelected(value) { this.setAttribute('button-save-selected', value); }
get modalWidth() { return this.getAttribute(parseInt('modal-width', 10)); }
set modalWidth(value) { this.setAttribute('modal-width', value); }
get modalHeight() { return this.getAttribute(parseInt('modal-height', 10)); }
set modalHeight(value) { this.setAttribute('modal-height', value); }
get previewWidth() { return this.getAttribute(parseInt('preview-width', 10)); }
set previewWidth(value) { this.setAttribute('preview-width', value); }
get previewHeight() { return this.getAttribute(parseInt('preview-height', 10)); }
set previewHeight(value) { this.setAttribute('preview-height', value); }
get preview() { return this.getAttribute('preview'); }
set preview(value) { this.setAttribute('preview', value); }
get previewContainer() { return this.getAttribute('preview-container'); }
// attributeChangedCallback(attr, oldValue, newValue) {}
connectedCallback() {
this.button = this.querySelector(this.buttonSelect);
this.inputElement = this.querySelector(this.input);
this.buttonClearEl = this.querySelector(this.buttonClear);
this.modalElement = this.querySelector('.joomla-modal');
this.buttonSaveSelectedElement = this.querySelector(this.buttonSaveSelected);
this.previewElement = this.querySelector('.field-media-preview');
if (!this.button || !this.inputElement || !this.buttonClearEl || !this.modalElement
|| !this.buttonSaveSelectedElement) {
throw new Error('Misconfiguaration...');
}
if (Joomla.Bootstrap && Joomla.Bootstrap.initModal && typeof Joomla.Bootstrap.initModal === 'function') {
Joomla.Bootstrap.initModal(this.modalElement);
}
this.button.addEventListener('click', this.show);
if (this.buttonClearEl) {
this.buttonClearEl.addEventListener('click', this.clearValue);
}
this.updatePreview();
}
disconnectedCallback() {
if (this.button) {
this.button.removeEventListener('click', this.show);
}
if (this.buttonClearEl) {
this.buttonClearEl.removeEventListener('click', this.clearValue);
}
}
onSelected(event) {
event.preventDefault();
event.stopPropagation();
this.modalClose();
return false;
}
show() {
this.modalElement.open();
Joomla.selectedFile = {};
window.document.addEventListener('onMediaFileEdit', this.onMediaFileEdit);
this.buttonSaveSelectedElement.addEventListener('click', this.onSelected);
}
modalClose() {
window.document.removeEventListener('onMediaFileEdit', this.onMediaFileEdit);
Joomla.getImage(Joomla.selectedFile, this.inputElement, this)
.then(() => {
Joomla.Modal.getCurrent().close();
Joomla.selectedFile = {};
})
.catch(() => {
Joomla.Modal.getCurrent().close();
Joomla.selectedFile = {};
Joomla.renderMessages({
error: [Joomla.Text._('JLIB_APPLICATION_ERROR_SERVER')],
});
});
}
setValue(value) {
this.inputElement.value = value;
this.updatePreview();
}
clearValue() {
this.setValue('');
}
updatePreview() {
if (['true', 'static'].indexOf(this.preview) === -1 || this.preview === 'false' || !this.previewElement) {
return;
}
// Reset preview
if (this.preview) {
const { value } = this.inputElement;
if (!value) {
this.previewElement.innerHTML = '<span class="field-media-preview-icon"></span>';
} else {
this.previewElement.innerHTML = '';
const imgPreview = new Image();
switch (this.type) {
case 'image':
imgPreview.src = /http/.test(value) ? value : Joomla.getOptions('system.paths').rootFull + value;
imgPreview.setAttribute('alt', '');
break;
default:
// imgPreview.src = dummy image path;
break;
}
this.previewElement.style.width = this.previewWidth;
this.previewElement.appendChild(imgPreview);
}
}
}
onMediaFileEdit(e) {
if (e.detail && e.detail.file && e.detail.file.name) {
this.setTitle(e.detail.file.name);
Joomla.selectedFile = e.detail;
}
}
setTitle(titleString) {
const title = this.querySelector('.modal-title');
if (title) {
title.textContent = `${ Joomla.JText._('PLG_IMAGE_BUTTON_IMAGE') } - ${ titleString } `;
}
}
}
customElements.define('joomla-field-media', JoomlaFieldMedia);
})(customElements, Joomla); and try again setting the debugger inside |
I don't see how this would change anything relevant to the problem, that the listeners are not getting registered. It just moves the methods to the end and removes some lines irrelevant to the issue. (Still tested it tho, but issue is still present) |
We have been at this point before. I know that it works for you, it just doesnt work for me. I tried console.logs already, but as I already mentioned, the listeners are not registered, so this never gets executed. All listeners registered outside the class work like expected. Since I also tried multiple times with fresh joomla installation, there is nothing I can do besides waiting until someone tests this and can either confirm that this is an issue at my end, or that there is something else wrong. |
@vlaucht Sorry I can't help here, am not a js guy ... but I did read you use xdebug. Maybe it's an xdebug issue that the event listeners don't register, or at least an issue which happens only when using xdebug? I remember having read something similar in some other issue in past. |
xdebug is for PHP, for debugging JS you need to use the browser's debugger. The PHP debugger will NEVER break on any JS breakpoint... |
Silly me ;-) |
@richard67 You dont need any JS knowledge. If you follow the steps in Comment and then click on the pencil icon of an image in the modal, it should open the edit view and change the name in the modal title. If not, you can open the browser debug tool, under sources navigate to |
I tested this. I click on the save as copy button, and nothing happens. no errors displayed |
I have tested this item 🔴 unsuccessfully on c889ca5 This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/30313. |
@vlaucht interesting feature, any chance you can solve conflicts? |
This pull request has automatically rebased to 4.2-dev. |
Nice feature needs a new start, somewhere else. |
Pull Request for Issue # .
Summary of Changes
Added a button to the media manager edit page to save changes as a copy, without overwriting the original file.
The new files will be named like the original file with an added version
Testing Instructions
Actual result BEFORE applying this Pull Request
All changes have been applied to the original image in a destructive way. The original image could not be restored.
Expected result AFTER applying this Pull Request
A copy of the original file is saved with changes applied, and the original file is not modified
Documentation Changes Required
Added one new method
generateNewName
in 'administrator/components/com_media/src/Controller/ApiController.php' and documentation is added