diff --git a/administrator/components/com_media/config.xml b/administrator/components/com_media/config.xml index d571a7107e54f..1ab44666e12ce 100644 --- a/administrator/components/com_media/config.xml +++ b/administrator/components/com_media/config.xml @@ -109,6 +109,17 @@ default="text/html" showon="restrict_uploads:1" /> + +
+ diff --git a/administrator/components/com_media/src/View/File/HtmlView.php b/administrator/components/com_media/src/View/File/HtmlView.php index e231868e02bae..ffcc91c610b18 100644 --- a/administrator/components/com_media/src/View/File/HtmlView.php +++ b/administrator/components/com_media/src/View/File/HtmlView.php @@ -71,7 +71,8 @@ protected function addToolbar() ToolbarHelper::apply('apply'); ToolbarHelper::save('save'); ToolbarHelper::custom('reset', 'refresh', '', 'COM_MEDIA_RESET', false); - + ToolbarHelper::custom('undo', 'undo', '', 'COM_MEDIA_UNDO', false); + ToolbarHelper::custom('redo', 'redo', '', 'COM_MEDIA_REDO', false); ToolbarHelper::cancel('cancel'); } } diff --git a/administrator/components/com_media/tmpl/file/default.php b/administrator/components/com_media/tmpl/file/default.php index b49e9929e953b..b15a38e485623 100644 --- a/administrator/components/com_media/tmpl/file/default.php +++ b/administrator/components/com_media/tmpl/file/default.php @@ -47,6 +47,7 @@ 'allowedUploadExtensions' => $params->get('upload_extensions', ''), 'maxUploadSizeMb' => $params->get('upload_maxsize', 10), 'contents' => $this->file->content, + 'historyLength' => $params->get('history_length', 25), ]; $this->document->addScriptOptions('com_media', $config); diff --git a/administrator/components/com_media/tmpl/media/default.php b/administrator/components/com_media/tmpl/media/default.php index d45d8ff25419f..18f1bfd096174 100644 --- a/administrator/components/com_media/tmpl/media/default.php +++ b/administrator/components/com_media/tmpl/media/default.php @@ -46,6 +46,7 @@ 'editViewUrl' => Route::_('index.php?option=com_media&view=file' . ($tmpl ? '&tmpl=' . $tmpl : ''), false, Route::TLS_IGNORE, true), 'allowedUploadExtensions' => $params->get('upload_extensions', ''), 'maxUploadSizeMb' => $params->get('upload_maxsize', 10), + 'historyLength' => $params->get('history_length', 25), 'providers' => (array) $this->providers, 'currentPath' => $this->currentPath, 'isModal' => $tmpl === 'component', diff --git a/administrator/language/en-GB/com_media.ini b/administrator/language/en-GB/com_media.ini index f75b26d181c55..caf963de98565 100644 --- a/administrator/language/en-GB/com_media.ini +++ b/administrator/language/en-GB/com_media.ini @@ -56,6 +56,8 @@ COM_MEDIA_FOLDER="Folder" COM_MEDIA_FOLDER_NAME="Folder Name" COM_MEDIA_FOLDERS="Media Folders" COM_MEDIA_FOLDERS_PATH_LABEL="Warning! Path Folder
Changing the 'Path to files folder' from the default of 'images' may break your links.
The 'Path to images' folder has to be the same or a subfolder of 'Path to files'." +COM_MEDIA_HISTORY_LENGTH_DESC="Set the number of states stored in the history to a value between 1 and 100." +COM_MEDIA_HISTORY_LENGTH_LABEL="History States" COM_MEDIA_INCREASE_GRID="Increase grid size" COM_MEDIA_MEDIA_DATE_CREATED="Date Created" COM_MEDIA_MEDIA_DATE_MODIFIED="Date Modified" @@ -68,6 +70,7 @@ COM_MEDIA_MEDIA_TYPE="Type" COM_MEDIA_NAME="Name" COM_MEDIA_OPEN_ITEM_ACTIONS="Open item actions" COM_MEDIA_PLEASE_SELECT_ITEM="Please select item." +COM_MEDIA_REDO="Redo" COM_MEDIA_RENAME="Rename" COM_MEDIA_RENAME_ERROR="Error renaming item." COM_MEDIA_RENAME_SUCCESS="Item renamed." @@ -83,4 +86,5 @@ COM_MEDIA_TOGGLE_INFO="Toggle item info" COM_MEDIA_TOGGLE_LIST_VIEW="Toggle between grid and table views" COM_MEDIA_TOGGLE_SELECT_ITEM="Toggle select item" COM_MEDIA_TOOLBAR_LABEL="Media Manager" +COM_MEDIA_UNDO="Undo" COM_MEDIA_UPLOAD_SUCCESS="Item uploaded." diff --git a/build/media_source/com_media/js/edit-images.es6.js b/build/media_source/com_media/js/edit-images.es6.js index 46f268773db9f..98cbf1908a0c1 100644 --- a/build/media_source/com_media/js/edit-images.es6.js +++ b/build/media_source/com_media/js/edit-images.es6.js @@ -25,6 +25,40 @@ Joomla.MediaManager = Joomla.MediaManager || {}; Joomla.MediaManager.Edit.history = {}; Joomla.MediaManager.Edit.current = {}; + const addHistoryPoint = (data) => { + if (Joomla.MediaManager.Edit.original !== Joomla.MediaManager.Edit.current.contents) { + const key = Joomla.MediaManager.Edit.history.lastKey; + if (Joomla.MediaManager.Edit.history[key] && Joomla.MediaManager.Edit.history[key - 1] + && Joomla.MediaManager.Edit.history[key].file + === Joomla.MediaManager.Edit.history[key - 1].file) { + return; + } + Joomla.MediaManager.Edit.history[key + 1] = {}; + Joomla.MediaManager.Edit.history[key + 1].data = {}; + if (data === 'reset') { + Joomla.MediaManager.Edit.history[key + 1].file = Joomla.MediaManager.Edit.original.contents; + } else { + Joomla.MediaManager.Edit.history[key + 1].file = Joomla.MediaManager.Edit.current.contents; + if (Joomla.MediaManager.Edit.history[key] && Joomla.MediaManager.Edit.history[key].data) { + Object.assign(Joomla.MediaManager.Edit.history[key + 1].data, + Joomla.MediaManager.Edit.history[key].data); + } else { + Object.assign(Joomla.MediaManager.Edit.history[key + 1].data, data.detail); + } + // eslint-disable-next-line max-len + Joomla.MediaManager.Edit.history[key + 1].data[data.detail.plugin] = data.detail[data.detail.plugin]; + } + + // eslint-disable-next-line max-len + Joomla.MediaManager.Edit.history.lastKey = Number(Joomla.MediaManager.Edit.history.lastKey) + 1; + Joomla.MediaManager.Edit.history.current = Number(Joomla.MediaManager.Edit.history.lastKey); + if (Joomla.MediaManager.Edit.history.lastKey > options.historyLength) { + // eslint-disable-next-line max-len + delete Joomla.MediaManager.Edit.history[Joomla.MediaManager.Edit.history.lastKey - options.historyLength]; + } + } + }; + const activate = (name, data) => { if (!data.contents) { return; @@ -53,14 +87,18 @@ Joomla.MediaManager = Joomla.MediaManager || {}; // Activate the first plugin Joomla.MediaManager.Edit[name.toLowerCase()].Activate(data); + + // Set first history point + if (Object.keys(Joomla.MediaManager.Edit.history).length === 0) { + Joomla.MediaManager.Edit.history.current = 0; + Joomla.MediaManager.Edit.history.lastKey = 0; + addHistoryPoint('reset'); + } }; // Reset the image to the initial state Joomla.MediaManager.Edit.Reset = (current) => { - if (!current || (current && current === 'initial')) { - Joomla.MediaManager.Edit.current.contents = Joomla.MediaManager.Edit.original.contents; - } - + Joomla.MediaManager.Edit.current.contents = Joomla.MediaManager.Edit.history[current].file; // Clear the DOM const container = document.getElementById('media-manager-edit-container'); container.innerHTML = ''; @@ -81,10 +119,7 @@ Joomla.MediaManager = Joomla.MediaManager || {}; Joomla.MediaManager.Edit[link.id.replace('tab-attrib-', '').toLowerCase()].Deactivate(); - let data = Joomla.MediaManager.Edit.current; - if (!current || (current && current !== true)) { - data = Joomla.MediaManager.Edit.original; - } + const data = Joomla.MediaManager.Edit.current; link.click(); @@ -98,21 +133,28 @@ Joomla.MediaManager = Joomla.MediaManager || {}; }; // Create history entry - window.addEventListener('mediaManager.history.point', () => { - if (Joomla.MediaManager.Edit.original !== Joomla.MediaManager.Edit.current.contents) { - const key = Object.keys(Joomla.MediaManager.Edit.history).length; - if (Joomla.MediaManager.Edit.history[key] && Joomla.MediaManager.Edit.history[key - 1] - && Joomla.MediaManager.Edit.history[key] === Joomla.MediaManager.Edit.history[key - 1]) { - return; - } - Joomla.MediaManager.Edit.history[key + 1] = Joomla.MediaManager.Edit.current.contents; - } + window.addEventListener('mediaManager.history.point', (data) => { + addHistoryPoint(data); }); - // @TODO History - Joomla.MediaManager.Edit.Undo = () => { }; - // @TODO History - Joomla.MediaManager.Edit.Redo = () => { }; + Joomla.MediaManager.Edit.Undo = () => { + if (Joomla.MediaManager.Edit.history.current && Joomla.MediaManager.Edit.history.current - 1 + > Joomla.MediaManager.Edit.history.lastKey + - Object.keys(Joomla.MediaManager.Edit.history).length + 2) { + // eslint-disable-next-line max-len + Joomla.MediaManager.Edit.history.current = Number(Joomla.MediaManager.Edit.history.current) - 1; + Joomla.MediaManager.Edit.Reset(Joomla.MediaManager.Edit.history.current); + } + }; + + Joomla.MediaManager.Edit.Redo = () => { + if (Joomla.MediaManager.Edit.history.current && Joomla.MediaManager.Edit.history.current + 1 + < Joomla.MediaManager.Edit.history.lastKey) { + // eslint-disable-next-line max-len + Joomla.MediaManager.Edit.history.current = Number(Joomla.MediaManager.Edit.history.current) + 1; + Joomla.MediaManager.Edit.Reset(Joomla.MediaManager.Edit.history.current); + } + }; // @TODO Create the progress bar Joomla.MediaManager.Edit.createProgressBar = () => { }; @@ -154,7 +196,7 @@ Joomla.MediaManager = Joomla.MediaManager || {}; switch (task) { case 'apply': Joomla.UploadFile.exec(name, JSON.stringify(forUpload), uploadPath, url, type); - Joomla.MediaManager.Edit.Reset(true); + Joomla.MediaManager.Edit.Reset(Joomla.MediaManager.Edit.history.current); break; case 'save': Joomla.UploadFile.exec(name, JSON.stringify(forUpload), uploadPath, url, type); @@ -168,13 +210,14 @@ Joomla.MediaManager = Joomla.MediaManager || {}; } break; case 'reset': - Joomla.MediaManager.Edit.Reset('initial'); + addHistoryPoint('reset'); + Joomla.MediaManager.Edit.Reset(Object.keys(Joomla.MediaManager.Edit.history).length - 1); break; case 'undo': - // @TODO magic goes here + Joomla.MediaManager.Edit.Undo(); break; case 'redo': - // @TODO other magic goes here + Joomla.MediaManager.Edit.Redo(); break; default: break; diff --git a/build/media_source/plg_media-action_crop/js/crop.es6.js b/build/media_source/plg_media-action_crop/js/crop.es6.js index 31304dfb0a516..8727ee68ad71a 100644 --- a/build/media_source/plg_media-action_crop/js/crop.es6.js +++ b/build/media_source/plg_media-action_crop/js/crop.es6.js @@ -15,7 +15,10 @@ Joomla.MediaManager.Edit = Joomla.MediaManager.Edit || {}; const initCrop = () => { const image = document.getElementById('image-preview'); - + const history = Joomla.MediaManager.Edit.history[Joomla.MediaManager.Edit.history.current]; + if (history && history.file) { + image.src = history.file; + } // Initiate the cropper Joomla.MediaManager.Edit.crop.cropper = new Cropper(image, { viewMode: 1, @@ -41,9 +44,10 @@ Joomla.MediaManager.Edit = Joomla.MediaManager.Edit || {}; // Update the store Joomla.MediaManager.Edit.current.contents = this.cropper.getCroppedCanvas().toDataURL(`image/${format}`, quality); - - // Notify the app that a change has been made - window.dispatchEvent(new Event('mediaManager.history.point')); + }, + cropend() { + const cropBoxData = Joomla.MediaManager.Edit.crop.cropper.getCropBoxData(); + window.dispatchEvent(new CustomEvent('mediaManager.history.point', { detail: { crop: cropBoxData, plugin: 'crop' } })); }, }); diff --git a/build/media_source/plg_media-action_resize/js/resize.es6.js b/build/media_source/plg_media-action_resize/js/resize.es6.js index a262204844ca7..91e6941c68c4e 100644 --- a/build/media_source/plg_media-action_resize/js/resize.es6.js +++ b/build/media_source/plg_media-action_resize/js/resize.es6.js @@ -41,14 +41,45 @@ Joomla.MediaManager.Edit = Joomla.MediaManager.Edit || {}; // Update the height input box document.getElementById('jform_resize_height').value = parseInt(height, 10); + }; - // Notify the app that a change has been made - window.dispatchEvent(new Event('mediaManager.history.point')); + const setHistory = ({ target }) => { + const image = document.getElementById('image-source'); + const quality = document.getElementById('jform_resize_quality').value; + const w = parseInt(target.value, 10); + const h = parseInt(target.value, 10) / (image.width / image.height); + resize(w, h); + + const resizeData = { + width: w, + height: h, + quality: parseInt(quality, 10), + }; + window.dispatchEvent(new CustomEvent('mediaManager.history.point', { detail: { resize: resizeData, plugin: 'resize' } })); + }; + + const removeListeners = () => { + const resizeWidth = document.getElementById('jform_resize_w'); + const resizeHeight = document.getElementById('jform_resize_h'); + const resizeWidthInputBox = document.getElementById('jform_resize_width'); + const resizeHeightInputBox = document.getElementById('jform_resize_height'); + resizeWidthInputBox.removeEventListener('change', setHistory); + resizeHeightInputBox.removeEventListener('change', setHistory); + ['mouseup', 'touchend'].forEach((evt) => { + resizeHeight.addEventListener(evt, setHistory); + resizeWidth.addEventListener(evt, setHistory); + }); }; const initResize = () => { const funct = () => { + removeListeners(); const image = document.getElementById('image-source'); + const preview = document.getElementById('image-preview'); + const history = Joomla.MediaManager.Edit.history[Joomla.MediaManager.Edit.history.current]; + if (history && history.file) { + preview.src = history.file; + } const resizeWidthInputBox = document.getElementById('jform_resize_width'); const resizeHeightInputBox = document.getElementById('jform_resize_height'); @@ -58,18 +89,8 @@ Joomla.MediaManager.Edit = Joomla.MediaManager.Edit || {}; resizeHeightInputBox.value = image.height; // The listeners - resizeWidthInputBox.addEventListener('change', ({ target }) => { - resize( - parseInt(target.value, 10), - parseInt(target.value, 10) / (image.width / image.height), - ); - }); - resizeHeightInputBox.addEventListener('change', ({ target }) => { - resize( - parseInt(target.value, 10) * (image.width / image.height), - parseInt(target.value, 10), - ); - }); + resizeWidthInputBox.addEventListener('change', setHistory); + resizeHeightInputBox.addEventListener('change', setHistory); // Set the values for the range fields const resizeWidth = document.getElementById('jform_resize_w'); @@ -86,8 +107,8 @@ Joomla.MediaManager.Edit = Joomla.MediaManager.Edit || {}; // The listeners resizeWidth.addEventListener('input', ({ target }) => { resize( + parseInt(target.value, 10) * (image.width / image.height), parseInt(target.value, 10), - parseInt(target.value, 10) / (image.width / image.height), ); }); resizeHeight.addEventListener('input', ({ target }) => { @@ -96,6 +117,10 @@ Joomla.MediaManager.Edit = Joomla.MediaManager.Edit || {}; parseInt(target.value, 10), ); }); + ['mouseup', 'touchend'].forEach((evt) => { + resizeHeight.addEventListener(evt, setHistory); + resizeWidth.addEventListener(evt, setHistory); + }); }; setTimeout(funct, 1000); }; @@ -107,6 +132,7 @@ Joomla.MediaManager.Edit = Joomla.MediaManager.Edit || {}; initResize(mediaData); }, Deactivate() { + removeListeners(); }, }; })(); diff --git a/build/media_source/plg_media-action_rotate/js/rotate.es6.js b/build/media_source/plg_media-action_rotate/js/rotate.es6.js index 98da0369d2e8c..abee740c51fca 100644 --- a/build/media_source/plg_media-action_rotate/js/rotate.es6.js +++ b/build/media_source/plg_media-action_rotate/js/rotate.es6.js @@ -53,11 +53,19 @@ Joomla.MediaManager.Edit = Joomla.MediaManager.Edit || {}; document.getElementById('jform_rotate_a').value = angle; // Notify the app that a change has been made - window.dispatchEvent(new Event('mediaManager.history.point')); + const rotateData = { + angle, + }; + window.dispatchEvent(new CustomEvent('mediaManager.history.point', { detail: { rotate: rotateData, plugin: 'rotate' } })); }; const initRotate = () => { const funct = () => { + const image = document.getElementById('image-preview'); + const history = Joomla.MediaManager.Edit.history[Joomla.MediaManager.Edit.history.current]; + if (history && history.file) { + image.src = history.file; + } // The number input listener document.getElementById('jform_rotate_a').addEventListener('input', ({ target }) => { rotate(parseInt(target.value, 10)); diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql index 7009ce9952e0a..95b232373d4e2 100644 --- a/installation/sql/mysql/base.sql +++ b/installation/sql/mysql/base.sql @@ -153,7 +153,7 @@ INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`, (0, 'com_installer', 'component', 'com_installer', '', 1, 1, 1, 1, 1, '', '{"cachetimeout":"6","minimum_stability":"4"}', ''), (0, 'com_languages', 'component', 'com_languages', '', 1, 1, 1, 1, 1, '', '{"administrator":"en-GB","site":"en-GB"}', ''), (0, 'com_login', 'component', 'com_login', '', 1, 1, 1, 1, 1, '', '', ''), -(0, 'com_media', 'component', 'com_media', '', 1, 1, 0, 1, 1, '', '{"upload_extensions":"bmp,csv,doc,gif,ico,jpg,jpeg,odg,odp,ods,odt,pdf,png,ppt,txt,xcf,xls,BMP,CSV,DOC,GIF,ICO,JPG,JPEG,ODG,ODP,ODS,ODT,PDF,PNG,PPT,TXT,XCF,XLS","upload_maxsize":"10","file_path":"images","image_path":"images","restrict_uploads":"1","allowed_media_usergroup":"3","check_mime":"1","image_extensions":"bmp,gif,jpg,png","ignore_extensions":"","upload_mime":"image\\/jpeg,image\\/gif,image\\/png,image\\/bmp,application\\/msword,application\\/excel,application\\/pdf,application\\/powerpoint,text\\/plain,application\\/x-zip","upload_mime_illegal":"text\\/html"}', ''), +(0, 'com_media', 'component', 'com_media', '', 1, 1, 0, 1, 1, '', '{"upload_extensions":"bmp,csv,doc,gif,ico,jpg,jpeg,odg,odp,ods,odt,pdf,png,ppt,txt,xcf,xls,BMP,CSV,DOC,GIF,ICO,JPG,JPEG,ODG,ODP,ODS,ODT,PDF,PNG,PPT,TXT,XCF,XLS","upload_maxsize":"10","file_path":"images","image_path":"images","restrict_uploads":"1","allowed_media_usergroup":"3","check_mime":"1","image_extensions":"bmp,gif,jpg,png","ignore_extensions":"","upload_mime":"image\\/jpeg,image\\/gif,image\\/png,image\\/bmp,application\\/msword,application\\/excel,application\\/pdf,application\\/powerpoint,text\\/plain,application\\/x-zip","upload_mime_illegal":"text\\/html","history_length":"25"}', ''), (0, 'com_menus', 'component', 'com_menus', '', 1, 1, 1, 1, 1, '', '{"page_title":"","show_page_heading":0,"page_heading":"","pageclass_sfx":""}', ''), (0, 'com_messages', 'component', 'com_messages', '', 1, 1, 1, 1, 1, '', '', ''), (0, 'com_modules', 'component', 'com_modules', '', 1, 1, 1, 1, 1, '', '', ''), diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql index 1ab6f3624aea4..c257ff4acc130 100644 --- a/installation/sql/postgresql/base.sql +++ b/installation/sql/postgresql/base.sql @@ -159,7 +159,7 @@ INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder", (0, 'com_installer', 'component', 'com_installer', '', 1, 1, 1, 1, 1, '', '{"cachetimeout":"6","minimum_stability":"4"}', '', 0, 0), (0, 'com_languages', 'component', 'com_languages', '', 1, 1, 1, 1, 1, '', '{"administrator":"en-GB","site":"en-GB"}', '', 0, 0), (0, 'com_login', 'component', 'com_login', '', 1, 1, 1, 1, 1, '', '', '', 0, 0), -(0, 'com_media', 'component', 'com_media', '', 1, 1, 0, 1, 1, '', '{"upload_extensions":"bmp,csv,doc,gif,ico,jpg,jpeg,odg,odp,ods,odt,pdf,png,ppt,txt,xcf,xls,BMP,CSV,DOC,GIF,ICO,JPG,JPEG,ODG,ODP,ODS,ODT,PDF,PNG,PPT,TXT,XCF,XLS","upload_maxsize":"10","file_path":"images","image_path":"images","restrict_uploads":"1","allowed_media_usergroup":"3","check_mime":"1","image_extensions":"bmp,gif,jpg,png","ignore_extensions":"","upload_mime":"image\\/jpeg,image\\/gif,image\\/png,image\\/bmp,application\\/msword,application\\/excel,application\\/pdf,application\\/powerpoint,text\\/plain,application\\/x-zip","upload_mime_illegal":"text\\/html"}', '', 0, 0), +(0, 'com_media', 'component', 'com_media', '', 1, 1, 0, 1, 1, '', '{"upload_extensions":"bmp,csv,doc,gif,ico,jpg,jpeg,odg,odp,ods,odt,pdf,png,ppt,txt,xcf,xls,BMP,CSV,DOC,GIF,ICO,JPG,JPEG,ODG,ODP,ODS,ODT,PDF,PNG,PPT,TXT,XCF,XLS","upload_maxsize":"10","file_path":"images","image_path":"images","restrict_uploads":"1","allowed_media_usergroup":"3","check_mime":"1","image_extensions":"bmp,gif,jpg,png","ignore_extensions":"","upload_mime":"image\\/jpeg,image\\/gif,image\\/png,image\\/bmp,application\\/msword,application\\/excel,application\\/pdf,application\\/powerpoint,text\\/plain,application\\/x-zip","upload_mime_illegal":"text\\/html","history_length":"25"}', '', 0, 0), (0, 'com_menus', 'component', 'com_menus', '', 1, 1, 1, 1, 1, '', '{"page_title":"","show_page_heading":0,"page_heading":"","pageclass_sfx":""}', '', 0, 0), (0, 'com_messages', 'component', 'com_messages', '', 1, 1, 1, 1, 1, '', '', '', 0, 0), (0, 'com_modules', 'component', 'com_modules', '', 1, 1, 1, 1, 1, '', '', '', 0, 0), diff --git a/language/en-GB/com_media.ini b/language/en-GB/com_media.ini index 61a1fa3dd278e..c90365ad9be65 100644 --- a/language/en-GB/com_media.ini +++ b/language/en-GB/com_media.ini @@ -76,6 +76,8 @@ COM_MEDIA_FILESIZE="File size" COM_MEDIA_FOLDER="Folder" COM_MEDIA_FOLDER_NAME="Folder Name" COM_MEDIA_FOLDERS="Folders" +COM_MEDIA_HISTORY_LENGTH_DESC="Set the number of states stored in the history to a value between 1 and 100." +COM_MEDIA_HISTORY_LENGTH_LABEL="History States" COM_MEDIA_IMAGE_DESCRIPTION="Image Description" COM_MEDIA_IMAGE_URL="Image URL" COM_MEDIA_INCREASE_GRID="Increase grid size"