diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a513a9c0e..ea5f3f07c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -128,7 +128,7 @@ jobs: sudo chmod +x /usr/local/bin/docker-compose - name: Set up Python - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 + uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: "3.12" cache: 'pip' # caching pip dependencies diff --git a/.github/workflows/check_properties.yml b/.github/workflows/check_properties.yml index 037a6284f..91bdcffae 100644 --- a/.github/workflows/check_properties.yml +++ b/.github/workflows/check_properties.yml @@ -26,7 +26,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Python - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 + uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: "3.12" diff --git a/.github/workflows/licenses-update.yml b/.github/workflows/licenses-update.yml index 96bdfd411..ee3c5ee7e 100644 --- a/.github/workflows/licenses-update.yml +++ b/.github/workflows/licenses-update.yml @@ -24,7 +24,7 @@ jobs: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@af35edadc00be37caa72ed9f3e6d5f7801bfdf09 # v1.11.7 + uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.0 with: app-id: ${{ secrets.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} @@ -38,7 +38,7 @@ jobs: java-version: "17" distribution: "adopt" - - uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0 + - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 - name: check the licenses for compatibility run: ./gradlew clean checkLicense diff --git a/.github/workflows/manage-label.yml b/.github/workflows/manage-label.yml index 3b2342e9b..0da55134a 100644 --- a/.github/workflows/manage-label.yml +++ b/.github/workflows/manage-label.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run Labeler - uses: crazy-max/ghaction-github-labeler@31674a3852a9074f2086abcf1c53839d466a47e7 # v5.2.0 + uses: crazy-max/ghaction-github-labeler@24d110aa46a59976b8a7f35518cb7f14f434c916 # v5.3.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} yaml-file: .github/labels.yml diff --git a/.github/workflows/multiOSReleases.yml b/.github/workflows/multiOSReleases.yml index 12c36510f..8d1577242 100644 --- a/.github/workflows/multiOSReleases.yml +++ b/.github/workflows/multiOSReleases.yml @@ -63,7 +63,7 @@ jobs: java-version: "21" distribution: "temurin" - - uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0 + - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 with: gradle-version: 8.12 @@ -151,7 +151,7 @@ jobs: java-version: "21" distribution: "temurin" - - uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0 + - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 with: gradle-version: 8.12 @@ -180,6 +180,7 @@ jobs: mv "./build/jpackage/Stirling-PDF-${{ needs.read_versions.outputs.version }}.exe" "./binaries/Stirling-PDF-win-installer.exe" elif [ "${{ matrix.os }}" = "macos-latest" ]; then mv "./build/jpackage/Stirling-PDF-${{ needs.read_versions.outputs.versionMac }}.dmg" "./binaries/Stirling-PDF-mac-installer.dmg" + mv "./build/jpackage/Stirling-PDF-x86_64-${{ needs.read_versions.outputs.versionMac }}.dmg" "./binaries/Stirling-PDF-mac-x86_64-installer.dmg" else mv "./build/jpackage/stirling-pdf_${{ needs.read_versions.outputs.version }}-1_amd64.deb" "./binaries/Stirling-PDF-linux-installer.deb" fi diff --git a/.github/workflows/pre_commit.yml b/.github/workflows/pre_commit.yml index f99e9bfc9..64d165378 100644 --- a/.github/workflows/pre_commit.yml +++ b/.github/workflows/pre_commit.yml @@ -22,7 +22,7 @@ jobs: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@af35edadc00be37caa72ed9f3e6d5f7801bfdf09 # v1.11.7 + uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.0 with: app-id: ${{ secrets.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} @@ -42,7 +42,7 @@ jobs: with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 + uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: 3.12 cache: 'pip' # caching pip dependencies diff --git a/.github/workflows/push-docker.yml b/.github/workflows/push-docker.yml index dfddd9b15..509ad1a9c 100644 --- a/.github/workflows/push-docker.yml +++ b/.github/workflows/push-docker.yml @@ -30,7 +30,7 @@ jobs: java-version: "17" distribution: "temurin" - - uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0 + - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 with: gradle-version: 8.12 diff --git a/.github/workflows/releaseArtifacts.yml b/.github/workflows/releaseArtifacts.yml index 6253b8eb0..735a3fb66 100644 --- a/.github/workflows/releaseArtifacts.yml +++ b/.github/workflows/releaseArtifacts.yml @@ -35,7 +35,7 @@ jobs: java-version: "17" distribution: "temurin" - - uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0 + - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 with: gradle-version: 8.12 diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml index 0925d94c7..a313cd753 100644 --- a/.github/workflows/sonarqube.yml +++ b/.github/workflows/sonarqube.yml @@ -27,7 +27,7 @@ jobs: fetch-depth: 0 - name: Setup Gradle - uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0 + uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 - name: Build and analyze with Gradle env: diff --git a/.github/workflows/swagger.yml b/.github/workflows/swagger.yml index 97ad11efc..c5405c1c5 100644 --- a/.github/workflows/swagger.yml +++ b/.github/workflows/swagger.yml @@ -26,7 +26,7 @@ jobs: java-version: "17" distribution: "temurin" - - uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0 + - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 - name: Generate Swagger documentation run: ./gradlew generateOpenApiDocs diff --git a/.github/workflows/sync_files.yml b/.github/workflows/sync_files.yml index 18158d3dd..e09f2e9ae 100644 --- a/.github/workflows/sync_files.yml +++ b/.github/workflows/sync_files.yml @@ -30,7 +30,7 @@ jobs: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@af35edadc00be37caa72ed9f3e6d5f7801bfdf09 # v1.11.7 + uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.0 with: app-id: ${{ secrets.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} @@ -63,7 +63,7 @@ jobs: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@af35edadc00be37caa72ed9f3e6d5f7801bfdf09 # v1.11.7 + uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.0 with: app-id: ${{ vars.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} @@ -71,7 +71,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Python - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 + uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 with: python-version: "3.12" cache: 'pip' # caching pip dependencies diff --git a/README.md b/README.md index 5aace9610..12a1a1271 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ Stirling-PDF currently supports 39 languages! | Portuguese (Português) (pt_PT) | ![93%](https://geps.dev/progress/93) | | Portuguese Brazilian (Português) (pt_BR) | ![96%](https://geps.dev/progress/96) | | Romanian (Română) (ro_RO) | ![77%](https://geps.dev/progress/77) | -| Russian (Русский) (ru_RU) | ![94%](https://geps.dev/progress/94) | +| Russian (Русский) (ru_RU) | ![96%](https://geps.dev/progress/96) | | Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![62%](https://geps.dev/progress/62) | | Simplified Chinese (简体中文) (zh_CN) | ![95%](https://geps.dev/progress/95) | | Slovakian (Slovensky) (sk_SK) | ![71%](https://geps.dev/progress/71) | @@ -154,7 +154,7 @@ Stirling-PDF currently supports 39 languages! | Tibetan (བོད་ཡིག་) (zh_BO) | ![91%](https://geps.dev/progress/91) | | Traditional Chinese (繁體中文) (zh_TW) | ![97%](https://geps.dev/progress/97) | | Turkish (Türkçe) (tr_TR) | ![79%](https://geps.dev/progress/79) | -| Ukrainian (Українська) (uk_UA) | ![97%](https://geps.dev/progress/97) | +| Ukrainian (Українська) (uk_UA) | ![99%](https://geps.dev/progress/99) | | Vietnamese (Tiếng Việt) (vi_VN) | ![76%](https://geps.dev/progress/76) | diff --git a/build.gradle b/build.gradle index 2c9e9f48f..382722ab1 100644 --- a/build.gradle +++ b/build.gradle @@ -9,19 +9,23 @@ plugins { id "com.github.jk1.dependency-license-report" version "2.9" //id "nebula.lint" version "19.0.3" id("org.panteleyev.jpackageplugin") version "1.6.1" - id "org.sonarqube" version "6.0.1.5171" + id "org.sonarqube" version "6.1.0.5360" } import com.github.jk1.license.render.* +import org.gradle.internal.os.OperatingSystem +import java.nio.file.Files +import java.time.Year ext { springBootVersion = "3.4.4" pdfboxVersion = "3.0.4" imageioVersion = "3.12.0" - lombokVersion = "1.18.36" + lombokVersion = "1.18.38" bouncycastleVersion = "1.80" springSecuritySamlVersion = "6.4.4" openSamlVersion = "4.3.2" + tempJrePath = null } group = "stirling.software" @@ -104,8 +108,8 @@ openApi { } //0.11.5 to 2024.11.5 -def getMacVersion(String version) { - def currentYear = java.time.Year.now().getValue() +static def getMacVersion(String version) { + def currentYear = Year.now().getValue() def versionParts = version.split("\\.", 2) return "${currentYear}.${versionParts.length > 1 ? versionParts[1] : versionParts[0]}" } @@ -116,6 +120,7 @@ jpackage { mainJar = "Stirling-PDF-${project.version}.jar" appName = "Stirling-PDF" appVersion = project.version +// appVersion = "2005.45.1" vendor = "Stirling-Software" appDescription = "Stirling PDF - Your Local PDF Editor" icon = "src/main/resources/static/favicon.ico" @@ -162,22 +167,22 @@ jpackage { icon = "src/main/resources/static/favicon.icns" type = "dmg" macPackageIdentifier = "com.stirling.software.pdf" - macPackageName = "Stirling-PDF" + macPackageName = "Stirling-PDF_aarch64" macAppCategory = "public.app-category.productivity" macSign = false // Enable signing macAppStore = false // Not targeting App Store initially - - //installDir = "Applications" - - // Add license and other documentation to DMG - /*macDmgContent = [ - "README.md", - "LICENSE", - "CHANGELOG.md" - ]*/ - - // Enable Mac-specific entitlements - //macEntitlements = "entitlements.plist" // You'll need to create this file +// +// //installDir = "Applications" +// +// // Add license and other documentation to DMG +// /*macDmgContent = [ +// "README.md", +// "LICENSE", +// "CHANGELOG.md" +// ]*/ +// +// // Enable Mac-specific entitlements +// //macEntitlements = "entitlements.plist" // You'll need to create this file } // Linux-specific configuration @@ -223,6 +228,107 @@ jpackage { licenseFile = "LICENSE" } +tasks.register('jpackageMacX64') { + group = 'distribution' + description = 'Packages app for MacOS x86_64' + + if (OperatingSystem.current().isMacOsX()) { + println "MacOS detected. Downloading temp JRE." + dependsOn("downloadTempJre") + } else { + return + } + + doLast { + def jrePath = project.ext.tempJrePath + + if (!jrePath) { + throw new GradleException("JRE path not found.") + } + + def outputStream = new ByteArrayOutputStream() + def errorStream = new ByteArrayOutputStream() + + def result = exec { + commandLine 'jpackage', + '--type', 'dmg', + '--name', 'Stirling-PDF-x86_64', + '--input', 'build/libs', + '--main-jar', "Stirling-PDF-${project.version}.jar", + '--main-class', 'stirling.software.SPDF.SPDFApplication', + '--runtime-image', file(jrePath + "/zulu-17.jre/Contents/Home"), + '--dest', 'build/jpackage', + '--icon', 'src/main/resources/static/favicon.icns', + '--app-version', getMacVersion(project.version.toString()), + '--mac-package-name', 'Stirling-PDF', + '--mac-package-identifier', 'com.stirling.software.pdf', + '--mac-app-category', 'public.app-category.productivity' + standardOutput = outputStream + errorOutput = errorStream + ignoreExitValue = true + } + + def stdout = outputStream.toString("UTF-8") + def stderr = errorStream.toString("UTF-8") + + if (!stdout.isBlank()) { + println "📝 jpackage stdout:\n$stdout" + } + + if (result.exitValue != 0) { + throw new GradleException("❌ jpackage failed with exit code ${result.exitValue}.\n\n$stderr") + } + } +} + +jpackage.finalizedBy(jpackageMacX64) + +tasks.register('downloadTempJre') { + group = 'distribution' + description = 'Downloads and extracts a temporary JRE' + + doLast { + try { + def jreUrl = 'https://cdn.azul.com/zulu/bin/zulu17.56.15-ca-jre17.0.14-macosx_x64.tar.gz' + def tmpDir = Files.createTempDirectory('zulu-jre').toFile() + def jreArchive = new File(tmpDir, 'jre.tar.gz') + def jreDir = new File(tmpDir, 'jre') + + println "🔽 Downloading JRE to $jreArchive..." + jreArchive.withOutputStream { out -> + new URI(jreUrl).toURL().withInputStream { from -> out << from } + } + + println "📦 Extracting JRE to $jreDir..." + jreDir.mkdirs() + providers.exec { + commandLine 'tar', '-xzf', jreArchive.absolutePath, '-C', jreDir.absolutePath, '--strip-components=1' + }.result.get() + + println "✅ JRE ready at: $jreDir" + ext.tempJrePath = jreDir.absolutePath + project.ext.tempJrePath = jreDir.absolutePath + } catch (Exception e) { + println "Failed to download JRE. ${e.getLocalizedMessage()}" + cleanTempJre + } + } +} + +tasks.register('cleanTempJre') { + dependsOn('jpackageMacX64') + group = 'distribution' + description = 'Deletes the temporary JRE' + + doLast { + def path = project.ext.tempJrePath + + if (path && new File("$path").exists()) { + println "🧹 Cleaning up temporary JRE: $path" + new File("$path").parentFile.deleteDir() + } + } +} launch4j { icon = "${projectDir}/src/main/resources/static/favicon.ico" @@ -330,13 +436,13 @@ dependencies { implementation "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion" implementation 'com.posthog.java:posthog:1.2.0' implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1' - + if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") { - + implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'io.micrometer:micrometer-registry-prometheus' - + implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion" implementation "org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.3.RELEASE" implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion" @@ -461,12 +567,12 @@ jar { attributes "Implementation-Title": "Stirling-PDF", "Implementation-Version": project.version } - } tasks.named("test") { useJUnitPlatform() } + task printVersion { doLast { println project.version diff --git a/src/main/java/stirling/software/SPDF/config/security/oauth2/OAuth2Configuration.java b/src/main/java/stirling/software/SPDF/config/security/oauth2/OAuth2Configuration.java index 4fe03c486..c43d8a606 100644 --- a/src/main/java/stirling/software/SPDF/config/security/oauth2/OAuth2Configuration.java +++ b/src/main/java/stirling/software/SPDF/config/security/oauth2/OAuth2Configuration.java @@ -186,7 +186,6 @@ public class OAuth2Configuration { oauth.getClientSecret(), oauth.getScopes(), UsernameAttribute.valueOf(oauth.getUseAsUsername().toUpperCase()), - oauth.getLogoutUrl(), null, null, null); diff --git a/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java b/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java index c70560e3f..a4b2cc962 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java @@ -122,7 +122,8 @@ public class OtherWebController { return Arrays.stream(files) .filter(file -> file.getName().endsWith(".traineddata")) .map(file -> file.getName().replace(".traineddata", "")) - .filter(lang -> !lang.equalsIgnoreCase("osd")).sorted() + .filter(lang -> !lang.equalsIgnoreCase("osd")) + .sorted() .toList(); } diff --git a/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java b/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java index 36f6f82b7..6956a28fc 100644 --- a/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java +++ b/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java @@ -230,7 +230,6 @@ public class ApplicationProperties { private Collection scopes = new ArrayList<>(); private String provider; private Client client = new Client(); - private String logoutUrl; public void setScopes(String scopes) { List scopesList = diff --git a/src/main/java/stirling/software/SPDF/model/provider/GitHubProvider.java b/src/main/java/stirling/software/SPDF/model/provider/GitHubProvider.java index 8d8aaf80c..7057ec903 100644 --- a/src/main/java/stirling/software/SPDF/model/provider/GitHubProvider.java +++ b/src/main/java/stirling/software/SPDF/model/provider/GitHubProvider.java @@ -29,7 +29,6 @@ public class GitHubProvider extends Provider { clientSecret, scopes, useAsUsername != null ? useAsUsername : UsernameAttribute.LOGIN, - null, AUTHORIZATION_URI, TOKEN_URI, USER_INFO_URI); diff --git a/src/main/java/stirling/software/SPDF/model/provider/GoogleProvider.java b/src/main/java/stirling/software/SPDF/model/provider/GoogleProvider.java index a8e65c61e..1bb217c9f 100644 --- a/src/main/java/stirling/software/SPDF/model/provider/GoogleProvider.java +++ b/src/main/java/stirling/software/SPDF/model/provider/GoogleProvider.java @@ -30,7 +30,6 @@ public class GoogleProvider extends Provider { clientSecret, scopes, useAsUsername, - null, AUTHORIZATION_URI, TOKEN_URI, USER_INFO_URI); diff --git a/src/main/java/stirling/software/SPDF/model/provider/KeycloakProvider.java b/src/main/java/stirling/software/SPDF/model/provider/KeycloakProvider.java index bf2725995..c01d27c20 100644 --- a/src/main/java/stirling/software/SPDF/model/provider/KeycloakProvider.java +++ b/src/main/java/stirling/software/SPDF/model/provider/KeycloakProvider.java @@ -29,7 +29,6 @@ public class KeycloakProvider extends Provider { useAsUsername, null, null, - null, null); } diff --git a/src/main/java/stirling/software/SPDF/model/provider/Provider.java b/src/main/java/stirling/software/SPDF/model/provider/Provider.java index da1d19f32..c15bc34a6 100644 --- a/src/main/java/stirling/software/SPDF/model/provider/Provider.java +++ b/src/main/java/stirling/software/SPDF/model/provider/Provider.java @@ -25,7 +25,6 @@ public class Provider { private String clientSecret; private Collection scopes; private UsernameAttribute useAsUsername; - private String logoutUrl; private String authorizationUri; private String tokenUri; private String userInfoUri; @@ -38,7 +37,6 @@ public class Provider { String clientSecret, Collection scopes, UsernameAttribute useAsUsername, - String logoutUrl, String authorizationUri, String tokenUri, String userInfoUri) { @@ -50,7 +48,6 @@ public class Provider { this.scopes = scopes == null ? new ArrayList<>() : scopes; this.useAsUsername = useAsUsername != null ? validateUsernameAttribute(useAsUsername) : EMAIL; - this.logoutUrl = logoutUrl; this.authorizationUri = authorizationUri; this.tokenUri = tokenUri; this.userInfoUri = userInfoUri; diff --git a/src/main/resources/messages_en_GB.properties b/src/main/resources/messages_en_GB.properties index 006e4e7a0..d63537403 100644 --- a/src/main/resources/messages_en_GB.properties +++ b/src/main/resources/messages_en_GB.properties @@ -83,6 +83,7 @@ loading=Loading... addToDoc=Add to Document reset=Reset apply=Apply +noFileSelected=No file selected. Please upload one. legal.privacy=Privacy Policy legal.terms=Terms and Conditions diff --git a/src/main/resources/messages_en_US.properties b/src/main/resources/messages_en_US.properties index 0c35d6c55..e56767c41 100644 --- a/src/main/resources/messages_en_US.properties +++ b/src/main/resources/messages_en_US.properties @@ -83,6 +83,7 @@ loading=Loading... addToDoc=Add to Document reset=Reset apply=Apply +noFileSelected=No file selected. Please upload one. legal.privacy=Privacy Policy legal.terms=Terms and Conditions diff --git a/src/main/resources/static/js/fileInput.js b/src/main/resources/static/js/fileInput.js index 7e89e6cc3..28331ef01 100644 --- a/src/main/resources/static/js/fileInput.js +++ b/src/main/resources/static/js/fileInput.js @@ -35,6 +35,7 @@ function setupFileInput(chooser) { const pdfPrompt = chooser.getAttribute('data-bs-pdf-prompt'); const inputContainerId = chooser.getAttribute('data-bs-element-container-id'); const showUploads = chooser.getAttribute('data-bs-show-uploads') === "true"; + const noFileSelectedPrompt = chooser.getAttribute('data-bs-no-file-selected'); let inputContainer = document.getElementById(inputContainerId); const input = document.getElementById(elementId); @@ -58,6 +59,12 @@ function setupFileInput(chooser) { inputBtn.click(); }); + // Handle form validation if the input is left empty + input.addEventListener("invalid", (e) => { + e.preventDefault(); + alert(noFileSelectedPrompt); + }); + const dragenterListener = function () { dragCounter++; if (!overlay) { diff --git a/src/main/resources/templates/fragments/common.html b/src/main/resources/templates/fragments/common.html index 66fa94b58..a407f60ee 100644 --- a/src/main/resources/templates/fragments/common.html +++ b/src/main/resources/templates/fragments/common.html @@ -228,7 +228,7 @@ loading: '[[#{loading}]]' };
+ th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-element-container-id=${name+'-input-container'}, data-bs-show-uploads=${showUploads}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}, data-bs-no-file-selected=#{noFileSelected}">