import { pluginSystem } from 'jodit/src/core/global'; // import { $$ } from 'jodit/src/core/helpers'; import { Dom, Plugin } from 'jodit/src/modules'; import { send, sendFiles } from 'jodit/src/modules/uploader/helpers'; import { IJodit } from 'jodit/src/types'; // import { openMultiImagePopup } from './popup/multi-image-popup'; import { watch } from 'jodit/src/core/decorators'; import './multi-image-collage.less'; /** ------------------------------------------------------------------------------ * * 08.22 콜라주 잠들다... * ------------------------------------------------------------------------------ */ export class MultiImageCollage extends Plugin { // private getCollageCount = (): number => { // const collageCount = $$('jodit-collage', this.j.editor).length; // return collageCount; // }; // private collageCount = 0; @watch(':click') protected onEditorClick(event: MouseEvent): void { if (this.j.o.readonly) { return; } const target = event.target; if (!target) { return; } if (!Dom.isTag(target, ['jodit-collage-item', 'jodit-collage'])) { this.removeSelector(); return; } this.showSelector(target as HTMLElement); } private collageSelector = this.j.c.fromHTML( "
" ); private isShowSelector = false; private showSelector = (target: HTMLElement): void => { if (this.isShowSelector) { this.removeSelector(); } const { top, left, width, height } = target.getBoundingClientRect(); const { top: wrapperTop, left: wrapperLeft } = this.j.workplace.getBoundingClientRect(); this.collageSelector.style.width = `${width}px`; this.collageSelector.style.height = `${height}px`; this.collageSelector.style.top = `${top - wrapperTop}px`; this.collageSelector.style.left = `${left - wrapperLeft}px`; this.j.workplace.appendChild(this.collageSelector); }; private removeSelector = (): void => { Dom.safeRemove(this.collageSelector); }; @watch(':change') protected onEditorChange(): void { this.removeSelector(); } @watch(':blur') protected onEditorBlur(): void { this.removeSelector(); } getImageList = async (fileList: File[]): Promise => { const uploadedCollageImages = await this.uploadImages(fileList); const promises = uploadedCollageImages .filter((item: any) => item) .map( (uploadedImage: any) => new Promise((resolve, reject) => { const img = new Image(); img.onload = (): void => { resolve({ width: img.naturalWidth, height: img.naturalHeight, url: uploadedImage.url }); }; img.onerror = reject; img.src = uploadedImage.url; }) ); return await Promise.all(promises); }; // private collageItemTemplate = (image: { // url: string; // width: number; // height: number; // collageIndex: number; // }): string => // ``; private uploadImages = async (files: File[]): Promise => { const promises: Array> = files.map(this.sendFile); return Promise.all(promises); }; protected override afterInit(jodit: IJodit): void { this.j.e.on('multiImageUploaded', async files => { // const createCollage = async (): Promise => { // if (files.length > 10) { // const collageImages = files.slice(0, 10); // const restImages = files.slice(10); // const uploadedImages = await this.getImageList( // collageImages // ); // const result = this.sizeItems(uploadedImages); // sendFiles(this.j.uploader, restImages); // this.createCollage(result); // } else { // const uploadedImages = await this.getImageList(files); // const result = this.sizeItems(uploadedImages); // this.createCollage(result); // } // }; const createIndividualImages = async (): Promise => { sendFiles(this.j.uploader, files); }; // openMultiImagePopup(this.j, createIndividualImages, createCollage); createIndividualImages(); this.j.e.fire('closeAllPopups'); }); // this.j.e.on('change', () => { // this.collageCount = this.getCollageCount(); // }); // this.j.e.on('collage-item-delete', this.handleDeleteCollageItem); } // private handleDeleteCollageItem = (collageIndex: string): void => { // const targetCollage = document.querySelector( // `[data-collage-index="${collageIndex}"]` // ); // const children = $$('jodit-collage-item', targetCollage as HTMLElement); // if (children.length === 0) { // this.j.s.removeNode(targetCollage as HTMLElement); // this.j.e.fire('change'); // return; // } // const childrenSizes = children.map(child => { // const { width, height } = child.style; // const src = child.getAttribute('src') as string; // const numberWidth = Number(width.replace('px', '')); // const numberHeight = Number(height.replace('px', '')); // return { width: numberWidth, height: numberHeight, url: src }; // }); // const resized = this.sizeItems(childrenSizes); // children.forEach((child, index) => { // child.style.width = `${resized[index].width}px`; // child.style.height = `${resized[index].height}px`; // }); // }; // private createCollage = (images: any[]): void => { // const collage = (children: string): string => { // return `${children}`; // }; // const collageItems = images // .map(item => ({ ...item, collageIndex: this.collageCount })) // .map(this.collageItemTemplate) // .join(''); // const collageHTML = collage(collageItems); // const collageElement = this.j.c.fromHTML(collageHTML); // this.j.s.insertHTML(collageElement); // this.j.e.fire('change'); // this.j.e.fire('closeAllPopups'); // }; // private sizeItems = ( // items: Array<{ width: number; height: number; url: string }> // ): any[] => { // const twoDimensional: any[] = []; // let index = 0; // items.forEach(item => { // const { width, height } = item; // const ratio = width / height; // if (ratio >= 2) { // if (twoDimensional[index]?.length === 1) { // twoDimensional[index].push(item); // index++; // return; // } // twoDimensional[index] = [item]; // index++; // return; // } // if (!twoDimensional[index]) { // twoDimensional[index] = []; // } // twoDimensional[index].push(item); // if (twoDimensional[index]?.length === 2) { // index++; // } // }); // const result = twoDimensional.map(array => { // const COLLAGE_WIDTH = 855; // const MIN_HEIGHT = 145; // const MAX_HEIGHT = 855; // const GAP = 5; // const TOTAL_WIDTH = COLLAGE_WIDTH - GAP; // if (array.length === 1) { // return array.map((item: any) => ({ // url: item.url, // width: COLLAGE_WIDTH, // height: COLLAGE_WIDTH * (item.height / item.width) // })); // } // const [first, second] = array; // const firstRatio = first.width / first.height; // const secondRatio = second.width / second.height; // const totalRatio = firstRatio + secondRatio; // const firstWidth = (firstRatio / totalRatio) * TOTAL_WIDTH; // const secondWidth = (secondRatio / totalRatio) * TOTAL_WIDTH; // const firstHeight = firstWidth / firstRatio; // const secondHeight = secondWidth / secondRatio; // const clampHeight = (num: number): number => // Math.min(Math.max(num, MIN_HEIGHT), MAX_HEIGHT); // return [ // { // ...first, // width: firstWidth, // height: clampHeight(firstHeight) // }, // { // ...second, // width: secondWidth, // height: clampHeight(secondHeight) // } // ]; // }); // return result.flat(); // }; protected override beforeDestruct(jodit: IJodit): void {} private sendFile = async (file: File): Promise => { const { o } = this.j.uploader; const form = new FormData(); const hasRealExtension = /\.[\d\w]+$/.test(file.name); const match_type = file.type.match(/([a-z0-9]+)\//i) as string[]; const match_extension = file.type.match(/\/([a-z0-9]+)/i) as string[]; const fileType: string = match_type && match_type[1] ? match_type[1].toLowerCase() : ''; const fileExtension: string = match_extension && match_extension[1] ? match_extension[1].toLowerCase() : ''; const time = String(new Date().getTime()); let newName = file.name ? `${time}_${file.name}` : time; if (!hasRealExtension && fileExtension) { let extForReg = fileExtension; if (['jpeg', 'jpg'].includes(extForReg)) { extForReg = 'jpeg|jpg'; } const reEnd = new RegExp('.(' + extForReg + ')$', 'i'); if (!reEnd.test(newName)) { newName += '.' + fileExtension; } } const [key, iFile, name] = o.processFileName.call( this.j.uploader, o.filesVariableName(fileType, fileExtension), file, newName ); form.append(key, iFile, name); return send(this.j.uploader, form).then(response => response.data); }; } pluginSystem.add('multi-image-collage', MultiImageCollage);