PageSourceSearch

https://www.simpleimageresizer.com/static/js/components.js?v=173

js simpleimageresizer.com collected 2026-09-24 09:17:41 UTC 35,786 bytes, 868 lines download raw bytes

1// resized/uploaded images template components
2
3const rowBreakerComponent = () => {
4    const rowBreaker = document.createElement('div');
5    rowBreaker.className = 'row-breaker';
6    return rowBreaker
7}
8
9const createTemporaryDownloadLink = (Obj) => {
10    const tempLink = document.createElement('a');
11    tempLink.href = Obj.optimizedImg;
12    tempLink.setAttribute('download', Obj.fileName);
13    document.body.appendChild(tempLink);
14    tempLink.click();
15    tempLink.remove();
16}
17
18const downloadBtnWithIconComponent = (Obj) => {
19    const downloadBtn = document.createElement('button');
20    const downloadBtnIcon = document.createElement('img');
21    const downloadBtnLink = document.createElement('a');
22    downloadBtn.id = 'download-image-id';
23    downloadBtn.className = 'desktop-download-icon btn btn-blue';
24    downloadBtnIcon.className = 'download-btn-icon';
25    downloadBtnLink.className = 'download-btn-link-desktop';
26    downloadBtn.setAttribute('type', 'button')
27    if (resizerJpUrls.includes(pageUrl)) {
28        downloadBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" fill="#fff" style="vertical-align: sub"><path d="M480-320 280-520l56-58 104 104v-326h80v326l104-104 56 58-200 200ZM240-160q-33 0-56.5-23.5T160-240v-120h80v120h480v-120h80v120q0 33-23.5 56.5T720-160H240Z"/></svg> ダウンロード `
29    } else {
30        downloadBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" fill="#fff" style="vertical-align: sub"><path d="M480-320 280-520l56-58 104 104v-326h80v326l104-104 56 58-200 200ZM240-160q-33 0-56.5-23.5T160-240v-120h80v120h480v-120h80v120q0 33-23.5 56.5T720-160H240Z"/></svg> Download `
31    }
32    downloadBtnLink.setAttribute('href', Obj.optimizedImg);
33    downloadBtnLink.setAttribute('download', Obj.fileName);
34    downloadBtnLink.setAttribute('aria-label', 'Download optimized image');
35    downloadBtnLink.addEventListener(TYPE_CLICK, () => {
36        gtag('event', DOWNLOAD_EVENT_NAME);
37    })
38
39    downloadBtnLink.ondragstart = () => {
40        return false
41    }
42    appendToElement(downloadBtnLink, downloadBtn)
43    return downloadBtnLink
44}
45
46const downloadPaidFileBtnWithIconComponent = (Obj) => {
47    const downloadBtn = document.createElement('button');
48    const downloadBtnIcon = document.createElement('img');
49    const downloadBtnLink = document.createElement('a');
50    downloadBtn.id = 'download-image-id';
51    downloadBtn.className = 'desktop-download-icon btn btn-blue';
52    downloadBtnIcon.className = 'download-btn-icon';
53    downloadBtnLink.className = 'download-btn-link-desktop';
54    downloadBtn.setAttribute('type', 'button')
55    downloadBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" fill="#fff" style="vertical-align: sub"><path d="M480-320 280-520l56-58 104 104v-326h80v326l104-104 56 58-200 200ZM240-160q-33 0-56.5-23.5T160-240v-120h80v120h480v-120h80v120q0 33-23.5 56.5T720-160H240Z"/></svg> Download `
56    downloadBtnLink.setAttribute('href', Obj.optimizedImg);
57    downloadBtnLink.setAttribute('download', Obj.fileName);
58    downloadBtnLink.setAttribute('aria-label', 'Download compressed PDF file');
59    downloadBtnLink.addEventListener(TYPE_CLICK, () => {
60        gtag('event', DOWNLOAD_EVENT_NAME);
61    })
62
63    downloadBtnLink.addEventListener(TYPE_CLICK, async (e) => {
64        e.preventDefault()
65        if (!isFileOptimizationPremium() || await isAPIResponseVerified(VERIFY_USER_API_URL) || await isAPIResponseVerified(VERIFY_ONE_TIME_PURCHASE_API_URL)) {
66            createTemporaryDownloadLink(Obj)
67            gtag('event', DOWNLOAD_EVENT_NAME);
68            await fetchPOSTRequest('/api/create-txt-files', {
69                "name": `${Obj.fileName}`
70            })
71        } else {
72            displayPaidActionPopup();
73        }
74    })
75
76    downloadBtnLink.ondragstart = () => {
77        return false
78    }
79    appendToElement(downloadBtnLink, downloadBtn)
80    return downloadBtnLink
81}
82
83const downloadBtnWithoutIconComponent = (Obj) => {
84    const downloadBtn = document.createElement('button');
85    const downloadBtnLink = document.createElement('a');
86    downloadBtn.id = 'download-image-id';
87    downloadBtn.className = 'desktop-download-icon btn btn-blue btn-webp-download';
88    downloadBtnLink.className = 'download-btn-link-desktop';
89    downloadBtn.setAttribute('type', 'button')
90    downloadBtn.innerText = Obj.btnContent
91    downloadBtnLink.setAttribute('href', Obj.url);
92    downloadBtnLink.setAttribute('download', Obj.fileName);
93    downloadBtnLink.addEventListener(TYPE_CLICK, () => {
94        gtag('event', Obj.eventName);
95    })
96    downloadBtnLink.ondragstart = () => {
97        return false
98    }
99    appendToElement(downloadBtnLink, downloadBtn)
100    return downloadBtnLink
101}
102
103const mobileDownloadLinkComponent = (url, downloadName, downloadEvent) => {
104    const mobileDownloadLink = document.createElement('a');
105    const mobileDownloadIcon = document.createElement('img');
106    mobileDownloadIcon.className = 'mobile-download-icon'
107    mobileDownloadIcon.src = '/static/images/download-image.svg';
108    mobileDownloadIcon.alt = 'Download Image';
109    mobileDownloadLink.id = 'mobile-download-id';
110    mobileDownloadLink.setAttribute('href', url)
111    mobileDownloadLink.setAttribute('download', downloadName);
112    mobileDownloadLink.setAttribute('aria-label', 'Download optimized image');
113    mobileDownloadLink.addEventListener(TYPE_CLICK, () => {
114        gtag('event', downloadEvent);
115    })
116    appendToElement(mobileDownloadLink, mobileDownloadIcon)
117    mobileDownloadLink.ondragstart = () => {
118        return false
119    }
120    return mobileDownloadLink
121}
122
123const mobileCompareLinkComponent = (url, compareEvent) => {
124    const mobileCompareLink = document.createElement('a');
125    const mobileCompareIcon = document.createElement('img');
126    mobileCompareIcon.className = 'mobile-compare-icon'
127    mobileCompareIcon.src = '/static/images/compare-icon.svg';
128    mobileCompareIcon.alt = 'Compare Images';
129    mobileCompareLink.id = 'mobile-compare-icon-id';
130    appendToElement(mobileCompareLink, mobileCompareIcon)
131    mobileCompareLink.addEventListener(TYPE_CLICK, () => {
132        gtag('event', compareEvent);
133        window.open(url, "_blank")
134    })
135    mobileCompareLink.ondragstart = () => {
136        return false
137    }
138    return mobileCompareLink
139}
140
141const compareBtnWithIconComponent = (Obj) => {
142    const compareBtn = document.createElement('button');
143    const compareBtnIcon = document.createElement('img');
144    const compareBtnLink = document.createElement('a');
145    compareBtn.id = 'btn-compare-images-id';
146    compareBtn.className = 'desktop-compare-icon btn btn-outline-primary';
147    compareBtnIcon.className = 'compare-btn-icon';
148    compareBtnLink.className = 'compare-btn-link-desktop';
149    compareBtn.setAttribute('type', 'button')
150    compareBtnLink.setAttribute('aria-label', 'Compare original and optimized image');
151    compareBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" fill="#377dff">
152    <path d="M400-40v-80H200q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h200v-80h80v880h-80ZM200-240h200v-240L200-240Zm360 120v-360l200 240v-520H560v-80h200q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H560Z"/>
153    </svg>Compare`
154    compareBtnLink.addEventListener(TYPE_CLICK, () => {
155        gtag('event', COMPARE_EVENT_NAME);
156        window.open(Obj.compareUrl, "_blank")
157    })
158    compareBtnLink.ondragstart = () => {
159        return false
160    }
161    appendToElement(compareBtnLink, compareBtn)
162    return compareBtnLink
163}
164
165const previewBtnWithIconComponent = (Obj) => {
166    const previewBtn = document.createElement('button');
167    const previewBtnIcon = document.createElement('img');
168    const previewBtnLink = document.createElement('a');
169    previewBtn.id = 'btn-compare-images-id';
170    previewBtn.className = 'desktop-compare-icon btn btn-outline-primary';
171    previewBtnIcon.className = 'compare-btn-icon';
172    previewBtnLink.className = 'compare-btn-link-desktop';
173    previewBtn.setAttribute('type', 'button')
174    previewBtnLink.setAttribute('aria-label', 'Compressed file demo preview');
175    previewBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#377
175dff"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-480H200v480Zm280-80q-82 0-146.5-44.5T240-440q29-71 93.5-115.5T480-600q82 0 146.5 44.5T720-440q-29 71-93.5 115.5T480-280Zm0-60q56 0 102-26.5t72-73.5q-26-47-72-73.5T480-540q-56 0-102 26.5T306-440q26 47 72 73.5T480-340Zm0-100Zm0 60q25 0 42.5-17.5T540-440q0-25-17.5-42.5T480-500q-25 0-42.5 17.5T420-440q0 25 17.5 42.5T480-380Z"/></svg> Preview`
176    previewBtnLink.addEventListener(TYPE_CLICK, () => {
177        gtag('event', COMPARE_EVENT_NAME);
178        window.open(Obj.compareUrl, "_blank")
179    })
180    previewBtnLink.ondragstart = () => {
181        return false
182    }
183    appendToElement(previewBtnLink, previewBtn)
184    return previewBtnLink
185}
186
187const deleteIconComponent = (uploadedImagesArray, baseStringsArray, index) => {
188    const deleteIcon = document.createElement('img');
189    deleteIcon.className = 'delete-image';
190    deleteIcon.src = '/static/images/trash-icon-no-border.svg';
191    deleteIcon.alt = 'Delete uploaded image';
192    deleteIcon.setAttribute('data-index', '' + index);
193    deleteIcon.addEventListener(TYPE_CLICK, (event) => {
194        let imageIndex = parseInt(event.target.attributes['data-index'].value, 10);
195        uploadedImagesArray.splice(imageIndex, 1);
196        baseStringsArray.splice(imageIndex, 1);
197        showUploadedImages();
198        if (uploadedImagesArray.length <= MAX_UPLOADED_PHOTOS_NUM) {
199            hideElement(uploadedFilesValidationPopup)
200        }
201    })
202    return deleteIcon
203}
204const uploadedImageTemplateComponent = () => {
205    const uploadedImageTemplate = document.createElement('div');
206    uploadedImageTemplate.className = 'uploaded-image-template';
207    uploadedImageTemplate.id = 'uploaded-image-template-id';
208    uploadedImageTemplate.name = 'uploaded-image-template-name';
209    return uploadedImageTemplate
210}
211
212const uploadedImageToCropComponent = (imageContainer, imageSrc) => {
213    const uploadedImage = document.createElement('img');
214    uploadedImage.id = 'uploaded-image';
215    uploadedImage.src = imageSrc;
216    imageContainer.innerHTML = '';
217    appendToElement(imageContainer, uploadedImage)
218    return uploadedImage
219}
220
221const uploadedImageThumbnailComponent = (file) => {
222    const uploadedImageThumbnail = document.createElement('img');
223    uploadedImageThumbnail.className = 'uploaded-image';
224    uploadedImageThumbnail.id = 'uploaded-image-id';
225    uploadedImageThumbnail.src = pdfPages.includes(pageUrl) ? '/static/images/pdf-icon.png' : URL.createObjectURL(file);
226    uploadedImageThumbnail.alt = "Thumbnail"
227    return uploadedImageThumbnail
228}
229
230const resizedImageThumbnailComponent = (url) => {
231    const uploadedImageThumbnail = document.createElement('img');
232    uploadedImageThumbnail.className = 'uploaded-image';
233    uploadedImageThumbnail.id = 'uploaded-image-id';
234    uploadedImageThumbnail.src = pdfPages.includes(pageUrl) ? '/static/images/pdf-icon.png' : url;
235    uploadedImageThumbnail.alt = "Thumbnail"
236    return uploadedImageThumbnail
237}
238
239const imageContainerComponent = () => {
240    const imageContainer = document.createElement('div');
241    imageContainer.className = 'image-container';
242    imageContainer.id = 'image-container-id'
243    return imageContainer
244}
245
246const uploadedImageNameComponent = (name) => {
247    const uploadedImageName = document.createElement('span');
248    uploadedImageName.className = 'uploaded-image-name';
249    uploadedImageName.innerHTML = `<strong>${name}</strong>`;
250    return uploadedImageName
251}
252
253const uploadedImageFormatComponent = () => {
254    const uploadedImageFormat = document.createElement('span');
255    uploadedImageFormat.className = 'from-to-formats-converted';
256    return uploadedImageFormat
257}
258
259const uploadedImageData = (name, file) => {
260    const uploadedImageTemplate = uploadedImageTemplateComponent()
261    const uploadedImageThumbnail = uploadedImageThumbnailComponent(file)
262    const uploadedImageName = uploadedImageNameComponent(name)
263    const imageContainer = imageContainerComponent()
264    return {
265        'imageTemplate': uploadedImageTemplate, 'imageThumbnail': uploadedImageThumbnail,
266        "imageName": uploadedImageName, "imageContainer": imageContainer
267    }
268}
269
270const resizedImageData = (name, url) => {
271    const uploadedImageTemplate = uploadedImageTemplateComponent()
272    const uploadedImageThumbnail = resizedImageThumbnailComponent(url)
273    const uploadedImageName = uploadedImageNameComponent(name)
274    const imageContainer = imageContainerComponent()
275    return {
276        'imageTemplate': uploadedImageTemplate, 'imageThumbnail': uploadedImageThumbnail,
277        "imageName": uploadedImageName, "imageContainer": imageContainer
278    }
279}
280
281const imgTxtDataElements = () => {
282    const sizeBefore = document.createElement('span');
283    const formatsSeparator = document.createElement('span')
284    const sizeAfter = document.createElement('span');
285    const readyToConvert = document.createElement('span');
286    sizeBefore.id = 'img-size-and-res-id';
287    sizeBefore.className = 'img-size-and-res';
288    sizeAfter.id = 'img-size-after-id';
289    sizeAfter.className = 'img-size-after';
290    formatsSeparator.className = 'formats-separator';
291    readyToConvert.className = 'ready-to-convert';
292    return {"sizeBefore": sizeBefore, "sizeAfter": sizeAfter, "separator": formatsSeparator, "ready": readyToConvert}
293}
294
295// resized images template
296const resizedFromToComponent = (sizeBefore, separator, sizeAfter, savings, savedSize, savedPercentage, resizeAction) => {
297    const convertFromFormat = document.createElement('p');
298    const formatsSeparator = document.createElement('span')
299    const convertToFormat = document.createElement('p');
300    const convertedSpan = document.createElement('span');
301    const savingsSpan = document.createElement('span');
302    const savedWeight = document.createElement('span');
303    const savedPercent = document.createElement('span');
304    convertFromFormat.id = 'convert-from-id';
305    convertFromFormat.className = 'convert-from';
306    convertFromFormat.innerText = sizeBefore;
307    formatsSeparator.className = 'formats-separator';
308    formatsSeparator.innerText = separator;
309    convertToFormat.id = 'convert-to-id';
310    convertToFormat.className = 'convert-to';
311    convertToFormat.innerText = sizeAfter;
312    convertedSpan.className = 'converted-span';
313    convertedSpan.innerText = resizeAction;
314    savingsSpan.className = 'savings-span';
315    savingsSpan.innerText = savings
316    savedWeight.className = 'saved-weight'
317    savedWeight.innerText = savedSize
318    savedPercent.className = 'saved-percent'
319    savedPercent.innerText = `(${savedPercentage} %)`
320
321    return {
322        convertFromFormatKey: convertFromFormat,
323        formatsSeparatorKey: formatsSeparator, convertToFormatKey: convertToFormat,
324        convertedSpanKey: convertedSpan, savingsSpanKey: savingsSpan,
325        savedWeightKey: savedWeight, savedPercentKey: savedPercent
326    }
327}
328// uploaded images template
329
330const appendUploadedImageWithResolutionAndSize = (Obj) => {
331    const imageData = uploadedImageData(Obj.name, uploadedImages[Obj.index])
332    const deleteIcon = deleteIconComponent(uploadedImages, strings64BaseArray, Obj.index)
333    const imageTxtData = imgTxtDataElements()
334
335    const imageDataWrapper = document.createElement('div')
336    imageDataWrapper.className = 'uploaded-image-data-wrapper'
337
338    appendToElement(uploadedImageContainer, imageData.imageTemplate)
339    appendToElement(imageData.imageContainer, imageData.imageThumbnail)
340
341    appendMultipleElements(
342        imageDataWrapper,
343        [
344            imageData.imageName,
345            imageTxtData.sizeBefore
346        ]
347    )
348
349    appendMultipleElements(
350        imageData.imageTemplate,
351        [
352            imageData.imageContainer,
353            imageDataWrapper,
354        ])
355
356    appendToElement(imageData.imageTemplate, deleteIcon)
357
358    displayDefaultImage('uploaded-image');
359    displayHEICImageThumbnail(uploadedImages[Obj.index], imageData.imageThumbnail);
360    displayUploadedImagesResolutionAndSize(uploadedImages[Obj.index], imageTxtData.sizeBefore, Obj.widthIn, Obj.heightIn)
361}
362
363const appendUploadedImageForInstagram = (Obj) => {
364    const imageData = uploadedImageData(Obj.name, uploadedImages[Obj.index])
365    const deleteIcon = deleteIconComponent(uploadedImages, strings64BaseArray, Obj.index)
366    const imageTxtData = imgTxtDataElements()
367
368    const imageDataWrapper = document.createElement('div')
369    imageDataWrapper.className = 'uploaded-image-data-wrapper'
370
371    addClassToElement(imageData.imageContainer, 'item')
372    addClassToElement(imageDataWrapper, 'item')
373
374    appendToElement(uploadedImageContainer, imageData.imageTemplate)
375    appendToElement(imageData.imageContainer, imageData.imageThumbnail)
376
377    appendMultipleElements(
378        imageDataWrapper,
379        [
380            imageData.imageName,
381            imageTxtData.sizeBefore,
382            deleteIcon
383        ]
384    )
385
386    appendMultipleElements(
387        imageData.imageTemplate,
388        [
389            imageData.imageContainer,
390            imageDataWrapper,
391        ])
392
393    displayDefaultImage('uploaded-image');
394    displayHEICImageThumbnail(uploadedImages[Obj.index], imageData.imageThumbnail);
395    displayUploadedImagesResolutionAndSize(uploadedImages[Obj.index], imageTxtData.sizeBefore, Obj.widthIn, Obj.heightIn)
396}
397
398
399const optimizedImageDataComponent = (optimizedImgDataObj) => {
400    const imageDataWrapper = document.createElement('div')
401    imageDataWrapper.className = 'converted-image-data'
402    const imageName = document.createElement('span')
403    imageName.className = 'converted-image-name'
404    const savingsSpan = document.createElement('span')
405    savingsSpan.className = 'savings'
406    const reducedSpan = document.createElement('span')
407
408    imageName.innerHTML = `<strong>${optimizedImgDataObj.name}</strong>`
409    savingsSpan.innerHTML = `<strong>${optimizedImgDataObj.savings}</strong>      `
410    reducedSpan.innerHTML = `<strong>${optimizedImgDataObj.sizeCompare}</strong>`
411
412    appendMultipleElements(
413        imageDataWrapper,
414        [
415            imageName,
416            savingsSpan,
417            reducedSpan
418        ]
419    )
420    return imageDataWrapper
421}
422
423const appendResizedImage = (resizedImgObj) => {
424    const imageData = resizedImageData(resizedImgObj.fileName, resizedImgObj.optimizedImg)
425    const uploadedImageFormat = uploadedImageFormatComponent()
426    let optimizedImgDataObj = {
427        name: resizedImgObj.shortName,
428        savings: resizedImgObj.savings,
429        sizeCompare: resizedImgObj.sizeComp
430    }
431    const compressedImageData = optimizedImageDataComponent(optimizedImgDataObj)
432    const successResultButtons = document.createElement('div')
433    successResultButtons.className = 'success-result-buttons-panel'
434
435    const downloadBtnLink = pdfPages.includes(pageUrl) ? downloadPaidFileBtnWithIconComponent(resizedImgObj) : downloadBtnWithIconComponent(resizedImgObj)
436    const compareLink = pdfPages.includes(pageUrl) ? previewBtnWithIconComponent(resizedImgObj) : compareBtnWithIconComponent(resizedImgObj);
437
438    displayDefaultImage();
439    displayHEICImageThumbnail(resizedImgObj.originImg, imageData.imageThumbnail);
440    buttonsPanel.className = 'buttons-panel'
441    appendMultipleElements(
442        resizedImgObj.imgContainer,
443        [
444            imageData.imageTemplate,
445            buttonsPanel
446        ]
447    )
448
449    appendToElement(imageData.imageContainer, imageData.imageThumbnail)
450    appendToElement(uploadedImageFormat, compressedImageData)
451
452    appendMultipleElements(
453        successResultButtons,
454        [
455            compareLink,
456            downloadBtnLink,
457        ])
458
459    appendMultipleElements(
460        imageData.imageTemplate,
461        [
462            imageData.imageContainer,
463            uploadedImageFormat,
464            successResultButtons
465        ])
466}
467
468
469const appendResizedImagesWithDisplayedPictureCroppedToDimensions = (name, file, url, downloadName, sizeBefore, separator, sizeAfter, savings, savedSize, savedPercentage, resizeAction, downloadEvent) => {
470    const uploadedImageTemplate = uploadedImageTemplateComponent()
471    const uploadedImageThumbnail = uploadedImageThumbnailComponent(file)
472    const imageContainer = imageContainerComponent()
473    const uploadedImageName = uploadedImageNameComponent(name)
474    const uploadedImageFormat = uploadedImageFormatComponent()
475    const fromToComponent = resizedFromToComponent(sizeBefore, separator, sizeAfter, savings, savedSize, savedPercentage, resizeAction)
476    const convertFromFormat = fromToComponent['convertFromFormatKey']
477    const formatsSeparator = fromToComponent['formatsSeparatorKey']
478    const convertToFormat = fromToComponent['convertToFormatKey']
479    const convertedSpan = fromToComponent['convertedSpanKey']
480    const savingsSpan = fromToComponent['savingsSpanKey']
481    const savedWeight = fromToComponent['savedWeightKey']
482    const savedPercent = fromToComponent['savedPercentKey']
483    const rowBreaker = rowBreakerComponent()
484    const downloadBtnLink = downloadBtnWithIconComponent(url, downloadName, downloadEvent)
485    const mobileDownloadLink = mobileDownloadLinkComponent(url, downloadName);
486    displayDefaultImage();
487    displayHEICImageThumbnail(file, uploadedImageThumbnail);
488    buttonsPanel.className = 'buttons-panel'
489    appendMultipleElements(
490        resizedImageContainer,
491        [
492            uploadedImageTemplate,
493            buttonsPanel,
494
495        ]
496    )
497
498    appendToElement(imageContainer, uploadedImageThumbnail)
499
500    appendMultipleElements(
501        uploadedImageFormat,
502        [
503            uploadedImageName,
504            convertedSpan,
505            convertFromFormat,
506            formatsSeparator,
507            convertToFormat,
508            rowBreaker,
509            savingsSpan,
510            savedWeight,
511            savedPercent,
512        ]
513    )
514
515    appendMultipleElements(
516        uploadedImageTemplate,
517        [
518            imageContainer,
519            uploadedImageFormat,
520            downloadBtnLink,
521            mobileDownloadLink,
522        ]
523    )
524}
525
526const returnResolutionSpan = (resSpan, obj) => {
527    if (obj.resBefore === obj.resAfter) {
528        resSpan.innerHTML = `✅ <strong>${obj.resBefore}</strong>`
529    } else {
530        resSpan.innerHTML = `✅ <strong>${obj.resBefore}</strong> <img src="/static/images/arrow-right-new.svg" alt="Resize result" class="inline-block" loading="lazy"> <strong style="color: var(--btn-green)">${obj.resAfter}</strong>`
531    }
532    return resSpan
533}
534
535const returnSavingsSpan = (savingsSpan, obj) => {
536    if (obj.savings.includes('-')) {
537        savingsSpan.innerHTML = `✅ <strong>${obj.sizeBefore}</strong> <img src="/static/images/arrow-right-new.svg" alt="Resize result" class="inline-block" loading="lazy"> <strong style="color: var(--btn-green)">${obj.sizeAfter}</strong>`
538    } else {
539        savingsSpan.innerHTML = `✅ <strong>${obj.sizeBefore}</strong> <img src="/static/images/arrow-right-new.svg" alt="Resize result" class="inline-block" loading="lazy"> <strong style="color: var(--btn-green)">${obj.sizeAfter} | Saved ${obj.savings} (${obj.savedPercentage}%)</strong>`
540    }
541    return savingsSpan
542}
543
544const resizedImageDataComponent = (name, obj) => {
545    const imageDataWrapper = document.createElement('div')
546    imageDataWrapper.className = 'converted-image-data'
547    const imageName = document.createElement('span')
548    imageName.className = 'converted-image-name'
549    const savingsSpan = document.createElement('span')
550    const reducedSpan = document.createElement('span')
551
552    imageName.innerHTML = `<strong>${name}</strong>`
553
554    if (resizerJpUrls.includes(pageUrl)) {
555        savingsSpan.innerHTML = `元のサイズ: <strong>${obj.fileSizeBefore}</strong>`;
556        reducedSpan.innerHTML = `変更後のサイズ: <strong>${obj.fileSizeAfter}</strong>`;
557    } else if (pdfPages.includes(pageUrl)) {
558        returnSavingsSpan(savingsSpan, obj)
559    } else {
560        returnResolutionSpan(savingsSpan, obj)
561        returnSavingsSpan(reducedSpan, obj)
562    }
563
564    appendMultipleElements(
565        imageDataWrapper,
566        [
567            imageName,
568            savingsSpan,
569            reducedSpan
570        ]
571    )
572    return imageDataWrapper
573}
574
575const appendCroppedAndResizedImages = (Obj) => {
576    const imageData = resizedImageData(shortName, Obj.optimizedImg)
577    const uploadedImageFormat = uploadedImageFormatComponent()
578    const imageResolutionAndSizeElement = document.createElement('span');
579    imageResolutionAndSizeElement.id = 'img-res-id';
580    imageResolutionAndSizeElement.className = 'img-size-and-res';
581    if (!pdfPages.includes(pageUrl) && Obj.resBefore) {
582        imageResolutionAndSizeElement.innerText = Obj.resBefore;
583    }
584
585    const resizedImageDataComp = resizedImageDataComponent(shortName, Obj)
586
587    const successResultButtons = document.createElement('div')
588    successResultButtons.className = 'success-result-buttons-panel'
589
590    const downloadBtnLink = pdfPages.includes(pageUrl) ? downloadPaidFileBtnWithIconComponent(Obj) : downloadBtnWithIconComponent(Obj)
591    const compareLink = pdfPages.includes(pageUrl) ? previewBtnWithIconComponent(Obj) : compareBtnWithIconComponent(Obj)
592
593    displayDefaultImage();
594    displayHEICImageThumbnail(uploadedImages[Obj.index], imageData.imageThumbnail);
595    displayUploadedImagesResolutionAndSize(uploadedImages[Obj.index], imageResolutionAndSizeElement, '', '')
596    buttonsPanel.className = 'buttons-panel'
597
598    appendMultipleElements(
599        Obj.imgContainer,
600        [
601            imageData.imageTemplate,
602            buttonsPanel,
603        ]
604    )
605
606    appendMultipleElements(
607        successResultButtons,
608        [
609            compareLink,
610            downloadBtnLink,
611        ]
612    )
613
614    appendToElement(imageData.imageContainer, imageData.imageThumbnail)
615    appendToElement(uploadedImageFormat, resizedImageDataComp)
616
617    appendMultipleElements(
618        imageData.imageTemplate,
619        [
620            imageData.imageContainer,
621            uploadedImageFormat,
622            successResultButtons
623        ]
624    )
625}
626
627const convertedImageDataComponent = (obj) => {
628    const imageDataWrapper = document.createElement('div')
629    imageDataWrapper.className = 'converted-image-data'
630    const imageName = document.createElement('span')
631    imageName.className = 'converted-image-name'
632    const convertedSpan = document.createElement('span')
633    const reducedSpan = document.createElement('span')
634    const resSpan = document.createElement('span')
635
636    imageName.innerText = shortName
637    convertedSpan.innerHTML = `✅ <strong>Converted ${obj.fileFormat}</strong> to <span class="green inline"><strong>${obj.targetFormat}</strong></span>`
638    if (obj.savedPercentage <= 0) {
639        reducedSpan.innerHTML = `✅ <strong>${obj.sizeBefore}</strong> <img src="/static/images/arrow-right-new.svg" alt="Resize result" class="inline-block" loading="lazy"> <strong style="color: var(--btn-green)">${obj.sizeAfter}</strong>`
640    } else {
641        reducedSpan.innerHTML = `✅ <strong>${obj.sizeBefore}</strong> <img src="/static/images/arrow-right-new.svg" alt="Resize result" class="inline-block" loading="lazy"> <strong style="color: var(--btn-green)">${obj.sizeAfter} | Saved ${obj.savings} (${obj.savedPercentage}%)</strong>`
642    }
643
644    const resAfterUnknown = !obj.resAfter || obj.resAfter === 'N/A' || obj.resAfter === 'undefined'
645    if (!resAfterUnknown && obj.resBefore !== obj.resAfter) {
646        resSpan.innerHTML = `✅ <strong>${obj.resBefore}</strong> <img src="/static/images/arrow-right-new.svg" alt="Resize result" class="inline-block" loading="lazy"> <strong style="color: var(--btn-green)">${obj.resAfter}</strong>`
647    } else {
648        resSpan.innerHTML = `✅ <strong>${obj.resBefore}</strong>`
649    }
650
651    appendMultipleElements(
652        imageDataWrapper,
653        [
654            imageName,
655            convertedSpan,
656            reducedSpan,
657            resSpan
658        ]
659    )
660    return imageDataWrapper
661}
662
663
664const appendConvertedImage = (convertedImgObj) => {
665    const uploadedImageTemplate = uploadedImageTemplateComponent()
666    const thumbnailSrc = convertedImgObj.targetFormat === 'PDF' ? '/static/images/pdf-icon.png' : convertedImgObj.optimizedImg
667    const uploadedImageThumbnail = resizedImageThumbnailComponent(thumbnailSrc)
668    const imageContainer = imageContainerComponent()
669    const convertedImageData = convertedImageDataComponent(convertedImgObj)
670    const downloadBtnLink = downloadBtnWithIconComponent(convertedImgObj)
671    const compareLink = compareBtnWithIconComponent(convertedImgObj);
672    const successResultButtons = document.createElement('div')
673
674    buttonsPanel.className = 'buttons-panel'
675    successResultButtons.className = 'success-result-buttons-panel'
676
677    appendMultipleElements(
678        successResultButtons,
679        [
680            compareLink,
681            downloadBtnLink,
682        ]
683    )
684
685    appendMultipleElements(
686        resizedImageContainer,
687        [
688            uploadedImageTemplate,
689            successResultButtons,
690            buttonsPanel
691        ]
692    )
693
694    appendMultipleElements(
695        uploadedImageTemplate,
696        [
697            imageContainer,
698            convertedImageData,
699            successResultButtons
700        ]
701    )
702
703    appendToElement(imageContainer, uploadedImageThumbnail)
704
705    displayDefaultImage();
706    displayHEICImageThumbnail(convertedImgObj.originImg, uploadedImageThumbnail);
707}
708
709const appendUploadedImagesForPrinting = (Obj) => {
710    const imageData = uploadedImageData(shortName, uploadedImages[Obj.index])
711    const uploadedImageFormat = uploadedImageFormatComponent()
712    const convertFromFormat = document.createElement('span');
713    convertFromFormat.id = 'convert-from-id';
714    convertFromFormat.className = 'convert-from';
715
716    const deleteIcon = deleteIconComponent(uploadedImages, strings64BaseArray, Obj.index)
717
718    displayDefaultImage('uploaded-image');
719    displayHEICImageThumbnail(uploadedImages[Obj.index], imageData.imageThumbnail);
720    displayUploadedImagesResolutionAndSize(uploadedImages[Obj.index], '', Obj.widthIn, Obj.heightIn)
721    getAndDisplayUploadedImagesResolution(uploadedImages[Obj.index], convertFromFormat, imageWidth, imageHeight)
722
723    appendToElement(uploadedImageContainer, imageData.imageTemplate)
724    appendToElement(imageData.imageContainer, imageData.imageThumbnail)
725
726    appendMultipleElements(
727        imageData.imageTemplate,
728        [
729            imageData.imageContainer,
730            uploadedImageFormat,
731            deleteIcon,
732        ]
733    )
734
735    appendMultipleElements(
736        uploadedImageFormat,
737        [
738            imageData.imageName,
739            convertFromFormat,
740        ]
741    )
742}
743
744// append new action (compression/optimization) button
745const appendNewActionButton = (imageContainer, btnContent) => {
746    const newActionBtn = document.createElement('button')
747    newActionBtn.className = 'btn btn-outline-primary btn-outline-blue btn-large btn-outline-label btn-new-action'
748    newActionBtn.id = 'btn-new-action-id'
749    newActionBtn.innerText = btnContent
750    newActionBtn.setAttribute('type', 'button')
751    newActionBtn.addEventListener(TYPE_CLICK, pageReload)
752    imageContainer.appendChild(newActionBtn)
753}
754
755// append download merged images in ZIP button
756const appendDownloadMergedFilesButton = (uploadedFiles, imageContainer, url, downloadName) => {
757    if (uploadedFiles.length > 1) {
758        const downloadBtn = document.createElement('a')
759        downloadBtn.className = 'btn btn-blue btn-large btn-merged-download'
760        if (resizerJpUrls.includes(pageUrl)) {
761            downloadBtn.innerText = '画像をZIP形式でダウンロード'
762        } else {
763            downloadBtn.innerText = `Download Images in ${downloadName.split('.')[1].toUpperCase()}`
764        }
765        downloadBtn.setAttribute('href', url);
766        downloadBtn.setAttribute('download', downloadName);
767        downloadBtn.setAttribute('aria-label', 'Download optimized images in zipfile');
768        imageContainer.appendChild(downloadBtn)
769    }
770}
771
772// EXIF viewer / remover components
773const tableRowComponent = (exifName, exifValue) => {
774    const row = document.createElement('tr')
775    const colOne = document.createElement('th')
776    const colTwo = document.createElement('th')
777    const separator = document.createElement('td')
778    colOne.setAttribute('scope', 'col')
779    colTwo.setAttribute('scope', 'col')
780    colOne.innerText = `${exifName}`
781    colTwo.innerText = `${exifValue}`
782    colOne.style.fontWeight = 'bold'
783    appendMultipleElements(
784        row,
785        [
786            colOne,
787            separator,
788            colTwo
789        ]
790    )
791    return row
792}
793
794const uploadedImageEXIFDataComponent = (exifData) => {
795    const exifMetaData = document.createElement('div')
796    exifMetaData.className = 'exif-data-container'
797    appendToElement(exifMetaData, exifData)
798    return exifMetaData
799}
800
801const appendUploadedImagesEXIFComponent = (file, exifData) => {
802    const imageData = uploadedImageData(shortName, file)
803    const uploadedImageEXIF = uploadedImageEXIFDataComponent(exifData)
804    displayHEICImageThumbnail(file, imageData.imageThumbnail);
805    displayDefaultImage('uploaded-image')
806    appendToElement(uploadedImageContainer, imageData.imageTemplate)
807    appendToElement(imageData.imageContainer, imageData.imageThumbnail)
808    appendMultipleElements(
809        imageData.imageTemplate,
810        [
811            imageData.imageContainer,
812            uploadedImageEXIF
813        ]
814    )
815    imageData.imageTemplate.ondragstart = () => {
816        return false
817    }
818}
819
820// basic success image component
821const resizedImageTemplateComponent = () => {
822    const resizedImageTemplate = document.createElement('div');
823    resizedImageTemplate.className = 'uploaded-image-template display-image';
824    resizedImageTemplate.id = 'uploaded-image-template-id';
825    resizedImageTemplate.name = 'uploaded-image-template-name';
826    return resizedImageTemplate
827}
828
829const resizedImagesThumbnailComponent = (file) => {
830    const uploadedImageThumbnail = document.createElement('img');
831    uploadedImageThumbnail.className = 'uploaded-image display-image';
832    uploadedImageThumbnail.id = 'uploaded-image-id';
833    uploadedImageThumbnail.src = URL.createObjectURL(file);
834    uploadedImageThumbnail.alt = "Thumbnail"
835    return uploadedImageThumbnail
836}
837
838const appendResizedImages = (Obj) => {
839    const resizedImageTemplate = resizedImageTemplateComponent()
840    const uploadedImageThumbnail = resizedImagesThumbnailComponent(uploadedImages[Obj.index])
841    const imageContainer = imageContainerComponent()
842    const uploadedImageName = uploadedImageNameComponent(shortName)
843    const uploadedImageFormat = uploadedImageFormatComponent()
844    const downloadBtnLink = downloadBtnWithIconComponent(Obj)
845    const mobileDownloadLink = mobileDownloadLinkComponent(Obj.optimizedImg[Obj.index], Obj.fileName);
846    displayDefaultImage();
847    displayHEICImageThumbnail(uploadedImages[Obj.index], uploadedImageThumbnail);
848    buttonsPanel.className = 'buttons-panel'
849    appendMultipleElements(
850        resizedImageContainer,
851        [
852            resizedImageTemplate,
853            buttonsPanel
854        ]
855    )
856    appendToElement(imageContainer, uploadedImageThumbnail)
857    appendToElement(uploadedImageFormat, uploadedImageName)
858
859    appendMultipleElements(
860        resizedImageTemplate,
861        [
862            imageContainer,
863            uploadedImageFormat,
864            downloadBtnLink,
865            mobileDownloadLink,
866        ]
867    )
868}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.