mirror of
				https://github.com/BookStackApp/BookStack.git
				synced 2025-10-31 03:50:27 +03:00 
			
		
		
		
	Quick patch to clear the gallery display when getting the first page. Duplication of the galler was occuring due to the mulitple upload events loading the gallery mulitple times while only clearing the existing gallery at the start of all refreshes. A bit flashy in terms of user experience, as there will still be mulitple load/clear events but fixes the duplication. Could be done more elegently in future by communicating up image upload counts. For #3160
		
			
				
	
	
		
			215 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			215 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import {onChildEvent, onSelect, removeLoading, showLoading} from "../services/dom";
 | |
| 
 | |
| /**
 | |
|  * ImageManager
 | |
|  * @extends {Component}
 | |
|  */
 | |
| class ImageManager {
 | |
| 
 | |
|     setup() {
 | |
| 
 | |
|         // Options
 | |
|         this.uploadedTo = this.$opts.uploadedTo;
 | |
| 
 | |
|         // Element References
 | |
|         this.container = this.$el;
 | |
|         this.popupEl = this.$refs.popup;
 | |
|         this.searchForm = this.$refs.searchForm;
 | |
|         this.searchInput = this.$refs.searchInput;
 | |
|         this.cancelSearch = this.$refs.cancelSearch;
 | |
|         this.listContainer = this.$refs.listContainer;
 | |
|         this.filterTabs = this.$manyRefs.filterTabs;
 | |
|         this.selectButton = this.$refs.selectButton;
 | |
|         this.formContainer = this.$refs.formContainer;
 | |
|         this.dropzoneContainer = this.$refs.dropzoneContainer;
 | |
| 
 | |
|         // Instance data
 | |
|         this.type = 'gallery';
 | |
|         this.lastSelected = {};
 | |
|         this.lastSelectedTime = 0;
 | |
|         this.callback = null;
 | |
|         this.resetState = () => {
 | |
|             this.hasData = false;
 | |
|             this.page = 1;
 | |
|             this.filter = 'all';
 | |
|         };
 | |
|         this.resetState();
 | |
| 
 | |
|         this.setupListeners();
 | |
| 
 | |
|         window.ImageManager = this;
 | |
|     }
 | |
| 
 | |
|     setupListeners() {
 | |
|         onSelect(this.filterTabs, e => {
 | |
|             this.resetAll();
 | |
|             this.filter = e.target.dataset.filter;
 | |
|             this.setActiveFilterTab(this.filter);
 | |
|             this.loadGallery();
 | |
|         });
 | |
| 
 | |
|         this.searchForm.addEventListener('submit', event => {
 | |
|             this.resetListView();
 | |
|             this.loadGallery();
 | |
|             event.preventDefault();
 | |
|         });
 | |
| 
 | |
|         onSelect(this.cancelSearch, event => {
 | |
|             this.resetListView();
 | |
|             this.resetSearchView();
 | |
|             this.loadGallery();
 | |
|             this.cancelSearch.classList.remove('active');
 | |
|         });
 | |
| 
 | |
|         this.searchInput.addEventListener('input', event => {
 | |
|             this.cancelSearch.classList.toggle('active', this.searchInput.value.trim());
 | |
|         });
 | |
| 
 | |
|         onChildEvent(this.listContainer, '.load-more', 'click', async event => {
 | |
|             showLoading(event.target);
 | |
|             this.page++;
 | |
|             await this.loadGallery();
 | |
|             event.target.remove();
 | |
|         });
 | |
| 
 | |
|         this.listContainer.addEventListener('event-emit-select-image', this.onImageSelectEvent.bind(this));
 | |
| 
 | |
|         this.listContainer.addEventListener('error', event => {
 | |
|             event.target.src = baseUrl('loading_error.png');
 | |
|         }, true);
 | |
| 
 | |
|         onSelect(this.selectButton, () => {
 | |
|             if (this.callback) {
 | |
|                 this.callback(this.lastSelected);
 | |
|             }
 | |
|             this.hide();
 | |
|         });
 | |
| 
 | |
|         onChildEvent(this.formContainer, '#image-manager-delete', 'click', event => {
 | |
|             if (this.lastSelected) {
 | |
|                 this.loadImageEditForm(this.lastSelected.id, true);
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         this.formContainer.addEventListener('ajax-form-success', this.refreshGallery.bind(this));
 | |
|         this.container.addEventListener('dropzone-success', this.refreshGallery.bind(this));
 | |
|     }
 | |
| 
 | |
|     show(callback, type = 'gallery') {
 | |
|         this.resetAll();
 | |
| 
 | |
|         this.callback = callback;
 | |
|         this.type = type;
 | |
|         this.popupEl.components.popup.show();
 | |
|         this.dropzoneContainer.classList.toggle('hidden', type !== 'gallery');
 | |
| 
 | |
|         if (!this.hasData) {
 | |
|             this.loadGallery();
 | |
|             this.hasData = true;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     hide() {
 | |
|         this.popupEl.components.popup.hide();
 | |
|     }
 | |
| 
 | |
|     async loadGallery() {
 | |
|         const params = {
 | |
|             page: this.page,
 | |
|             search: this.searchInput.value || null,
 | |
|             uploaded_to: this.uploadedTo,
 | |
|             filter_type: this.filter === 'all' ? null : this.filter,
 | |
|         };
 | |
| 
 | |
|         const {data: html} = await window.$http.get(`images/${this.type}`, params);
 | |
|         if (params.page === 1) {
 | |
|             this.listContainer.innerHTML = '';
 | |
|         }
 | |
|         this.addReturnedHtmlElementsToList(html);
 | |
|         removeLoading(this.listContainer);
 | |
|     }
 | |
| 
 | |
|     addReturnedHtmlElementsToList(html) {
 | |
|         const el = document.createElement('div');
 | |
|         el.innerHTML = html;
 | |
|         window.components.init(el);
 | |
|         for (const child of [...el.children]) {
 | |
|             this.listContainer.appendChild(child);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     setActiveFilterTab(filterName) {
 | |
|         this.filterTabs.forEach(t => t.classList.remove('selected'));
 | |
|         const activeTab = this.filterTabs.find(t => t.dataset.filter === filterName);
 | |
|         if (activeTab) {
 | |
|             activeTab.classList.add('selected');
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     resetAll() {
 | |
|         this.resetState();
 | |
|         this.resetListView();
 | |
|         this.resetSearchView();
 | |
|         this.resetEditForm();
 | |
|         this.setActiveFilterTab('all');
 | |
|         this.selectButton.classList.add('hidden');
 | |
|     }
 | |
| 
 | |
|     resetSearchView() {
 | |
|         this.searchInput.value = '';
 | |
|     }
 | |
| 
 | |
|     resetEditForm() {
 | |
|         this.formContainer.innerHTML = '';
 | |
|     }
 | |
| 
 | |
|     resetListView() {
 | |
|         showLoading(this.listContainer);
 | |
|         this.page = 1;
 | |
|     }
 | |
| 
 | |
|     refreshGallery() {
 | |
|         this.resetListView();
 | |
|         this.loadGallery();
 | |
|     }
 | |
| 
 | |
|     onImageSelectEvent(event) {
 | |
|         const image = JSON.parse(event.detail.data);
 | |
|         const isDblClick = ((image && image.id === this.lastSelected.id)
 | |
|             && Date.now() - this.lastSelectedTime < 400);
 | |
|         const alreadySelected = event.target.classList.contains('selected');
 | |
|         [...this.listContainer.querySelectorAll('.selected')].forEach(el => {
 | |
|             el.classList.remove('selected');
 | |
|         });
 | |
| 
 | |
|         if (!alreadySelected) {
 | |
|             event.target.classList.add('selected');
 | |
|             this.loadImageEditForm(image.id);
 | |
|         } else {
 | |
|             this.resetEditForm();
 | |
|         }
 | |
|         this.selectButton.classList.toggle('hidden', alreadySelected);
 | |
| 
 | |
|         if (isDblClick && this.callback) {
 | |
|             this.callback(image);
 | |
|             this.hide();
 | |
|         }
 | |
| 
 | |
|         this.lastSelected = image;
 | |
|         this.lastSelectedTime = Date.now();
 | |
|     }
 | |
| 
 | |
|     async loadImageEditForm(imageId, requestDelete = false) {
 | |
|         if (!requestDelete) {
 | |
|             this.formContainer.innerHTML = '';
 | |
|         }
 | |
| 
 | |
|         const params = requestDelete ? {delete: true} : {};
 | |
|         const {data: formHtml} = await window.$http.get(`/images/edit/${imageId}`, params);
 | |
|         this.formContainer.innerHTML = formHtml;
 | |
|         window.components.init(this.formContainer);
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| export default ImageManager; |