diff --git a/README.md b/README.md index 472398a8..d7fd1e29 100644 --- a/README.md +++ b/README.md @@ -134,14 +134,14 @@ Stirling-PDF currently supports 39 languages! | Hungarian (Magyar) (hu_HU) |  | | Indonesian (Bahasa Indonesia) (id_ID) |  | | Irish (Gaeilge) (ga_IE) |  | -| Italian (Italiano) (it_IT) |  | +| Italian (Italiano) (it_IT) |  | | Japanese (日本語) (ja_JP) |  | | Korean (한국어) (ko_KR) |  | | Norwegian (Norsk) (no_NB) |  | | Persian (فارسی) (fa_IR) |  | | Polish (Polski) (pl_PL) |  | | Portuguese (Português) (pt_PT) |  | -| Portuguese Brazilian (Português) (pt_BR) |  | +| Portuguese Brazilian (Português) (pt_BR) |  | | Romanian (Română) (ro_RO) |  | | Russian (Русский) (ru_RU) |  | | Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  | diff --git a/build.gradle b/build.gradle index 6a933caa..7176fef2 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ ext { } group = "stirling.software" -version = "0.45.5" +version = "0.45.6" java { // 17 is lowest but we support and recommend 21 @@ -518,7 +518,7 @@ dependencies { implementation "org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion" implementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion" implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" - implementation "io.micrometer:micrometer-core:1.14.5" + implementation "io.micrometer:micrometer-core:1.14.6" implementation group: "com.google.zxing", name: "core", version: "3.5.3" // https://mvnrepository.com/artifact/org.commonmark/commonmark implementation "org.commonmark:commonmark:0.24.0" diff --git a/src/main/java/stirling/software/SPDF/config/AppConfig.java b/src/main/java/stirling/software/SPDF/config/AppConfig.java index 146f9762..1c850b2d 100644 --- a/src/main/java/stirling/software/SPDF/config/AppConfig.java +++ b/src/main/java/stirling/software/SPDF/config/AppConfig.java @@ -109,33 +109,6 @@ public class AppConfig { return (rateLimit != null) ? Boolean.valueOf(rateLimit) : false; } - @Bean(name = "uploadLimit") - public long uploadLimit() { - String maxUploadSize = - applicationProperties.getSystem().getFileUploadLimit() != null - ? applicationProperties.getSystem().getFileUploadLimit() - : ""; - - if (maxUploadSize.isEmpty()) { - return 0; - } else if (!new Regex("^[1-9][0-9]{0,2}[KMGkmg][Bb]$").matches(maxUploadSize)) { - log.error( - "Invalid maxUploadSize format. Expected format: [1-9][0-9]{0,2}[KMGkmg][Bb], but got: {}", - maxUploadSize); - return 0; - } else { - String unit = maxUploadSize.replaceAll("[1-9][0-9]{0,2}", "").toUpperCase(); - String number = maxUploadSize.replaceAll("[KMGkmg][Bb]", ""); - long size = Long.parseLong(number); - return switch (unit) { - case "KB" -> size * 1024; - case "MB" -> size * 1024 * 1024; - case "GB" -> size * 1024 * 1024 * 1024; - default -> 0; - }; - } - } - @Bean(name = "RunningInDocker") public boolean runningInDocker() { return Files.exists(Paths.get("/.dockerenv")); diff --git a/src/main/java/stirling/software/SPDF/controller/web/GlobalUploadLimitWebController.java b/src/main/java/stirling/software/SPDF/controller/web/GlobalUploadLimitWebController.java deleted file mode 100644 index 1c8b2b3a..00000000 --- a/src/main/java/stirling/software/SPDF/controller/web/GlobalUploadLimitWebController.java +++ /dev/null @@ -1,30 +0,0 @@ -package stirling.software.SPDF.controller.web; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ModelAttribute; - -@Component -@ControllerAdvice -public class GlobalUploadLimitWebController { - - @Autowired() private long uploadLimit; - - @ModelAttribute("uploadLimit") - public long populateUploadLimit() { - return uploadLimit; - } - - @ModelAttribute("uploadLimitReadable") - public String populateReadableLimit() { - return humanReadableByteCount(uploadLimit); - } - - private String humanReadableByteCount(long bytes) { - if (bytes < 1024) return bytes + " B"; - int exp = (int) (Math.log(bytes) / Math.log(1024)); - String pre = "KMGTPE".charAt(exp - 1) + "B"; - return String.format("%.1f %s", bytes / Math.pow(1024, exp), pre); - } -} diff --git a/src/main/java/stirling/software/SPDF/controller/web/UploadLimitService.java b/src/main/java/stirling/software/SPDF/controller/web/UploadLimitService.java new file mode 100644 index 00000000..c1c9aebc --- /dev/null +++ b/src/main/java/stirling/software/SPDF/controller/web/UploadLimitService.java @@ -0,0 +1,55 @@ +package stirling.software.SPDF.controller.web; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import lombok.extern.slf4j.Slf4j; +import stirling.software.SPDF.model.ApplicationProperties; + +import java.util.regex.Pattern; + +@Service +@Slf4j +public class UploadLimitService { + + @Autowired + private ApplicationProperties applicationProperties; + + public long getUploadLimit() { + String maxUploadSize = + applicationProperties.getSystem().getFileUploadLimit() != null + ? applicationProperties.getSystem().getFileUploadLimit() + : ""; + + if (maxUploadSize.isEmpty()) { + return 0; + } else if (!Pattern.compile("^[1-9][0-9]{0,2}[KMGkmg][Bb]$").matcher(maxUploadSize).matches()) { + log.error( + "Invalid maxUploadSize format. Expected format: [1-9][0-9]{0,2}[KMGkmg][Bb], but got: {}", + maxUploadSize); + return 0; + } else { + String unit = maxUploadSize.replaceAll("[1-9][0-9]{0,2}", "").toUpperCase(); + String number = maxUploadSize.replaceAll("[KMGkmg][Bb]", ""); + long size = Long.parseLong(number); + return switch (unit) { + case "KB" -> size * 1024; + case "MB" -> size * 1024 * 1024; + case "GB" -> size * 1024 * 1024 * 1024; + default -> 0; + }; + } + } + + //TODO: why do this server side not client? + public String getReadableUploadLimit() { + return humanReadableByteCount(getUploadLimit()); + } + + private String humanReadableByteCount(long bytes) { + if (bytes < 1024) return bytes + " B"; + int exp = (int) (Math.log(bytes) / Math.log(1024)); + String pre = "KMGTPE".charAt(exp - 1) + "B"; + return String.format("%.1f %s", bytes / Math.pow(1024, exp), pre); + } +} \ No newline at end of file diff --git a/src/main/resources/messages_it_IT.properties b/src/main/resources/messages_it_IT.properties index 62b8b096..30368524 100644 --- a/src/main/resources/messages_it_IT.properties +++ b/src/main/resources/messages_it_IT.properties @@ -10,9 +10,9 @@ multiPdfPrompt=Scegli 2 o più PDF multiPdfDropPrompt=Scegli (o trascina e rilascia) uno o più PDF imgPrompt=Scegli immagine/i genericSubmit=Invia -uploadLimit=Maximum file size: -uploadLimitExceededSingular=is too large. Maximum allowed size is -uploadLimitExceededPlural=are too large. Maximum allowed size is +uploadLimit=Dimensione massima del file: +uploadLimitExceededSingular=è troppo grande. La dimensione massima consentita è +uploadLimitExceededPlural=sono troppo grandi. La dimensione massima consentita è processTimeWarning=Nota: Questo processo potrebbe richiedere fino a un minuto in base alla dimensione dei file pageOrderPrompt=Ordine delle pagine (inserisci una lista di numeri separati da virgola): pageSelectionPrompt=Selezione pagina personalizzata (inserisci un elenco separato da virgole di numeri di pagina 1,5,6 o funzioni come 2n+1) : @@ -93,7 +93,7 @@ legal.terms=Termini e Condizioni legal.accessibility=Accessibilità legal.cookie=Informativa sui cookie legal.impressum=Informazioni legali -legal.showCookieBanner=Cookie Preferences +legal.showCookieBanner=Preferenze sui cookie ############### # Pipeline # diff --git a/src/main/resources/messages_pt_BR.properties b/src/main/resources/messages_pt_BR.properties index 683e3b0e..c6bbddb3 100644 --- a/src/main/resources/messages_pt_BR.properties +++ b/src/main/resources/messages_pt_BR.properties @@ -10,9 +10,9 @@ multiPdfPrompt=Selecione os PDFs (2+) multiPdfDropPrompt=Selecione (ou arraste e solte) todos os PDFs desejados: imgPrompt=Selecione a(s) Imagem(ns) genericSubmit=Enviar -uploadLimit=Maximum file size: -uploadLimitExceededSingular=is too large. Maximum allowed size is -uploadLimitExceededPlural=are too large. Maximum allowed size is +uploadLimit=Tamanho máximo do arquivo: +uploadLimitExceededSingular=está acima do limite. Tamanho máximo permitido é +uploadLimitExceededPlural=estão acima do limite. Tamanho máximo permitido é processTimeWarning=Aviso: Este processo pode levar até um minuto, dependendo do tamanho do arquivo pageOrderPrompt=Ordem de Página Personalizada (Digite uma lista de números de páginas, separadas por vírgula ou funções como 2n+1): pageSelectionPrompt=Seleção de Página Personalizada (Digite uma lista de números de páginas, separadas por vírgula como 1,5,6 ou funções como 2n+1): @@ -86,14 +86,14 @@ loading=Carregando... addToDoc=Adicionar ao Documento reset=Reiniciar apply=Aplicar -noFileSelected=No file selected. Please upload one. +noFileSelected=Nenhum arquivo selecionado. Por favo, envie um arquivo. legal.privacy=Política de Privacidade legal.terms=Termos e Condições legal.accessibility=Acessibilidade legal.cookie=Política de Cookies legal.impressum=Informações legais -legal.showCookieBanner=Cookie Preferences +legal.showCookieBanner=Preferências de Cookies ############### # Pipeline # @@ -237,31 +237,31 @@ adminUserSettings.activeUsers=Usuários Ativos: adminUserSettings.disabledUsers=Usuários Desabilitados: adminUserSettings.totalUsers=Total de Usuários: adminUserSettings.lastRequest=Última solicitação -adminUserSettings.usage=View Usage +adminUserSettings.usage=Ver Utilização -endpointStatistics.title=Endpoint Statistics -endpointStatistics.header=Endpoint Statistics +endpointStatistics.title=Estatísticas de Endpoints +endpointStatistics.header=Estatísticas de Endpoints endpointStatistics.top10=Top 10 endpointStatistics.top20=Top 20 -endpointStatistics.all=All -endpointStatistics.refresh=Refresh -endpointStatistics.includeHomepage=Include Homepage ('/') -endpointStatistics.includeLoginPage=Include Login Page ('/login') -endpointStatistics.totalEndpoints=Total Endpoints -endpointStatistics.totalVisits=Total Visits -endpointStatistics.showing=Showing -endpointStatistics.selectedVisits=Selected Visits +endpointStatistics.all=Todos +endpointStatistics.refresh=Atualizar +endpointStatistics.includeHomepage=Incluir Página Inicial ('/') +endpointStatistics.includeLoginPage=Incluir Página de Login ('/login') +endpointStatistics.totalEndpoints=Total de Endpoints +endpointStatistics.totalVisits=Total de Visitas +endpointStatistics.showing=Mostrando +endpointStatistics.selectedVisits=Visitas Selecionadas endpointStatistics.endpoint=Endpoint -endpointStatistics.visits=Visits -endpointStatistics.percentage=Percentage -endpointStatistics.loading=Loading... -endpointStatistics.failedToLoad=Failed to load endpoint data. Please try refreshing. +endpointStatistics.visits=Visitas +endpointStatistics.percentage=Percentagem +endpointStatistics.loading=Carregando... +endpointStatistics.failedToLoad=Falha ao carregar dados do Endpoint. Por favor, tente atualizar. endpointStatistics.home=Home endpointStatistics.login=Login endpointStatistics.top=Top -endpointStatistics.numberOfVisits=Number of Visits -endpointStatistics.visitsTooltip=Visits: {0} ({1}% of total) -endpointStatistics.retry=Retry +endpointStatistics.numberOfVisits=Número de Visitas +endpointStatistics.visitsTooltip=Visitas: {0} ({1}% do total) +endpointStatistics.retry=Tentar novamente database.title=Importar/Exportar banco de dados database.header=Importar/Exportar banco de dados @@ -739,10 +739,10 @@ sanitizePDF.title=Higienizar sanitizePDF.header=Higienizar sanitizePDF.selectText.1=Remover scripts de JavaScript. sanitizePDF.selectText.2=Remover arquivos embutidos. -sanitizePDF.selectText.3=Remove XMP metadata +sanitizePDF.selectText.3=Remover metadados XMP. sanitizePDF.selectText.4=Remover links. sanitizePDF.selectText.5=Remover fontes. -sanitizePDF.selectText.6=Remove Document Info Metadata +sanitizePDF.selectText.6=Remover metadados de informações do documento. sanitizePDF.submit=Higienizar PDF @@ -1408,25 +1408,25 @@ validateSignature.cert.bits=bits #################### # Cookie banner # #################### -cookieBanner.popUp.title=How we use Cookies -cookieBanner.popUp.description.1=We use cookies and other technologies to make Stirling PDF work better for you—helping us improve our tools and keep building features you'll love. -cookieBanner.popUp.description.2=If you’d rather not, clicking 'No Thanks' will only enable the essential cookies needed to keep things running smoothly. -cookieBanner.popUp.acceptAllBtn=Okay -cookieBanner.popUp.acceptNecessaryBtn=No Thanks -cookieBanner.popUp.showPreferencesBtn=Manage preferences -cookieBanner.preferencesModal.title=Consent Preferences Center -cookieBanner.preferencesModal.acceptAllBtn=Accept all -cookieBanner.preferencesModal.acceptNecessaryBtn=Reject all -cookieBanner.preferencesModal.savePreferencesBtn=Save preferences -cookieBanner.preferencesModal.closeIconLabel=Close modal -cookieBanner.preferencesModal.serviceCounterLabel=Service|Services -cookieBanner.preferencesModal.subtitle=Cookie Usage -cookieBanner.preferencesModal.description.1=Stirling PDF uses cookies and similar technologies to enhance your experience and understand how our tools are used. This helps us improve performance, develop the features you care about, and provide ongoing support to our users. -cookieBanner.preferencesModal.description.2=Stirling PDF cannot—and will never—track or access the content of the documents you use. -cookieBanner.preferencesModal.description.3=Your privacy and trust are at the core of what we do. -cookieBanner.preferencesModal.necessary.title.1=Strictly Necessary Cookies -cookieBanner.preferencesModal.necessary.title.2=Always Enabled -cookieBanner.preferencesModal.necessary.description=These cookies are essential for the website to function properly. They enable core features like setting your privacy preferences, logging in, and filling out forms—which is why they can’t be turned off. -cookieBanner.preferencesModal.analytics.title=Analytics -cookieBanner.preferencesModal.analytics.description=These cookies help us understand how our tools are being used, so we can focus on building the features our community values most. Rest assured—Stirling PDF cannot and will never track the content of the documents you work with. +cookieBanner.popUp.title=Como nós utilizamos Cookies: +cookieBanner.popUp.description.1=Nós utilizamos cookies e outras tecnologias para melhorar o Stirling PDF, ajude-nos para que possamos desenvolver novas funcionalidades que você irá amar. +cookieBanner.popUp.description.2=Se você não tiver interesse, clicando em "Não, Obrigado" será habilitado apenas cookies essenciais, para o site funcionar sem problemas. +cookieBanner.popUp.acceptAllBtn=Aceito +cookieBanner.popUp.acceptNecessaryBtn=Não, Obrigado +cookieBanner.popUp.showPreferencesBtn=Gerenciar Preferências +cookieBanner.preferencesModal.title=Central de Preferências de Consentimento +cookieBanner.preferencesModal.acceptAllBtn=Aceitar tudo +cookieBanner.preferencesModal.acceptNecessaryBtn=Rejeitar tudo +cookieBanner.preferencesModal.savePreferencesBtn=Salvar preferências +cookieBanner.preferencesModal.closeIconLabel=Fechar janela +cookieBanner.preferencesModal.serviceCounterLabel=Serviço|Serviços +cookieBanner.preferencesModal.subtitle=Uso de Cookies +cookieBanner.preferencesModal.description.1=Stirling PDF utiliza cookies e tecnologias semelhantes para aprimorar sua experiência e entender como nossas ferramentas são utilizadas. Isso nos ajuda a melhorar o desempenho, desenvolver os recursos de seu interesse e fornecer suporte contínuo aos nossos usuários. +cookieBanner.preferencesModal.description.2=O Stirling PDF não pode – e nunca irá – rastrear ou acessar o conteúdo dos documentos que você manipula. +cookieBanner.preferencesModal.description.3=Sua privacidade e confiança são prioridades para nós. +cookieBanner.preferencesModal.necessary.title.1=Cookies Estritamente Necessários +cookieBanner.preferencesModal.necessary.title.2=Sempre Ativado +cookieBanner.preferencesModal.necessary.description=Estes cookies são essenciais para o bom funcionamento do site. Eles habilitam recursos básicos como definir suas preferências de privacidade, realizar login e preencher formulários – e é por isso que não podem ser desativados. +cookieBanner.preferencesModal.analytics.title=Cookies Analíticos +cookieBanner.preferencesModal.analytics.description=Estes cookies nos ajudam a entender como nossas ferramentas estão sendo utilizadas, para que possamos nos concentrar na construção dos recursos que nossa comunidade mais valoriza. Fique tranquilo: o Stirling PDF não pode e nunca rastreará o conteúdo dos documentos com os quais você manipula. diff --git a/src/main/resources/static/3rdPartyLicenses.json b/src/main/resources/static/3rdPartyLicenses.json index e76bca57..8d07e610 100644 --- a/src/main/resources/static/3rdPartyLicenses.json +++ b/src/main/resources/static/3rdPartyLicenses.json @@ -553,7 +553,7 @@ { "moduleName": "io.micrometer:micrometer-core", "moduleUrl": "https://github.com/micrometer-metrics/micrometer", - "moduleVersion": "1.14.5", + "moduleVersion": "1.14.6", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, diff --git a/src/main/resources/static/js/downloader.js b/src/main/resources/static/js/downloader.js index 3b325b59..7bdcd83d 100644 --- a/src/main/resources/static/js/downloader.js +++ b/src/main/resources/static/js/downloader.js @@ -132,7 +132,9 @@ } } catch (error) { clearTimeout(timeoutId); - showGameBtn.style.display = 'none'; + if(showGameBtn){ + showGameBtn.style.display = 'none'; + } submitButton.textContent = originalButtonText; submitButton.disabled = false; handleDownloadError(error); diff --git a/src/main/resources/static/js/fileInput.js b/src/main/resources/static/js/fileInput.js index a67ff1fd..b24563c0 100644 --- a/src/main/resources/static/js/fileInput.js +++ b/src/main/resources/static/js/fileInput.js @@ -170,7 +170,7 @@ function setupFileInput(chooser) { inputContainer.querySelector('#fileInputText').innerHTML = window.fileInput.loading; async function checkZipFile() { - const hasZipFiles = allFiles.some(file => zipTypes.includes(file.type)); + const hasZipFiles = allFiles.some(file => file.type && zipTypes.includes(file.type)); // Only change to extractPDF message if we actually have zip files if (hasZipFiles) { diff --git a/src/main/resources/static/js/homecard-legacy.js b/src/main/resources/static/js/homecard-legacy.js index 02789efd..a43453f1 100644 --- a/src/main/resources/static/js/homecard-legacy.js +++ b/src/main/resources/static/js/homecard-legacy.js @@ -255,5 +255,12 @@ document.addEventListener('DOMContentLoaded', function () { }); }, 500); + Array.from(document.querySelectorAll('.feature-group-header')).forEach((header) => { + const parent = header.parentNode; + header.onclick = () => { + expandCollapseToggle(parent); + }; + }); + showFavoritesOnly(); }); diff --git a/src/main/resources/static/js/homecard.js b/src/main/resources/static/js/homecard.js index 33d49a78..8f5a92f0 100644 --- a/src/main/resources/static/js/homecard.js +++ b/src/main/resources/static/js/homecard.js @@ -241,10 +241,5 @@ document.addEventListener('DOMContentLoaded', async function () { console.error('Material Symbols Rounded font failed to load.'); }); - Array.from(document.querySelectorAll('.feature-group-header')).forEach((header) => { - const parent = header.parentNode; - header.onclick = () => { - expandCollapseToggle(parent); - }; - }); + }); diff --git a/src/main/resources/static/js/languageSelection.js b/src/main/resources/static/js/languageSelection.js index 2c7e0406..7d4b8bc0 100644 --- a/src/main/resources/static/js/languageSelection.js +++ b/src/main/resources/static/js/languageSelection.js @@ -57,11 +57,15 @@ function initLanguageSettings() { function sortLanguageDropdown() { document.addEventListener('DOMContentLoaded', function () { - const dropdownMenu = document.querySelector('.dropdown-menu .dropdown-item.lang_dropdown-item').parentElement; + const dropdownMenu = document.getElementById('languageSelection'); if (dropdownMenu) { - const items = Array.from(dropdownMenu.children).filter((child) => child.matches('a')); + const items = Array.from(dropdownMenu.children).filter((child) => child.querySelector('a')); items - .sort((a, b) => a.dataset.bsLanguageCode.localeCompare(b.dataset.bsLanguageCode)) + .sort((wrapperA, wrapperB) => { + const a = wrapperA.querySelector('a'); + const b = wrapperB.querySelector('a'); + return a.dataset.bsLanguageCode.localeCompare(b.dataset.bsLanguageCode); + }) .forEach((node) => dropdownMenu.appendChild(node)); } }); diff --git a/src/main/resources/static/js/multitool/commands/delete-page.js b/src/main/resources/static/js/multitool/commands/delete-page.js index 89fbe8a2..751b115e 100644 --- a/src/main/resources/static/js/multitool/commands/delete-page.js +++ b/src/main/resources/static/js/multitool/commands/delete-page.js @@ -21,12 +21,10 @@ export class DeletePageCommand extends Command { this.pagesContainer.removeChild(this.element); if (this.pagesContainer.childElementCount === 0) { const filenameInput = document.getElementById("filename-input"); - const filenameParagraph = document.getElementById("filename"); const downloadBtn = document.getElementById("export-button"); filenameInput.disabled = true; filenameInput.value = ""; - filenameParagraph.innerText = ""; downloadBtn.disabled = true; } @@ -43,13 +41,10 @@ export class DeletePageCommand extends Command { } const filenameInput = document.getElementById("filename-input"); - const filenameParagraph = document.getElementById("filename"); const downloadBtn = document.getElementById("export-button"); filenameInput.disabled = false; filenameInput.value = this.filenameInputValue; - if (this.filenameParagraph) - filenameParagraph.innerText = this.filenameParagraphText; downloadBtn.disabled = false; } @@ -63,12 +58,10 @@ export class DeletePageCommand extends Command { this.pagesContainer.removeChild(this.element); if (this.pagesContainer.childElementCount === 0) { const filenameInput = document.getElementById("filename-input"); - const filenameParagraph = document.getElementById("filename"); const downloadBtn = document.getElementById("export-button"); filenameInput.disabled = true; filenameInput.value = ""; - filenameParagraph.innerText = ""; downloadBtn.disabled = true; } diff --git a/src/main/resources/static/js/pages/home.js b/src/main/resources/static/js/pages/home.js index 8565c44a..7872374e 100644 --- a/src/main/resources/static/js/pages/home.js +++ b/src/main/resources/static/js/pages/home.js @@ -112,10 +112,10 @@ function setAsDefault(value) { function adjustVisibleElements() { const container = document.querySelector('.recent-features'); + if(!container) return; const subElements = Array.from(container.children); let totalWidth = 0; - const containerWidth = container.offsetWidth; subElements.forEach((element) => { totalWidth += 12 * parseFloat(getComputedStyle(document.documentElement).fontSize); diff --git a/src/main/resources/static/js/sign/signature-canvas.js b/src/main/resources/static/js/sign/signature-canvas.js index bd06e845..a3f7b1e9 100644 --- a/src/main/resources/static/js/sign/signature-canvas.js +++ b/src/main/resources/static/js/sign/signature-canvas.js @@ -26,7 +26,6 @@ window.addEventListener("keydown", (event) => { function undoDraw() { const data = signaturePad.toData(); - if (data && data.length > 0) { const removed = data.pop(); undoData.push(removed); @@ -35,7 +34,6 @@ function undoDraw() { } function redoDraw() { - if (undoData.length > 0) { const data = signaturePad.toData(); data.push(undoData.pop()); @@ -52,24 +50,18 @@ function addDraggableFromPad() { } function getCroppedCanvasDataUrl(canvas) { - let originalCtx = canvas.getContext('2d'); + let originalCtx = canvas.getContext('2d', { willReadFrequently: true }); let originalWidth = canvas.width; let originalHeight = canvas.height; let imageData = originalCtx.getImageData(0, 0, originalWidth, originalHeight); - let minX = originalWidth + 1, - maxX = -1, - minY = originalHeight + 1, - maxY = -1, - x = 0, - y = 0, - currentPixelColorValueIndex; + let minX = originalWidth + 1, maxX = -1, minY = originalHeight + 1, maxY = -1; - for (y = 0; y < originalHeight; y++) { - for (x = 0; x < originalWidth; x++) { - currentPixelColorValueIndex = (y * originalWidth + x) * 4; - let currentPixelAlphaValue = imageData.data[currentPixelColorValueIndex + 3]; - if (currentPixelAlphaValue > 0) { + for (let y = 0; y < originalHeight; y++) { + for (let x = 0; x < originalWidth; x++) { + let idx = (y * originalWidth + x) * 4; + let alpha = imageData.data[idx + 3]; + if (alpha > 0) { if (minX > x) minX = x; if (maxX < x) maxX = x; if (minY > y) minY = y; @@ -81,14 +73,14 @@ function getCroppedCanvasDataUrl(canvas) { let croppedWidth = maxX - minX; let croppedHeight = maxY - minY; if (croppedWidth < 0 || croppedHeight < 0) return null; - let cuttedImageData = originalCtx.getImageData(minX, minY, croppedWidth, croppedHeight); + let cutImageData = originalCtx.getImageData(minX, minY, croppedWidth, croppedHeight); - let croppedCanvas = document.createElement('canvas'), - croppedCtx = croppedCanvas.getContext('2d'); + let croppedCanvas = document.createElement('canvas'); + let croppedCtx = croppedCanvas.getContext('2d'); croppedCanvas.width = croppedWidth; croppedCanvas.height = croppedHeight; - croppedCtx.putImageData(cuttedImageData, 0, 0); + croppedCtx.putImageData(cutImageData, 0, 0); return croppedCanvas.toDataURL(); } @@ -114,10 +106,20 @@ function resizeCanvas() { signaturePad.clear(); } -new IntersectionObserver((entries, observer) => { +const debounce = (fn, delay = 100) => { + let timer; + return (...args) => { + clearTimeout(timer); + timer = setTimeout(() => fn(...args), delay); + }; +}; + +const debouncedResize = debounce(resizeCanvas, 200); + +new IntersectionObserver((entries) => { if (entries.some((entry) => entry.intersectionRatio > 0)) { - resizeCanvas(); + debouncedResize(); } }).observe(signaturePadCanvas); -new ResizeObserver(resizeCanvas).observe(signaturePadCanvas); +new ResizeObserver(debouncedResize).observe(signaturePadCanvas); diff --git a/src/main/resources/templates/fragments/common.html b/src/main/resources/templates/fragments/common.html index b8211481..7fd26c77 100644 --- a/src/main/resources/templates/fragments/common.html +++ b/src/main/resources/templates/fragments/common.html @@ -240,8 +240,8 @@ window.stirlingPDF.sessionExpired = /*[[#{session.expired}]]*/ ''; window.stirlingPDF.refreshPage = /*[[#{session.refreshPage}]]*/ 'Refresh Page'; window.stirlingPDF.error = /*[[#{error}]]*/ "Error"; - window.stirlingPDF.uploadLimit = /*[[${uploadLimit}]]*/ 0; - window.stirlingPDF.uploadLimitReadable = /*[[${uploadLimitReadable}]]*/ 'Unlimited'; + window.stirlingPDF.uploadLimitReadable = /*[[${@uploadLimitService.getReadableUploadLimit()}]]*/ 'Unlimited'; + window.stirlingPDF.uploadLimit = /*[[${@uploadLimitService.getUploadLimit()}]]*/ 0; window.stirlingPDF.uploadLimitExceededSingular = /*[[#{uploadLimitExceededSingular}]]*/ 'is too large. Maximum allowed size is'; window.stirlingPDF.uploadLimitExceededPlural = /*[[#{uploadLimitExceededPlural}]]*/ 'are too large. Maximum allowed size is'; })(); @@ -292,10 +292,10 @@
-