Compare commits

..

9 Commits

Author SHA1 Message Date
Anthony Stirling
597e57c009 Merge branch 'main' into languages 2024-02-11 10:27:55 +00:00
Ludy87
0011947c60 add placeholder translation 2024-02-11 01:03:08 +01:00
Ludy87
369b3a7ba6 add separator 2024-02-11 01:02:09 +01:00
Ludy87
dfa6dccee1 remove dublicate -> change showJS.tags to autoRedact.tags 2024-02-10 18:59:36 +01:00
Ludy87
c94e5f3e55 added missing strings 2024-02-10 11:56:42 +01:00
Ludy87
171b603abe Update messages_de_DE.properties 2024-02-09 23:55:42 +01:00
Ludy87
671f2cd361 Update messages_de_DE.properties 2024-02-09 23:42:04 +01:00
Ludy87
c90bad8f35 double spaces removed 2024-02-09 23:41:46 +01:00
Ludy87
b229222f45 Removed unnecessary characters and added DE missing strings 2024-02-09 23:20:47 +01:00
206 changed files with 10860 additions and 10638 deletions

View File

@@ -1,5 +1,2 @@
# Formatting
5f771b785130154ed47952635b7acef371ffe0ec
# Normalize files
55d4fda01b2f39f5b7d7b4fda5214bd7ff0fd5dd
5f771b785130154ed47952635b7acef371ffe0ec

View File

@@ -3,7 +3,7 @@ name: Push Docker Image with VersionNumber
on:
workflow_dispatch:
push:
branches:
branches:
- master
- main
permissions:
@@ -15,13 +15,13 @@ jobs:
steps:
- uses: actions/checkout@v3.5.2
- name: Set up JDK 17
uses: actions/setup-java@v3.11.0
with:
java-version: '17'
distribution: 'temurin'
- uses: gradle/gradle-build-action@v2.4.2
env:
@@ -32,11 +32,11 @@ jobs:
- name: Make Gradle wrapper executable
run: chmod +x gradlew
- name: Get version number
id: versionNumber
run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)"
- name: Login to Docker Hub
uses: docker/login-action@v2.1.0
with:
@@ -53,7 +53,7 @@ jobs:
- name: Convert repository owner to lowercase
id: repoowner
run: echo "::set-output name=lowercase::$(echo ${{ github.repository_owner }} | awk '{print tolower($0)}')"
- name: Generate tags
id: meta
uses: docker/metadata-action@v4.4.0
@@ -82,7 +82,7 @@ jobs:
cache-to: type=gha,mode=max
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args:
build-args:
VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
platforms: linux/amd64,linux/arm64/v8
@@ -99,7 +99,7 @@ jobs:
tags: |
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
type=raw,value=latest-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
- name: Build and push Dockerfile-ultra-lite
uses: docker/build-push-action@v4.0.0
@@ -112,7 +112,7 @@ jobs:
cache-to: type=gha,mode=max
tags: ${{ steps.meta2.outputs.tags }}
labels: ${{ steps.meta2.outputs.labels }}
build-args:
build-args:
VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
platforms: linux/amd64,linux/arm64/v8
@@ -129,7 +129,7 @@ jobs:
tags: |
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-lite,enable=${{ github.ref == 'refs/heads/master' }}
type=raw,value=latest-lite,enable=${{ github.ref == 'refs/heads/master' }}
- name: Build and push Dockerfile-lite
uses: docker/build-push-action@v4.0.0
@@ -142,7 +142,7 @@ jobs:
cache-to: type=gha,mode=max
tags: ${{ steps.meta3.outputs.tags }}
labels: ${{ steps.meta3.outputs.labels }}
build-args:
build-args:
VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
platforms: linux/amd64,linux/arm64/v8
- name: Build and Push Helm Chart

View File

@@ -1,7 +1,7 @@
name: Release Artifacts
on:
release:
on:
release:
types: [created]
permissions:
contents: write
@@ -19,13 +19,13 @@ jobs:
file_suffix: ''
steps:
- uses: actions/checkout@v3.5.2
- name: Set up JDK 17
uses: actions/setup-java@v3.11.0
with:
java-version: '17'
distribution: 'temurin'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
@@ -42,11 +42,11 @@ jobs:
asset_name: Stirling-PDF${{ matrix.file_suffix }}.exe
tag: ${{ github.ref }}
overwrite: true
- name: Get version number
id: versionNumber
run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)"
- name: Upload jar binaries to release
uses: svenstaro/upload-release-action@v2
with:

View File

@@ -3,7 +3,7 @@ name: Update Swagger
on:
workflow_dispatch:
push:
branches:
branches:
- master
jobs:
push:
@@ -12,13 +12,13 @@ jobs:
steps:
- uses: actions/checkout@v3.5.2
- name: Set up JDK 17
uses: actions/setup-java@v3.11.0
with:
java-version: '17'
distribution: 'temurin'
- name: Grant execute permission for gradlew
run: chmod +x gradlew

View File

@@ -30,7 +30,7 @@ jobs:
- name: Run Docker Compose Tests
run: |
chmod +x ./gradlew
- name: Get version number
id: versionNumber
run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)"

252
.gitignore vendored
View File

@@ -1,127 +1,127 @@
### Eclipse ###
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
.classpath
.project
version.properties
pipeline/watchedFolders/
pipeline/finishedFolders/
#### Stirling-PDF Files ###
customFiles/
configs/
watchedFolders/
# Gradle
.gradle
.lock
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
.apt_generated_test/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
# Uncomment this line if you wish to ignore the project description file.
# Typically, this file would be tracked if it contains build/dependency configurations:
#.project
### Eclipse Patch ###
# Spring Boot Tooling
.sts4-cache/
### Git ###
# Created by git for backups. To disable backups in Git:
# $ git config --global mergetool.keepBackup false
*.orig
# Created by git when using merge tools for conflicts
*.BACKUP.*
*.BASE.*
*.LOCAL.*
*.REMOTE.*
*_BACKUP_*.txt
*_BASE_*.txt
*_LOCAL_*.txt
*_REMOTE_*.txt
### Java ###
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
*.db
/build
/.vscode
/.idea
# Ignore Mac DS_Store files
.DS_Store
### Eclipse ###
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
.classpath
.project
version.properties
pipeline/watchedFolders/
pipeline/finishedFolders/
#### Stirling-PDF Files ###
customFiles/
configs/
watchedFolders/
# Gradle
.gradle
.lock
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
.apt_generated_test/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
# Uncomment this line if you wish to ignore the project description file.
# Typically, this file would be tracked if it contains build/dependency configurations:
#.project
### Eclipse Patch ###
# Spring Boot Tooling
.sts4-cache/
### Git ###
# Created by git for backups. To disable backups in Git:
# $ git config --global mergetool.keepBackup false
*.orig
# Created by git when using merge tools for conflicts
*.BACKUP.*
*.BASE.*
*.LOCAL.*
*.REMOTE.*
*_BACKUP_*.txt
*_BASE_*.txt
*_LOCAL_*.txt
*_REMOTE_*.txt
### Java ###
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
*.db
/build
/.vscode
/.idea
# Ignore Mac DS_Store files
.DS_Store
**/.DS_Store

View File

@@ -1,69 +1,69 @@
# Main stage
FROM alpine:3.19.1
# JDK for app
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
apk add --no-cache \
ca-certificates \
tzdata \
tini \
bash \
curl \
openjdk17-jre \
# Doc conversion
libreoffice@testing \
# OCR MY PDF (unpaper for descew and other advanced featues)
ocrmypdf \
tesseract-ocr-data-eng \
# CV
py3-opencv \
# python3/pip
python3 && \
wget https://bootstrap.pypa.io/get-pip.py -qO - | python3 - --break-system-packages --no-cache-dir --upgrade && \
# uno unoconv and HTML
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint && \
mv /usr/share/tessdata /usr/share/tessdata-original
ARG VERSION_TAG
# Set Environment Variables
ENV DOCKER_ENABLE_SECURITY=false \
HOME=/home/stirlingpdfuser \
VERSION_TAG=$VERSION_TAG \
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75"
# PUID=1000 \
# PGID=1000 \
# UMASK=022 \
# Copy necessary files
COPY scripts /scripts
COPY pipeline /pipeline
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto
COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto
COPY build/libs/*.jar app.jar
# Create user and group
##RUN groupadd -g $PGID stirlingpdfgroup && \
## useradd -u $PUID -g stirlingpdfgroup -s /bin/sh stirlingpdfuser && \
## mkdir -p $HOME && chown stirlingpdfuser:stirlingpdfgroup $HOME && \
# Set up necessary directories and permissions
RUN mkdir -p /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
##&& \
## chown -R stirlingpdfuser:stirlingpdfgroup /scripts /usr/share/fonts/opentype/noto /usr/share/tesseract-ocr /configs /customFiles && \
## chown -R stirlingpdfuser:stirlingpdfgroup /usr/share/tesseract-ocr-original && \
# Set font cache and permissions
fc-cache -f -v && \
chmod +x /scripts/*
## chown stirlingpdfuser:stirlingpdfgroup /app.jar && \
## chmod +x /scripts/init.sh
EXPOSE 8080
# Set user and run command
##USER stirlingpdfuser
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]
# Main stage
FROM alpine:3.19.1
# JDK for app
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
apk add --no-cache \
ca-certificates \
tzdata \
tini \
bash \
curl \
openjdk17-jre \
# Doc conversion
libreoffice@testing \
# OCR MY PDF (unpaper for descew and other advanced featues)
ocrmypdf \
tesseract-ocr-data-eng \
# CV
py3-opencv \
# python3/pip
python3 && \
wget https://bootstrap.pypa.io/get-pip.py -qO - | python3 - --break-system-packages --no-cache-dir --upgrade && \
# uno unoconv and HTML
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint && \
mv /usr/share/tessdata /usr/share/tessdata-original
ARG VERSION_TAG
# Set Environment Variables
ENV DOCKER_ENABLE_SECURITY=false \
HOME=/home/stirlingpdfuser \
VERSION_TAG=$VERSION_TAG \
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75"
# PUID=1000 \
# PGID=1000 \
# UMASK=022 \
# Copy necessary files
COPY scripts /scripts
COPY pipeline /pipeline
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto
COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto
COPY build/libs/*.jar app.jar
# Create user and group
##RUN groupadd -g $PGID stirlingpdfgroup && \
## useradd -u $PUID -g stirlingpdfgroup -s /bin/sh stirlingpdfuser && \
## mkdir -p $HOME && chown stirlingpdfuser:stirlingpdfgroup $HOME && \
# Set up necessary directories and permissions
RUN mkdir -p /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
##&& \
## chown -R stirlingpdfuser:stirlingpdfgroup /scripts /usr/share/fonts/opentype/noto /usr/share/tesseract-ocr /configs /customFiles && \
## chown -R stirlingpdfuser:stirlingpdfgroup /usr/share/tesseract-ocr-original && \
# Set font cache and permissions
fc-cache -f -v && \
chmod +x /scripts/*
## chown stirlingpdfuser:stirlingpdfgroup /app.jar && \
## chmod +x /scripts/init.sh
EXPOSE 8080
# Set user and run command
##USER stirlingpdfuser
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]

View File

@@ -1,46 +1,46 @@
| Operation | PageOps | Convert | Security | Other | CLI | Python | OpenCV | LibreOffice | OCRmyPDF | Java | Javascript |
|---------------------|---------|---------|----------|-------|------|--------|--------|-------------|----------|----------|------------|
| adjust-contrast | ✔️ | | | | | | | | | | ✔️ |
| auto-split-pdf | ✔️ | | | | | | | | | ✔️ | |
| crop | ✔️ | | | | | | | | | ✔️ | |
| extract-page | ✔️ | | | | | | | | | ✔️ | |
| merge-pdfs | ✔️ | | | | | | | | | ✔️ | |
| multi-page-layout | ✔️ | | | | | | | | | ✔️ | |
| pdf-organizer | ✔️ | | | | | | | | | ✔️ | ✔️ |
| pdf-to-single-page | ✔️ | | | | | | | | | ✔️ | |
| remove-pages | ✔️ | | | | | | | | | ✔️ | |
| rotate-pdf | ✔️ | | | | | | | | | ✔️ | |
| scale-pages | ✔️ | | | | | | | | | ✔️ | |
| split-pdfs | ✔️ | | | | | | | | | ✔️ | |
| file-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | |
| img-to-pdf | | ✔️ | | | | | | | | ✔️ | |
| pdf-to-html | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-img | | ✔️ | | | | | | | | ✔️ | |
| pdf-to-pdfa | | ✔️ | | | ✔️ | | | | ✔️ | | |
| pdf-to-markdown | | ✔️ | | | | | | | | ✔️ | |
| pdf-to-presentation | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-text | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-word | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-xml | | ✔️ | | | ✔️ | | | ✔️ | | | |
| xlsx-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | |
| add-password | | | ✔️ | | | | | | | ✔️ | |
| add-watermark | | | ✔️ | | | | | | | ✔️ | |
| cert-sign | | | ✔️ | | | | | | | ✔️ | |
| change-permissions | | | ✔️ | | | | | | | ✔️ | |
| remove-password | | | ✔️ | | | | | | | ✔️ | |
| sanitize-pdf | | | ✔️ | | | | | | | ✔️ | |
| add-image | | | | ✔️ | | | | | | ✔️ | |
| add-page-numbers | | | | ✔️ | | | | | | ✔️ | |
| auto-rename | | | | ✔️ | | | | | | ✔️ | |
| change-metadata | | | | ✔️ | | | | | | ✔️ | |
| compare | | | | ✔️ | | | | | | | ✔️ |
| compress-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
| extract-image-scans | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
| extract-images | | | | ✔️ | | | | | | ✔️ | |
| flatten | | | | ✔️ | | | | | | | ✔️ |
| get-info-on-pdf | | | | ✔️ | | | | | | ✔️ | |
| ocr-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
| remove-blanks | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
| repair | | | | ✔️ | ✔️ | | | ✔️ | | | |
| show-javascript | | | | ✔️ | | | | | | | ✔️ |
| Operation | PageOps | Convert | Security | Other | CLI | Python | OpenCV | LibreOffice | OCRmyPDF | Java | Javascript |
|---------------------|---------|---------|----------|-------|------|--------|--------|-------------|----------|----------|------------|
| adjust-contrast | ✔️ | | | | | | | | | | ✔️ |
| auto-split-pdf | ✔️ | | | | | | | | | ✔️ | |
| crop | ✔️ | | | | | | | | | ✔️ | |
| extract-page | ✔️ | | | | | | | | | ✔️ | |
| merge-pdfs | ✔️ | | | | | | | | | ✔️ | |
| multi-page-layout | ✔️ | | | | | | | | | ✔️ | |
| pdf-organizer | ✔️ | | | | | | | | | ✔️ | ✔️ |
| pdf-to-single-page | ✔️ | | | | | | | | | ✔️ | |
| remove-pages | ✔️ | | | | | | | | | ✔️ | |
| rotate-pdf | ✔️ | | | | | | | | | ✔️ | |
| scale-pages | ✔️ | | | | | | | | | ✔️ | |
| split-pdfs | ✔️ | | | | | | | | | ✔️ | |
| file-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | |
| img-to-pdf | | ✔️ | | | | | | | | ✔️ | |
| pdf-to-html | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-img | | ✔️ | | | | | | | | ✔️ | |
| pdf-to-pdfa | | ✔️ | | | ✔️ | | | | ✔️ | | |
| pdf-to-markdown | | ✔️ | | | | | | | | ✔️ | |
| pdf-to-presentation | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-text | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-word | | ✔️ | | | ✔️ | | | ✔️ | | | |
| pdf-to-xml | | ✔️ | | | ✔️ | | | ✔️ | | | |
| xlsx-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | |
| add-password | | | ✔️ | | | | | | | ✔️ | |
| add-watermark | | | ✔️ | | | | | | | ✔️ | |
| cert-sign | | | ✔️ | | | | | | | ✔️ | |
| change-permissions | | | ✔️ | | | | | | | ✔️ | |
| remove-password | | | ✔️ | | | | | | | ✔️ | |
| sanitize-pdf | | | ✔️ | | | | | | | ✔️ | |
| add-image | | | | ✔️ | | | | | | ✔️ | |
| add-page-numbers | | | | ✔️ | | | | | | ✔️ | |
| auto-rename | | | | ✔️ | | | | | | ✔️ | |
| change-metadata | | | | ✔️ | | | | | | ✔️ | |
| compare | | | | ✔️ | | | | | | | ✔️ |
| compress-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
| extract-image-scans | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
| extract-images | | | | ✔️ | | | | | | ✔️ | |
| flatten | | | | ✔️ | | | | | | | ✔️ |
| get-info-on-pdf | | | | ✔️ | | | | | | ✔️ | |
| ocr-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
| remove-blanks | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
| repair | | | | ✔️ | ✔️ | | | ✔️ | | | |
| show-javascript | | | | ✔️ | | | | | | | ✔️ |
| sign | | | | ✔️ | | | | | | | ✔️ |

View File

@@ -9,13 +9,13 @@ Fork Stirling-PDF and make a new branch out of Main
Then add reference to the language in the navbar by adding a new language entry to the dropdown
https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/templates/fragments/languages.html
and add a flag svg file to
and add a flag svg file to
https://github.com/Stirling-Tools/Stirling-PDF/tree/main/src/main/resources/static/images/flags
Any SVG flags are fine, i got most of mine from [here](https://flagicons.lipis.dev/)
If your language isn't represented by a flag just find whichever closely matches it, such as for Arabic i chose Saudi Arabia
If your language isnt represented by a flag just find whichever closely matches it, such as for Arabic i chose Saudi Arabia
For example to add Polish you would add
For example to add Polish you would add
```html
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="pl_PL">
<img src="images/flags/pl.svg" alt="icon" width="20" height="15"> Polski
@@ -23,7 +23,7 @@ For example to add Polish you would add
```
The data-language-code is the code used to reference the file in the next step.
Start by copying the existing english property file
Start by copying the existing english property file
[https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/messages_en_GB.properties](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/messages_en_GB.properties)
@@ -32,7 +32,7 @@ Copy and rename it to messages_{your data-language-code here}.properties, in the
Then simply translate all property entries within that file and make a PR into main for others to use!
If you do not have a java IDE i am happy to verify the changes worked once you raise PR (but won't be able to verify the translations themselves)
If you do not have a java IDE i am happy to verify the changes worked once you raise PR (but wont be able to verify the translations themselves)

View File

@@ -2,12 +2,12 @@
This document provides instructions on how to add additional language packs for the OCR tab in Stirling-PDF, both inside and outside of Docker.
## My OCR used to work and now doesn't!
The paths have changed for the tessadata locations on new docker images, please use ``/usr/share/tessdata`` (Others should still work for backwards compatability but might not)
## My OCR used to work and now doesnt!
Please update your tesseract docker volume path version from 4.00 to 5
## How does the OCR Work
Stirling-PDF uses [OCRmyPDF](https://github.com/ocrmypdf/OCRmyPDF) which in turn uses tesseract for its text recognition.
All credit goes to them for this awesome work!
All credit goes to them for this awesome work!
## Language Packs
@@ -27,7 +27,7 @@ Depending on your requirements, you can choose the appropriate language pack for
#### Docker
If you are using Docker, you need to expose the Tesseract tessdata directory as a volume in order to use the additional language packs.
If you are using Docker, you need to expose the Tesseract tessdata directory as a volume in order to use the additional language packs.
#### Docker Compose
Modify your `docker-compose.yml` file to include the following volume configuration:

88
Jenkinsfile vendored
View File

@@ -1,45 +1,45 @@
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'chmod 755 gradlew'
sh './gradlew build'
}
}
stage('Docker Build') {
steps {
script {
def appVersion = sh(returnStdout: true, script: './gradlew printVersion -q').trim()
def image = "frooodle/s-pdf:$appVersion"
sh "docker build -t $image ."
}
}
}
stage('Docker Push') {
steps {
script {
def appVersion = sh(returnStdout: true, script: './gradlew printVersion -q').trim()
def image = "frooodle/s-pdf:$appVersion"
withCredentials([string(credentialsId: 'docker_hub_access_token', variable: 'DOCKER_HUB_ACCESS_TOKEN')]) {
sh "docker login --username frooodle --password $DOCKER_HUB_ACCESS_TOKEN"
sh "docker push $image"
}
}
}
}
stage('Helm Push') {
steps {
script {
//TODO: Read chartVersion from Chart.yaml
def chartVersion = '1.0.0'
withCredentials([string(credentialsId: 'docker_hub_access_token', variable: 'DOCKER_HUB_ACCESS_TOKEN')]) {
sh "docker login --username frooodle --password $DOCKER_HUB_ACCESS_TOKEN"
sh "helm package chart/stirling-pdf"
sh "helm push stirling-pdf-chart-1.0.0.tgz oci://registry-1.docker.io/frooodle"
}
}
}
}
}
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'chmod 755 gradlew'
sh './gradlew build'
}
}
stage('Docker Build') {
steps {
script {
def appVersion = sh(returnStdout: true, script: './gradlew printVersion -q').trim()
def image = "frooodle/s-pdf:$appVersion"
sh "docker build -t $image ."
}
}
}
stage('Docker Push') {
steps {
script {
def appVersion = sh(returnStdout: true, script: './gradlew printVersion -q').trim()
def image = "frooodle/s-pdf:$appVersion"
withCredentials([string(credentialsId: 'docker_hub_access_token', variable: 'DOCKER_HUB_ACCESS_TOKEN')]) {
sh "docker login --username frooodle --password $DOCKER_HUB_ACCESS_TOKEN"
sh "docker push $image"
}
}
}
}
stage('Helm Push') {
steps {
script {
//TODO: Read chartVersion from Chart.yaml
def chartVersion = '1.0.0'
withCredentials([string(credentialsId: 'docker_hub_access_token', variable: 'DOCKER_HUB_ACCESS_TOKEN')]) {
sh "docker login --username frooodle --password $DOCKER_HUB_ACCESS_TOKEN"
sh "helm package chart/stirling-pdf"
sh "helm push stirling-pdf-chart-1.0.0.tgz oci://registry-1.docker.io/frooodle"
}
}
}
}
}
}

View File

@@ -45,7 +45,7 @@ sudo apt-get update
sudo apt-get install -y git automake autoconf libtool libleptonica-dev pkg-config zlib1g-dev make g++ java-17-openjdk python3 python3-pip
```
For Fedora-based systems use this command:
For Fedora-based systems use this command:
```bash
sudo dnf install -y git automake autoconf libtool leptonica-devel pkg-config zlib-devel make gcc-c++ java-17-openjdk python3 python3-pip
@@ -65,7 +65,7 @@ sudo make install
```
### Step 3: Install Additional Software
Next we need to install LibreOffice for conversions, ocrmypdf for OCR, and opencv for pattern recognition functionality.
Next we need to install LibreOffice for conversions, ocrmypdf for OCR, and opencv for patern recognition functionality.
Install the following software:
@@ -95,14 +95,14 @@ For Debian-based systems, you can use the following command:
```bash
sudo apt-get install -y libreoffice-writer libreoffice-calc libreoffice-impress unpaper ocrmypdf
pip3 install uno opencv-python-headless unoconv pngquant WeasyPrint
pip3 install uno opencv-python-headless unoconv pngquant WeasyPrint
```
For Fedora:
```bash
sudo dnf install -y libreoffice-writer libreoffice-calc libreoffice-impress unpaper ocrmypdf
pip3 install uno opencv-python-headless unoconv pngquant WeasyPrint
pip3 install uno opencv-python-headless unoconv pngquant WeasyPrint
```
### Step 4: Clone and Build Stirling-PDF
@@ -140,7 +140,7 @@ Manual:
1. Download the desired language pack(s) by selecting the `.traineddata` file(s) for the language(s) you need.
2. Place the `.traineddata` files in the Tesseract tessdata directory: `/usr/share/tessdata`
3.
3.
Please view [OCRmyPDF install guide](https://ocrmypdf.readthedocs.io/en/latest/installation.html) for more info.
**IMPORTANT:** DO NOT REMOVE EXISTING `eng.traineddata`, IT'S REQUIRED.
@@ -264,10 +264,10 @@ sudo systemctl restart stirlingpdf.service
Remember to set the necessary environment variables before running the project if you want to customize the application the list can be seen in the main readme.
You can do this in the terminal by using the `export` command or -D argument to java -jar command:
You can do this in the terminal by using the `export` command or -D arguements to java -jar command:
```bash
export APP_HOME_NAME="Stirling PDF"
or
-DAPP_HOME_NAME="Stirling PDF"
-DAPP_HOME_NAME="Stirling PDF"
```

View File

@@ -6,7 +6,7 @@
[![Docker Image Version (tag latest semver)](https://img.shields.io/docker/v/frooodle/s-pdf/latest)](https://github.com/Stirling-Tools/Stirling-PDF/)
[![GitHub Repo stars](https://img.shields.io/github/stars/stirling-tools/stirling-pdf?style=social)](https://github.com/Stirling-Tools/stirling-pdf)
[![Paypal Donate](https://img.shields.io/badge/Paypal%20Donate-yellow?style=flat&logo=paypal)](https://www.paypal.com/paypalme/froodleplex)
[![Github Sponsor](https://img.shields.io/badge/Github%20Sponsor-yellow?style=flat&logo=github)](https://github.com/sponsors/Frooodle)
[![Github Sponser](https://img.shields.io/badge/Github%20Sponsor-yellow?style=flat&logo=github)](https://github.com/sponsors/Frooodle)
[![Deploy to DO](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/Stirling-Tools/Stirling-PDF/tree/digitalOcean&refcode=c3210994b1af)
@@ -172,7 +172,7 @@ Stirling PDF currently supports 26!
- Hindi (हिंदी) (hi_IN)
- Hungarian (Magyar) (hu_HU)
- Bulgarian (Български) (bg_BG)
- Sebian Latin alphabet (Srpski) (sr_LATN_RS)
- Sebian Latin alphabet (Srpski) (sr-Latn-RS)
## Contributing (creating issues, translations, fixing bugs, etc.)
@@ -262,7 +262,7 @@ For API usage you must provide a header with 'X-API-Key' and the associated API
- Redact text (Via UI not just automated way)
- Add Forms
- Multi page layout (Stich PDF pages together) support x rows y columns and custom page sizing
- Fill forms manually or automatically
- Fill forms mannual and automatic
### Q2: Why is my application downloading .htm files?
This is an issue caused commonly by your NGINX configuration. The default file upload size for NGINX is 1MB, you need to add the following in your Nginx sites-available file. ``client_max_body_size SIZE;`` Where "SIZE" is 50M for example for 50MB files.

View File

@@ -1,64 +1,64 @@
|Technology | Ultra-Lite | Lite | Full |
|----------------|:----------:|:----:|:----:|
| Java | ✔️ | ✔️ | ✔️ |
| JavaScript | ✔️ | ✔️ | ✔️ |
| Libre | | ✔️ | ✔️ |
| Python | | | ✔️ |
| OpenCV | | | ✔️ |
| OCRmyPDF | | | ✔️ |
Operation | Ultra-Lite | Lite | Full
--------------------|------------|------|-----
add-page-numbers | ✔️ | ✔️ | ✔️
add-password | ✔️ | ✔️ | ✔️
add-image | ✔️ | ✔️ | ✔️
add-watermark | ✔️ | ✔️ | ✔️
adjust-contrast | ✔️ | ✔️ | ✔️
auto-split-pdf | ✔️ | ✔️ | ✔️
auto-redact | ✔️ | ✔️ | ✔️
auto-rename | ✔️ | ✔️ | ✔️
cert-sign | ✔️ | ✔️ | ✔️
crop | ✔️ | ✔️ | ✔️
change-metadata | ✔️ | ✔️ | ✔️
change-permissions | ✔️ | ✔️ | ✔️
compare | ✔️ | ✔️ | ✔️
extract-page | ✔️ | ✔️ | ✔️
extract-images | ✔️ | ✔️ | ✔️
flatten | ✔️ | ✔️ | ✔️
get-info-on-pdf | ✔️ | ✔️ | ✔️
img-to-pdf | ✔️ | ✔️ | ✔️
markdown-to-pdf | ✔️ | ✔️ | ✔️
merge-pdfs | ✔️ | ✔️ | ✔️
multi-page-layout | ✔️ | ✔️ | ✔️
overlay-pdf | ✔️ | ✔️ | ✔️
pdf-organizer | ✔️ | ✔️ | ✔️
pdf-to-csv | ✔️ | ✔️ | ✔️
pdf-to-img | ✔️ | ✔️ | ✔️
pdf-to-single-page | ✔️ | ✔️ | ✔️
remove-pages | ✔️ | ✔️ | ✔️
remove-password | ✔️ | ✔️ | ✔️
rotate-pdf | ✔️ | ✔️ | ✔️
sanitize-pdf | ✔️ | ✔️ | ✔️
scale-pages | ✔️ | ✔️ | ✔️
sign | ✔️ | ✔️ | ✔️
show-javascript | ✔️ | ✔️ | ✔️
split-by-size-or-count | ✔️ | ✔️ | ✔️
split-pdf-by-sections | ✔️ | ✔️ | ✔️
split-pdfs | ✔️ | ✔️ | ✔️
file-to-pdf | | ✔️ | ✔️
pdf-to-html | | ✔️ | ✔️
pdf-to-presentation | | ✔️ | ✔️
pdf-to-text | | ✔️ | ✔️
pdf-to-word | | ✔️ | ✔️
pdf-to-xml | | ✔️ | ✔️
repair | | ✔️ | ✔️
xlsx-to-pdf | | ✔️ | ✔️
compress-pdf | | | ✔️
extract-image-scans | | | ✔️
ocr-pdf | | | ✔️
pdf-to-pdfa | | | ✔️
remove-blanks | | | ✔️
|Technology | Ultra-Lite | Lite | Full |
|----------------|:----------:|:----:|:----:|
| Java | ✔️ | ✔️ | ✔️ |
| JavaScript | ✔️ | ✔️ | ✔️ |
| Libre | | ✔️ | ✔️ |
| Python | | | ✔️ |
| OpenCV | | | ✔️ |
| OCRmyPDF | | | ✔️ |
Operation | Ultra-Lite | Lite | Full
--------------------|------------|------|-----
add-page-numbers | ✔️ | ✔️ | ✔️
add-password | ✔️ | ✔️ | ✔️
add-image | ✔️ | ✔️ | ✔️
add-watermark | ✔️ | ✔️ | ✔️
adjust-contrast | ✔️ | ✔️ | ✔️
auto-split-pdf | ✔️ | ✔️ | ✔️
auto-redact | ✔️ | ✔️ | ✔️
auto-rename | ✔️ | ✔️ | ✔️
cert-sign | ✔️ | ✔️ | ✔️
crop | ✔️ | ✔️ | ✔️
change-metadata | ✔️ | ✔️ | ✔️
change-permissions | ✔️ | ✔️ | ✔️
compare | ✔️ | ✔️ | ✔️
extract-page | ✔️ | ✔️ | ✔️
extract-images | ✔️ | ✔️ | ✔️
flatten | ✔️ | ✔️ | ✔️
get-info-on-pdf | ✔️ | ✔️ | ✔️
img-to-pdf | ✔️ | ✔️ | ✔️
markdown-to-pdf | ✔️ | ✔️ | ✔️
merge-pdfs | ✔️ | ✔️ | ✔️
multi-page-layout | ✔️ | ✔️ | ✔️
overlay-pdf | ✔️ | ✔️ | ✔️
pdf-organizer | ✔️ | ✔️ | ✔️
pdf-to-csv | ✔️ | ✔️ | ✔️
pdf-to-img | ✔️ | ✔️ | ✔️
pdf-to-single-page | ✔️ | ✔️ | ✔️
remove-pages | ✔️ | ✔️ | ✔️
remove-password | ✔️ | ✔️ | ✔️
rotate-pdf | ✔️ | ✔️ | ✔️
sanitize-pdf | ✔️ | ✔️ | ✔️
scale-pages | ✔️ | ✔️ | ✔️
sign | ✔️ | ✔️ | ✔️
show-javascript | ✔️ | ✔️ | ✔️
split-by-size-or-count | ✔️ | ✔️ | ✔️
split-pdf-by-sections | ✔️ | ✔️ | ✔️
split-pdfs | ✔️ | ✔️ | ✔️
file-to-pdf | | ✔️ | ✔️
pdf-to-html | | ✔️ | ✔️
pdf-to-presentation | | ✔️ | ✔️
pdf-to-text | | ✔️ | ✔️
pdf-to-word | | ✔️ | ✔️
pdf-to-xml | | ✔️ | ✔️
repair | | ✔️ | ✔️
xlsx-to-pdf | | ✔️ | ✔️
compress-pdf | | | ✔️
extract-image-scans | | | ✔️
ocr-pdf | | | ✔️
pdf-to-pdfa | | | ✔️
remove-blanks | | | ✔️

View File

@@ -89,10 +89,10 @@ dependencies {
//security updates
implementation 'ch.qos.logback:logback-classic:1.4.14'
implementation 'ch.qos.logback:logback-core:1.4.14'
implementation 'org.springframework:spring-webmvc:6.1.3'
implementation 'org.springframework:spring-webmvc:6.1.2'
implementation("io.github.pixee:java-security-toolkit:1.1.2")
implementation 'org.yaml:snakeyaml:2.2'
implementation 'org.springframework.boot:spring-boot-starter-web:3.2.2'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.2.2'
@@ -101,7 +101,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security:3.2.2'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE'
implementation "org.springframework.boot:spring-boot-starter-data-jpa:3.2.2"
//2.2.x requires rebuild of DB file.. need migration path
implementation "com.h2database:h2:2.1.214"
}
@@ -138,19 +138,19 @@ dependencies {
implementation ('com.opencsv:opencsv:5.9') {
exclude group: 'commons-logging', module: 'commons-logging'
}
implementation ('org.apache.pdfbox:pdfbox:3.0.1'){
exclude group: 'commons-logging', module: 'commons-logging'
}
implementation ('org.apache.pdfbox:xmpbox:3.0.1'){
exclude group: 'commons-logging', module: 'commons-logging'
}
implementation 'org.bouncycastle:bcprov-jdk18on:1.77'
implementation 'org.bouncycastle:bcpkix-jdk18on:1.77'
implementation 'org.springframework.boot:spring-boot-starter-actuator:3.2.2'
implementation 'io.micrometer:micrometer-core:1.12.3'
implementation 'io.micrometer:micrometer-core:1.12.2'
implementation group: 'com.google.zxing', name: 'core', version: '3.5.2'
// https://mvnrepository.com/artifact/org.commonmark/commonmark
implementation 'org.commonmark:commonmark:0.21.0'

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: 0.20.2
appVersion: 0.14.2
description: locally hosted web application that allows you to perform various operations on PDF files
home: https://github.com/Stirling-Tools/Stirling-PDF
keywords:

View File

@@ -43,6 +43,6 @@ spec:
name: http
{{- end }}
protocol: TCP
selector:
{{- include "stirlingpdf.selectorLabels" . | nindent 4 }}

View File

@@ -16,11 +16,11 @@ commonLabels: {}
# team_name: dev
envs: []
# - name: UI_APP_NAME
# - name: PP_HOME_NAME
# value: "Stirling PDF"
# - name: UI_HOME_DESCRIPTION
# - name: APP_HOME_DESCRIPTION
# value: "Your locally hosted one-stop-shop for all your PDF needs."
# - name: UI_APP_NAVBAR_NAME
# - name: APP_NAVBAR_NAME
# value: "Stirling PDF"
# - name: ALLOW_GOOGLE_VISIBILITY
# value: "true"

View File

@@ -19,8 +19,8 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs173">
<linearGradient
id="XMLID_5_"
gradientUnits="userSpaceOnUse"
@@ -37,7 +37,7 @@
style="stop-color:#C2C2C9"
id="stop158" />
</linearGradient>
</defs><sodipodi:namedview
id="namedview171"
pagecolor="#ffffff"

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -15,7 +15,7 @@ services:
ports:
- 8080:8080
volumes:
- /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw
- /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw
environment:

View File

@@ -15,7 +15,7 @@ services:
ports:
- 8080:8080
volumes:
- /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw
- /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw
environment:

View File

@@ -15,7 +15,7 @@ services:
ports:
- 8080:8080
volumes:
- /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw
- /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw
environment:

View File

@@ -15,7 +15,7 @@ services:
ports:
- 8080:8080
volumes:
- /stirling/latest/data:/usr/share/tessdata:rw
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw
- /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw
environment:

182
gradlew.bat vendored
View File

@@ -1,91 +1,91 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1,37 @@
import cv2
import sys
import argparse
import numpy as np
def is_blank_image(image_path, threshold=10, white_percent=99, white_value=255, blur_size=5):
image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if image is None:
print(f"Error: Unable to read the image file: {image_path}")
return False
# Apply Gaussian blur to reduce noise
blurred_image = cv2.GaussianBlur(image, (blur_size, blur_size), 0)
_, thresholded_image = cv2.threshold(blurred_image, white_value - threshold, white_value, cv2.THRESH_BINARY)
# Calculate the percentage of white pixels in the thresholded image
white_pixels = np.sum(thresholded_image == white_value)
white_pixel_percentage = (white_pixels / thresholded_image.size) * 100
print(f"Page has white pixel percent of {white_pixel_percentage}")
return white_pixel_percentage >= white_percent
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Detect if an image is considered blank or not.')
parser.add_argument('image_path', help='The path to the image file.')
parser.add_argument('-t', '--threshold', type=int, default=10, help='Threshold for determining white pixels. The default value is 10.')
parser.add_argument('-w', '--white_percent', type=float, default=99, help='The percentage of white pixels for an image to be considered blank. The default value is 99.')
args = parser.parse_args()
blank = is_blank_image(args.image_path, args.threshold, args.white_percent)
# Return code 1: The image is considered blank.
# Return code 0: The image is not considered blank.
sys.exit(int(blank))

View File

@@ -4,7 +4,7 @@ if [ "$DOCKER_ENABLE_SECURITY" = "true" ] && [ "$VERSION_TAG" != "alpha" ]; then
if [ ! -f app-security.jar ]; then
echo "Trying to download from: https://github.com/Stirling-Tools/Stirling-PDF/releases/download/v$VERSION_TAG/Stirling-PDF-with-login.jar"
curl -L -o app-security.jar https://github.com/Stirling-Tools/Stirling-PDF/releases/download/v$VERSION_TAG/Stirling-PDF-with-login.jar
# If the first download attempt failed, try with the 'v' prefix
if [ $? -ne 0 ]; then
echo "Trying to download from: https://github.com/Stirling-Tools/Stirling-PDF/releases/download/$VERSION_TAG/Stirling-PDF-with-login.jar"

View File

@@ -2,7 +2,7 @@ import argparse
import sys
import cv2
import numpy as np
import os
import os
def find_photo_boundaries(image, background_color, tolerance=30, min_area=10000, min_contour_area=500):
mask = cv2.inRange(image, background_color - tolerance, background_color + tolerance)
@@ -49,9 +49,9 @@ def auto_rotate(image, angle_threshold=1):
angles = []
for rho, theta in lines[:, 0]:
angles.append((theta * 180) / np.pi - 90)
angle = np.median(angles)
if abs(angle) < angle_threshold:
return image
@@ -65,16 +65,16 @@ def auto_rotate(image, angle_threshold=1):
def crop_borders(image, border_color, tolerance=30):
mask = cv2.inRange(image, border_color - tolerance, border_color + tolerance)
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if len(contours) == 0:
return image
largest_contour = max(contours, key=cv2.contourArea)
x, y, w, h = cv2.boundingRect(largest_contour)
return image[y:y+h, x:x+w]
def split_photos(input_file, output_directory, tolerance=30, min_area=10000, min_contour_area=500, angle_threshold=10, border_size=0):
image = cv2.imread(input_file)
background_color = estimate_background_color(image)
@@ -110,7 +110,7 @@ if __name__ == "__main__":
parser.add_argument("--min_contour_area", type=int, default=500, help="Sets the minimum contour area threshold for a photo (default: 500).")
parser.add_argument("--angle_threshold", type=int, default=10, help="Sets the minimum absolute angle required for the image to be rotated (default: 10).")
parser.add_argument("--border_size", type=int, default=0, help="Sets the size of the border added and removed to prevent white borders in the output (default: 0).")
args = parser.parse_args()
split_photos(args.input_file, args.output_directory, tolerance=args.tolerance, min_area=args.min_area, min_contour_area=args.min_contour_area, angle_threshold=args.angle_threshold, border_size=args.border_size)

View File

@@ -79,16 +79,6 @@ public class ConfigInitializer
return parts.length > 0 ? parts[0].trim().replace("#", "").trim() : "";
};
Function<String, Integer> getIndentationLevel =
line -> {
int count = 0;
for (char ch : line.toCharArray()) {
if (ch == ' ') count++;
else break;
}
return count;
};
Set<String> userKeys = userLines.stream().map(extractKey).collect(Collectors.toSet());
for (String line : templateLines) {
@@ -144,77 +134,10 @@ public class ConfigInitializer
.map(extractKey)
.anyMatch(templateKey -> templateKey.equalsIgnoreCase(userKey));
if (!isPresentInTemplate && !isCommented.apply(userLine)) {
if (!childOfTemplateEntry(
isCommented,
extractKey,
getIndentationLevel,
userLines,
userLine,
templateLines)) {
// check if userLine is a child of a entry within templateLines or not, if child
// of parent in templateLines then dont add to mergedLines, if anything else
// then add
mergedLines.add(userLine);
}
mergedLines.add(userLine);
}
}
Files.write(outputPath, mergedLines, StandardCharsets.UTF_8);
}
// New method to check if a userLine is a child of an entry in templateLines
boolean childOfTemplateEntry(
Function<String, Boolean> isCommented,
Function<String, String> extractKey,
Function<String, Integer> getIndentationLevel,
List<String> userLines,
String userLine,
List<String> templateLines) {
String userKey = extractKey.apply(userLine).trim();
int userIndentation = getIndentationLevel.apply(userLine);
// Start by assuming the line is not a child of an entry in templateLines
boolean isChild = false;
// Iterate backwards through userLines from the current line to find any parent
for (int i = userLines.indexOf(userLine) - 1; i >= 0; i--) {
String potentialParentLine = userLines.get(i);
int parentIndentation = getIndentationLevel.apply(potentialParentLine);
// Check if we've reached a potential parent based on indentation
if (parentIndentation < userIndentation) {
String parentKey = extractKey.apply(potentialParentLine).trim();
// Now, check if this potential parent or any of its parents exist in templateLines
boolean parentExistsInTemplate =
templateLines.stream()
.filter(line -> !isCommented.apply(line)) // Skip commented lines
.anyMatch(
templateLine -> {
String templateKey =
extractKey.apply(templateLine).trim();
return parentKey.equalsIgnoreCase(templateKey);
});
if (!parentExistsInTemplate) {
// If the parent does not exist in template, check the next level parent
userIndentation =
parentIndentation; // Update userIndentation to the parent's indentation
// for next iteration
if (parentIndentation == 0) {
// If we've reached the top-level parent and it's not in template, the
// original line is considered not a child
isChild = false;
break;
}
} else {
// If any parent exists in template, the original line is considered a child
isChild = true;
break;
}
}
}
return isChild; // Return true if the line is not a child of any entry in templateLines
}
}

View File

@@ -140,6 +140,7 @@ public class EndpointConfiguration {
// CLI
addEndpointToGroup("CLI", "compress-pdf");
addEndpointToGroup("CLI", "extract-image-scans");
addEndpointToGroup("CLI", "remove-blanks");
addEndpointToGroup("CLI", "repair");
addEndpointToGroup("CLI", "pdf-to-pdfa");
addEndpointToGroup("CLI", "file-to-pdf");
@@ -217,7 +218,6 @@ public class EndpointConfiguration {
addEndpointToGroup("Java", "split-by-size-or-count");
addEndpointToGroup("Java", "overlay-pdf");
addEndpointToGroup("Java", "split-pdf-by-sections");
addEndpointToGroup("Java", "remove-blanks");
// Javascript
addEndpointToGroup("Javascript", "pdf-organizer");

View File

@@ -9,9 +9,6 @@ import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@@ -47,11 +44,6 @@ public class SecurityConfiguration {
@Autowired private FirstLoginFilter firstLoginFilter;
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.addFilterBefore(userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
@@ -61,14 +53,6 @@ public class SecurityConfiguration {
http.csrf(csrf -> csrf.disable());
http.addFilterBefore(rateLimitingFilter(), UsernamePasswordAuthenticationFilter.class);
http.addFilterAfter(firstLoginFilter, UsernamePasswordAuthenticationFilter.class);
http.sessionManagement(
sessionManagement ->
sessionManagement
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.maximumSessions(3)
.maxSessionsPreventsLogin(true)
.sessionRegistry(sessionRegistry())
.expiredUrl("/login?logout=true"));
http.formLogin(
formLogin ->
formLogin

View File

@@ -10,9 +10,6 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
@@ -231,27 +228,11 @@ public class UserController {
if (currentUsername.equals(username)) {
throw new IllegalArgumentException("Cannot delete currently logined in user.");
}
invalidateUserSessions(username);
userService.deleteUser(username);
return "redirect:/addUsers";
}
@Autowired private SessionRegistry sessionRegistry;
private void invalidateUserSessions(String username) {
for (Object principal : sessionRegistry.getAllPrincipals()) {
if (principal instanceof UserDetails) {
UserDetails userDetails = (UserDetails) principal;
if (userDetails.getUsername().equals(username)) {
for (SessionInformation session :
sessionRegistry.getAllSessions(principal, false)) {
session.expireNow();
}
}
}
}
}
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
@PostMapping("/get-api-key")
public ResponseEntity<String> getApiKey(Principal principal) {

View File

@@ -41,7 +41,7 @@ public class OCRController {
private static final Logger logger = LoggerFactory.getLogger(OCRController.class);
public List<String> getAvailableTesseractLanguages() {
String tessdataDir = "/usr/share/tessdata";
String tessdataDir = "/usr/share/tesseract-ocr/5/tessdata";
File[] files = new File(tessdataDir).listFiles();
if (files == null) {
return Collections.emptyList();

View File

@@ -33,8 +33,6 @@ public class AccountWebController {
return "redirect:/";
}
model.addAttribute("currentPage", "login");
if (request.getParameter("error") != null) {
model.addAttribute("error", request.getParameter("error"));
@@ -114,7 +112,6 @@ public class AccountWebController {
model.addAttribute("role", user.get().getRolesAsString());
model.addAttribute("settings", settingsJson);
model.addAttribute("changeCredsFlag", user.get().isFirstLogin());
model.addAttribute("currentPage", "account");
}
} else {
return "redirect:/";

View File

@@ -82,7 +82,7 @@ public class OtherWebController {
}
public List<String> getAvailableTesseractLanguages() {
String tessdataDir = "/usr/share/tessdata";
String tessdataDir = "/usr/share/tesseract-ocr/5/tessdata";
File[] files = new File(tessdataDir).listFiles();
if (files == null) {
return Collections.emptyList();

View File

@@ -12,6 +12,6 @@ public class PdfToTextOrRTFRequest extends PDFFile {
@Schema(
description = "The output Text or RTF format",
allowableValues = {"rtf", "txt"})
allowableValues = {"rtf", "txt:Text"})
private String outputFormat;
}

View File

@@ -1,6 +1,6 @@
____ _____ ___ ____ _ ___ _ _ ____ ____ ____ _____
____ _____ ___ ____ _ ___ _ _ ____ ____ ____ _____
/ ___|_ _|_ _| _ \| | |_ _| \ | |/ ___| | _ \| _ \| ___|
\___ \ | | | || |_) | | | || \| | | _ _____| |_) | | | | |_
___) || | | || _ <| |___ | || |\ | |_| |_____| __/| |_| | _|
|____/ |_| |___|_| \_\_____|___|_| \_|\____| |_| |____/|_|
\___ \ | | | || |_) | | | || \| | | _ _____| |_) | | | | |_
___) || | | || _ <| |___ | || |\ | |_| |_____| __/| |_| | _|
|____/ |_| |___|_| \_\_____|___|_| \_|\____| |_| |____/|_|
Powered by Spring Boot ${spring-boot.version}

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=اختر صورة
genericSubmit=إرسال
processTimeWarning=تحذير: يمكن أن تستغرق هذه العملية ما يصل إلى دقيقة حسب حجم الملف
pageOrderPrompt=ترتيب الصفحات (أدخل قائمة بأرقام الصفحات مفصولة بفواصل):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=اذهب
true=\u0635\u062D\u064A\u062D
false=\u062E\u0637\u0623
@@ -20,7 +19,6 @@ save=\u062D\u0641\u0638
close=\u0625\u063A\u0644\u0627\u0642
filesSelected=الملفات المحددة
noFavourites=لم تتم إضافة أي مفضلات
downloadComplete=Download Complete
bored=الانتظار بالملل؟
alphabet=\u0627\u0644\u0623\u0628\u062C\u062F\u064A\u0629
downloadPdf=تنزيل PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Изберете изображение(я)
genericSubmit=Подайте
processTimeWarning=Предупреждение: Този процес може да отнеме до минута в зависимост от размера на файла
pageOrderPrompt=Персонализиран ред на страниците (Въведете разделен със запетаи списък с номера на страници или функции като 2n+1):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Давай
true=Вярно
false=Невярно
@@ -20,7 +19,6 @@ save=Съхранете
close=Затворете
filesSelected=избрани файлове
noFavourites=Няма добавени любими
downloadComplete=Download Complete
bored=Отекчени сте да чакате?
alphabet=Азбука
downloadPdf=Изтеглете PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Selecciona Imatge(s)
genericSubmit=Envia
processTimeWarning=Alerta: Aquest procés pot tardar 1 minut depenent de la mida de l'arxiu
pageOrderPrompt=Ordre de Pàgines (Llista separada per comes) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Anar
true=Verdader
false=Fals
@@ -20,7 +19,6 @@ save=Desa
close=Tanca
filesSelected=fitxers seleccionats
noFavourites=No s'ha afegit cap favorit
downloadComplete=Download Complete
bored=Avorrit esperant?
alphabet=Alfabet
downloadPdf=Descarregueu PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Wählen Sie ein Bild
genericSubmit=Einreichen
processTimeWarning=Achtung: Abhängig von der Dateigröße kann dieser Prozess bis zu einer Minute dauern
pageOrderPrompt=Seitenreihenfolge (Geben Sie eine durch Komma getrennte Liste von Seitenzahlen ein):
pageSelectionPrompt=Benutzerdefinierte Seitenauswahl (Geben Sie eine durch Kommas getrennte Liste von Seitenzahlen 1,5,6 oder Funktionen wie 2n+1 ein):
goToPage=Los
true=Wahr
false=Falsch
@@ -20,7 +19,6 @@ save=Speichern
close=Schließen
filesSelected=Dateien ausgewählt
noFavourites=Keine Favoriten hinzugefügt
downloadComplete=Download Complete
bored=Langeweile beim Warten?
alphabet=Alphabet
downloadPdf=PDF herunterladen

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=\u0395\u03C0\u03B9\u03BB\u03BF\u03B3\u03AE \u0395\u03B9\u03BA\u03CC\u0
genericSubmit=\u03A5\u03C0\u03BF\u03B2\u03BF\u03BB\u03AE
processTimeWarning=\u03A0\u03C1\u03BF\u03C3\u03BF\u03C7\u03AE: \u0391\u03C5\u03C4\u03AE \u03B7 \u03B4\u03B9\u03B1\u03B4\u03B9\u03BA\u03B1\u03C3\u03AF\u03B1 \u03BC\u03C0\u03BF\u03C1\u03B5\u03AF \u03BD\u03B1 \u03B4\u03B9\u03B1\u03C1\u03BA\u03AD\u03C3\u03B5\u03B9 \u03AD\u03C9\u03C2 \u03BA\u03B1\u03B9 \u03AD\u03BD\u03B1 \u03BB\u03B5\u03C0\u03C4\u03CC \u03B1\u03BD\u03AC\u03BB\u03BF\u03B3\u03B1 \u03BC\u03B5 \u03C4\u03BF \u03BC\u03AD\u03B3\u03B5\u03B8\u03BF\u03C2 \u03C4\u03BF\u03C5 \u03B1\u03C1\u03C7\u03B5\u03AF\u03BF\u03C5
pageOrderPrompt=\u03A0\u03C1\u03BF\u03C3\u03B1\u03C1\u03BC\u03BF\u03C3\u03BC\u03AD\u03BD\u03B7 \u03A3\u03B5\u03B9\u03C1\u03AC \u03A3\u03B5\u03BB\u03AF\u03B4\u03B1\u03C2 (\u03A0\u03C1\u03BF\u03C3\u03B8\u03AD\u03C3\u03C4\u03B5 \u03BC\u03AF\u03B1 \u03BB\u03AF\u03C3\u03C4\u03B5 \u03B1\u03C0\u03BF \u03B1\u03C1\u03B9\u03B8\u03BC\u03BF\u03CD\u03C2 \u03C3\u03B5\u03BB\u03B9\u03B4\u03CE\u03BD, \u03C7\u03C9\u03C1\u03B9\u03C3\u03BC\u03AD\u03BD\u03B5\u03C2 \u03BC\u03B5 \u03BA\u03CC\u03BC\u03BC\u03B1 \u03AE \u03C3\u03C5\u03BD\u03B1\u03C1\u03C4\u03AE\u03C3\u03B5\u03B9\u03C2 \u03CC\u03C0\u03C9\u03C2 2n+1) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Go
true=\u0391\u03BB\u03B7\u03B8\u03AD\u03C2
false=\u039B\u03B1\u03BD\u03B8\u03B1\u03C3\u03BC\u03AD\u03BD\u03BF
@@ -20,7 +19,6 @@ save=\u0391\u03C0\u03BF\u03B8\u03AE\u03BA\u03B5\u03C5\u03C3\u03B7
close=\u039A\u03BB\u03B5\u03AF\u03C3\u03B9\u03BC\u03BF
filesSelected=\u03B1\u03C1\u03C7\u03B5\u03AF\u03B1 \u03C0\u03BF\u03C5 \u03B5\u03C0\u03B9\u03BB\u03AD\u03C7\u03B8\u03B7\u03BA\u03B1\u03BD
noFavourites=\u039A\u03B1\u03BD\u03AD\u03BD\u03B1 \u03B1\u03B3\u03B1\u03C0\u03AE\u03BC\u03B5\u03BD\u03BF \u03B4\u03B5\u03BD \u03AD\u03C7\u03B5\u03B9 \u03C0\u03C1\u03BF\u03C3\u03C4\u03B5\u03B8\u03B5\u03AF
downloadComplete=Download Complete
bored=\u0392\u03B1\u03C1\u03B9\u03AD\u03C3\u03C4\u03B5 \u03BD\u03B1 \u03C0\u03B5\u03C1\u03B9\u03BC\u03AD\u03BD\u03B5\u03C4\u03B5;
alphabet=\u0391\u03BB\u03C6\u03AC\u03B2\u03B7\u03C4\u03BF
downloadPdf=\u039A\u03B1\u03C4\u03AD\u03B2\u03B1\u03C3\u03BC\u03B1 \u03C4\u03BF\u03C5 PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr = left to right, rtl = right to left)
@@ -20,7 +20,6 @@ save=Save
close=Close
filesSelected=files selected
noFavourites=No favourites added
downloadComplete=Download Complete
bored=Bored Waiting?
alphabet=Alphabet
downloadPdf=Download PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Select Image(s)
genericSubmit=Submit
processTimeWarning=Warning: This process can take up to a minute depending on file-size
pageOrderPrompt=Custom Page Order (Enter a comma-separated list of page numbers or Functions like 2n+1) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Go
true=True
false=False
@@ -20,7 +19,6 @@ save=Save
close=Close
filesSelected=files selected
noFavourites=No favorites added
downloadComplete=Download Complete
bored=Bored Waiting?
alphabet=Alphabet
downloadPdf=Download PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Seleccionar Imagen(es)
genericSubmit=Enviar
processTimeWarning=Advertencia: este proceso puede tardar hasta un minuto dependiendo del tamaño del archivo
pageOrderPrompt=Orden de páginas (Introduzca una lista de números de página separados por coma):
pageSelectionPrompt=Selección de página personalizada (Intruduzca una lista de números de página separados por comas 1,5,6 o funciones como 2n+1) :
goToPage=Ir a
true=Verdadero
false=Falso
@@ -20,7 +19,6 @@ save=Guardar
close=Cerrar
filesSelected=archivos seleccionados
noFavourites=No se agregaron favoritos
downloadComplete=Download Complete
bored=¿Cansado de esperar?
alphabet=Alfabeto
downloadPdf=Descargar PDF
@@ -58,7 +56,7 @@ usernameExistsMessage=El nuevo nombre de usuario está en uso.
###############
# Pipeline #
###############
pipeline.header=Menú de canalización (Alfa)
pipeline.header=Menu Pipeline (Alfa)
pipeline.uploadButton=Cargar personalización
pipeline.configureButton=Configurar
pipeline.defaultOption=Personalizar
@@ -67,13 +65,13 @@ pipeline.submitButton=Enviar
######################
# Pipeline Options #
######################
pipelineOptions.header=Configuración de la canalización
pipelineOptions.pipelineNameLabel=Nombre de la canalización
pipelineOptions.saveSettings=Guardar configuración de la canalización
pipelineOptions.pipelineNamePrompt=Introduzca aquí el nombre de la canalización
pipelineOptions.header=Configuración Pipeline
pipelineOptions.pipelineNameLabel=Nombre del Pipeline
pipelineOptions.saveSettings=Guardar configuración de la oiperación
pipelineOptions.pipelineNamePrompt=Introduzca aquí el nombre del pipeline
pipelineOptions.selectOperation=Seleccione la operación
pipelineOptions.addOperationButton=Añadir operación
pipelineOptions.pipelineHeader=Canalización:
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Descargar
pipelineOptions.validateButton=Validar
@@ -564,7 +562,7 @@ autoSplitPDF.submit=Entregar
#pipeline
pipeline.title=Canalización
pipeline.title=Pipeline
#pageLayout

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Hautatu Irudia(k)
genericSubmit=Bidali
processTimeWarning=Oharra: prozesu honetarako minutu bat ere beharko da fitxategiaren tamaiaren arabera
pageOrderPrompt=Orrialdeen ordena (sartu komaz bereizitako orrialde-zenbakien zerrenda)
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Joan
true=Egiazkoa
false=Faltsua
@@ -20,7 +19,6 @@ save=Gorde
close=Itxi
filesSelected=Hautatutako fitxategiak
noFavourites=Ez dira gogokoak gehitu
downloadComplete=Download Complete
bored=Itxaroten aspertuta?
alphabet=Alfabetoa
downloadPdf=PDFa deskargatu

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Choisir une image
genericSubmit=Envoyer
processTimeWarning=Attention, ce processus peut prendre jusqu\u2019à une minute en fonction de la taille du fichier.
pageOrderPrompt=Ordre des pages (entrez une liste de numéros de page séparés par des virgules ou des fonctions telles que 2n+1)\u00a0:
pageSelectionPrompt=Sélection des pages (entrez une liste de numéros de page séparés par des virgules ou des fonctions telles que 2n+1)\u00a0:
goToPage=Aller
true=Vrai
false=Faux
@@ -20,7 +19,6 @@ save=Enregistrer
close=Fermer
filesSelected=fichiers sélectionnés
noFavourites=Aucun favori ajouté
downloadComplete=Téléchargement terminé
bored=Ennuyé d\u2019attendre\u00a0?
alphabet=Alphabet
downloadPdf=Télécharger le PDF
@@ -44,10 +42,10 @@ red=Rouge
green=Vert
blue=Bleu
custom=Personnalisé\u2026
WorkInProgess=En cours de développement, merci de nous remonter les problèmes que vous pourriez constater!
poweredBy=Propulsé par
yes=Oui
no=Non
WorkInProgess=Work in progress, May not work or be buggy, Please report any problems!
poweredBy=Powered by
yes=Yes
no=No
changedCredsMessage=Les identifiants ont été mis à jour\u00a0!
notAuthenticatedMessage=Utilisateur non authentifié.
userNotFoundMessage=Utilisateur non trouvé.
@@ -58,24 +56,24 @@ usernameExistsMessage=Le nouveau nom d\u2019utilisateur existe déjà.
###############
# Pipeline #
###############
pipeline.header=Menu Pipeline (Alpha)
pipeline.uploadButton=Télécharger une personnalisation
pipeline.configureButton=Configurer
pipeline.defaultOption=Personnaliser
pipeline.submitButton=Soumettre
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Configuration du pipeline
pipelineOptions.pipelineNameLabel=Nom du pipeline
pipelineOptions.saveSettings=Sauvegarder la configuration
pipelineOptions.pipelineNamePrompt=Entrez ici le nom du pipeline
pipelineOptions.selectOperation=Sélectionner une opération
pipelineOptions.addOperationButton=Ajouter une opération
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Operation Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.selectOperation=Select Operation
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Télécharger
pipelineOptions.validateButton=Valider
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
@@ -148,7 +146,7 @@ adminUserSettings.role=Rôle
adminUserSettings.actions=Actions
adminUserSettings.apiUser=Utilisateur API limité
adminUserSettings.webOnlyUser=Utilisateur Web uniquement
adminUserSettings.demoUser=Demo User (Paramètres par défaut)
adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.forceChange=Forcer l\u2019utilisateur à changer son nom d\u2019utilisateur/mot de passe lors de la connexion
adminUserSettings.submit=Ajouter
@@ -160,7 +158,7 @@ home.searchBar=Rechercher des fonctionnalités...
home.viewPdf.title=Visionner le PDF
home.viewPdf.desc=Visionner, annoter, ajouter du texte ou des images.
home.viewPdf.desc=Visionner, annoter, ajouter du texte ou des images
viewPdf.tags=visualiser,lire,annoter,texte,image
home.multiTool.title=Outil multifonction PDF
@@ -169,7 +167,7 @@ multiTool.tags=outil multifonction,opération multifonction,interface utilisateu
home.merge.title=Fusionner
home.merge.desc=Fusionnez facilement plusieurs PDF en un seul.
merge.tags=fusionner,opérations sur les pages,backend,server side,merge
merge.tags=fusionner,opérations sur les pages,backeend,server side,merge
home.split.title=Diviser
home.split.desc=Divisez un PDF en plusieurs documents.
@@ -285,9 +283,9 @@ home.removeBlanks.title=Supprimer les pages vierges
home.removeBlanks.desc=Détectez et supprimez les pages vierges d\u2019un PDF.
removeBlanks.tags=pages vierges,supprimer,nettoyer,cleanup,streamline,non-content,organize
home.removeAnnotations.title=Supprimer les annotations
home.removeAnnotations.desc=Supprimer tous les commentaires/annotations d\u2019un PDF.
removeAnnotations.tags=commentaires,supprimer,annotations,highlight,notes,markup,remove
home.removeAnnotations.title=Remove Annotations
home.removeAnnotations.desc=Removes all comments/annotations from a PDF
removeAnnotations.tags=comments,highlight,notes,markup,remove
home.compare.title=Comparer
home.compare.desc=Comparez et visualisez les différences entre deux PDF.
@@ -371,7 +369,7 @@ home.autoRedact.desc=Caviardez automatiquement les informations sensibles d\u201
autoRedact.tags=caviarder,redact,auto
home.tableExtraxt.title=PDF en CSV
home.tableExtraxt.desc=Extrait les tableaux d\u2019un PDF et les transforme en CSV.
home.tableExtraxt.desc=Extrait les tableaux d\u2019un PDF et les transforme en CSV
tableExtraxt.tags=CSV,Table Extraction,extract,convert
@@ -381,16 +379,16 @@ autoSizeSplitPDF.tags=pdf,split,document,organization
home.overlay-pdfs.title=Incrustation de PDF
home.overlay-pdfs.desc=Incrustation d\u2019un PDF sur un autre PDF.
overlay-pdfs.tags=Overlay,incrustation
home.overlay-pdfs.desc=Incrustation d\u2019un PDF sur un autre PDF
overlay-pdfs.tags=Overlay
home.split-by-sections.title=Séparer un PDF en sections
home.split-by-sections.desc=Diviser chaque page d\u2019un PDF en sections horizontales/verticales plus petites.
split-by-sections.tags=Sections,Diviser,Section Split, Divide, Customize
home.split-by-sections.title=Split PDF by Sections
home.split-by-sections.desc=Divide each page of a PDF into smaller horizontal and vertical sections
split-by-sections.tags=Section Split, Divide, Customize
home.AddStampRequest.title=Ajouter un tampon sur un PDF
home.AddStampRequest.desc=Ajouter un texte ou l\u2019image d\u2019un tampon à un emplacement défini.
AddStampRequest.tags=Tampon,Ajouter,Stamp,Add image,center image,Watermark,PDF,Embed,Customize
home.AddStampRequest.title=Add Stamp to PDF
home.AddStampRequest.desc=Add text or add image stamps at set locations
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
###########################
@@ -468,37 +466,37 @@ HTMLToPDF.header=HTML en PDF
HTMLToPDF.help=Accepte les fichiers HTML et les ZIP contenant du HTML, du CSS, des images, etc. (requis).
HTMLToPDF.submit=Convertir
HTMLToPDF.credit=Utilise WeasyPrint.
HTMLToPDF.zoom=Niveau de zoom pour l\u2019affichage du site web.
HTMLToPDF.pageWidth=Largeur de la page en centimètres. (Vide par défaut)
HTMLToPDF.pageHeight=Hauteur de la page en centimètres. (Vide par défaut)
HTMLToPDF.marginTop=Marge supérieure de la page en millimètres. (Vide par défaut)
HTMLToPDF.marginBottom=Marge inférieure de la page en millimètres. (Vide par défaut)
HTMLToPDF.marginLeft=Marge gauche de la page en millimètres. (Vide par défaut)
HTMLToPDF.marginRight=Marge droite de la page en millimètres. (Vide par défaut)
HTMLToPDF.printBackground=Restituer l\u2019image de fond des sites web.
HTMLToPDF.defaultHeader=Activer l\u2019entête par défaut (Nom et numéro de page)
HTMLToPDF.cssMediaType=Modifier le type de média CSS de la page.
HTMLToPDF.none=Aucun
HTMLToPDF.print=Imprimer
HTMLToPDF.screen=Écran
HTMLToPDF.zoom=Zoom level for displaying the website.
HTMLToPDF.pageWidth=Width of the page in centimeters. (Blank to default)
HTMLToPDF.pageHeight=Height of the page in centimeters. (Blank to default)
HTMLToPDF.marginTop=Top margin of the page in millimeters. (Blank to default)
HTMLToPDF.marginBottom=Bottom margin of the page in millimeters. (Blank to default)
HTMLToPDF.marginLeft=Left margin of the page in millimeters. (Blank to default)
HTMLToPDF.marginRight=Right margin of the page in millimeters. (Blank to default)
HTMLToPDF.printBackground=Render the background of websites.
HTMLToPDF.defaultHeader=Enable Default Header (Name and page number)
HTMLToPDF.cssMediaType=Change the CSS media type of the page.
HTMLToPDF.none=None
HTMLToPDF.print=Print
HTMLToPDF.screen=Screen
#AddStampRequest
AddStampRequest.header=Tampon PDF
AddStampRequest.title=Tampon PDF
AddStampRequest.stampType=Type de tampon
AddStampRequest.stampText=Tampon texte
AddStampRequest.stampImage=Tampon image
AddStampRequest.header=Stamp PDF
AddStampRequest.title=Stamp PDF
AddStampRequest.stampType=Stamp Type
AddStampRequest.stampText=Stamp Text
AddStampRequest.stampImage=Stamp Image
AddStampRequest.alphabet=Alphabet
AddStampRequest.fontSize=Taille de fonte/image
AddStampRequest.fontSize=Font/Image Size
AddStampRequest.rotation=Rotation
AddStampRequest.opacity=Opacité
AddStampRequest.opacity=Opacity
AddStampRequest.position=Position
AddStampRequest.overrideX=Définir coordonnées X
AddStampRequest.overrideY=Définir coordonnées Y
AddStampRequest.customMargin=Marge personnalisée
AddStampRequest.customColor=Couleur de texte personnalisée
AddStampRequest.submit=Soumettre
AddStampRequest.overrideX=Override X Coordinate
AddStampRequest.overrideY=Override Y Coordinate
AddStampRequest.customMargin=Custom Margin
AddStampRequest.customColor=Custom Text Color
AddStampRequest.submit=Submit
#sanitizePDF
@@ -587,11 +585,11 @@ scalePages.submit=Ajuster
certSign.title=Signer avec un certificat
certSign.header=Signer avec un certificat (Travail en cours)
certSign.selectPDF=PDF à signer
certSign.jksNote=Note: Si votre type de certificat n\u2019est pas listé ci\u002Ddessous, merci de le convertir en fichier Java Keystore (.jks) en utilisant l\u2019outil en ligne de commande keytool. Puis choisissez l\u2019option Fichier .jks ci\u002Ddessous.
certSign.jksNote=Note: If your certificate type is not listed below, please convert it to a Java Keystore (.jks) file using the keytool command line tool. Then, choose the .jks file option below.
certSign.selectKey=Fichier de clé privée (format PKCS#8, peut être .pem ou .der)
certSign.selectCert=Fichier de certificat (format X.509, peut être .pem ou .der)
certSign.selectP12=Fichier keystore de clés PKCS#12 (.p12 ou .pfx) (facultatif, s\u2019il n\u2019est fourni, il doit contenir votre clé privée et votre certificat)
certSign.selectJKS=Sélectionner votre fichier Java Keystore File (.jks or .keystore):
certSign.selectJKS=Select Your Java Keystore File (.jks or .keystore):
certSign.certType=Type de certificat
certSign.password=Mot de passe keystore ou clé privée le cas échéant
certSign.showSig=Afficher la signature
@@ -612,9 +610,9 @@ removeBlanks.submit=Supprimer les pages vierges
#removeAnnotations
removeAnnotations.title=Supprimer les annotations
removeAnnotations.header=Supprimer les annotations
removeAnnotations.submit=Supprimer
removeAnnotations.title=Remove Annotations
removeAnnotations.header=Remove Annotations
removeAnnotations.submit=Remove
#compare
@@ -696,14 +694,14 @@ fileToPDF.submit=Convertir
#compress
compress.title=Compresser un PDF
compress.header=Compresser un PDF (lorsque c\u2019est possible!)
compress.title=Compresser
compress.header=Compresser
compress.credit=Ce service utilise Ghostscript pour la compression et l\u2019optimisation des PDF.
compress.selectText.1=Mode manuel \u2013 de 1 à 4
compress.selectText.2=Niveau d\u2019optimisation
compress.selectText.3=4 (terrible pour les images textuelles)
compress.selectText.4=Mode automatique \u2013 ajuste automatiquement la qualité pour obtenir le PDF à la taille exacte
compress.selectText.5=Taille PDF attendue (par exemple, 25\u202fMB, 10,8\u202fMB, 25\u202fKB)
compress.selectText.5=Taille PDF attendue (par exemple, 25\u202fMo, 10,8\u202fMo, 25\u202fKo)
compress.submit=Compresser
@@ -734,8 +732,8 @@ multiTool.title=Outil multifonction PDF
multiTool.header=Outil multifonction PDF
#view pdf
viewPdf.title=Visualiser un PDF
viewPdf.header=Visualiser un PDF
viewPdf.title=View PDF
viewPdf.header=View PDF
#pageRemover
pageRemover.title=Supprimer des pages
@@ -790,7 +788,7 @@ pdfToImage.multi=Plusieurs images
pdfToImage.colorType=Type d\u2019impression
pdfToImage.color=Couleur
pdfToImage.grey=Niveaux de gris
pdfToImage.blackwhite=Noir et blanc (peut engendrer une perte de données\u00a0!)
pdfToImage.blackwhite=Noir et blanc (peut engendre une perde de données\u00a0!)
pdfToImage.submit=Convertir
@@ -869,7 +867,7 @@ changeMetadata.keywords=Mots clés
changeMetadata.modDate=Date de modification (yyyy/MM/dd HH:mm:ss)
changeMetadata.producer=Producteur
changeMetadata.subject=Sujet
changeMetadata.trapped=Recouvrement (technique dimpression)
changeMetadata.trapped=Défoncé (technique dimpression)
changeMetadata.selectText.4=Autres métadonnées
changeMetadata.selectText.5=Ajouter une entrée de métadonnées personnalisée
changeMetadata.submit=Modifier
@@ -937,19 +935,19 @@ split-by-size-or-count.submit=Séparer
#overlay-pdfs
overlay-pdfs.header=Incrustation de PDF
overlay-pdfs.header=Overlay PDF Files
overlay-pdfs.baseFile.label=Sélectionner le fichier PDF de base
overlay-pdfs.overlayFiles.label=Sélectionner les fichiers PDF à superposer
overlay-pdfs.mode.label=Sélectionner le mode d\u2019incrustation
overlay-pdfs.mode.sequential=Superposition séquentielle
overlay-pdfs.mode.interleaved=Superposition entrelacée
overlay-pdfs.mode.label=Select Overlay Mode
overlay-pdfs.mode.sequential=Sequential Overlay
overlay-pdfs.mode.interleaved=Interleaved Overlay
overlay-pdfs.mode.fixedRepeat=Superposition à répétition fixe
overlay-pdfs.counts.label=Nombre de superpositions (pour le mode de répétition fixe)
overlay-pdfs.counts.placeholder=Compteurs (séparés par des virgules, exemple : 2,3,1)
overlay-pdfs.position.label=Définir la position de l\u2019incrustation
overlay-pdfs.counts.placeholder=Enter comma-separated counts (e.g., 2,3,1)
overlay-pdfs.position.label=Select Overlay Position
overlay-pdfs.position.foreground=Premier plan
overlay-pdfs.position.background=Arrière-plan
overlay-pdfs.submit=Soumettre
overlay-pdfs.submit=Submit
#split-by-sections
@@ -963,11 +961,11 @@ split-by-sections.submit=Diviser le PDF
#licenses
licenses.nav=Licences
licenses.title=Licences tierces
licenses.header=Licences tierces
licenses.nav=Licenses
licenses.title=3rd Party Licenses
licenses.header=3rd Party Licenses
licenses.module=Module
licenses.version=Version
licenses.license=Licence
licenses.license=License

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=छवियों का चयन करें
genericSubmit=प्रस्तुत करें
processTimeWarning=चेतावनी: यह प्रक्रिया फ़ाइल के आकार पर निर्भर करती है और यह से एक मिनट तक लग सकती है
pageOrderPrompt=कस्टम पेज क्रम (पेज नंबरों या 2n+1 जैसे कार्यों की एक कॉमा से अलग-अलग सूची दर्ज करें):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=जाएँ
true=सही
false=गलत
@@ -20,7 +19,6 @@ save=सहेजें
close=बंद करें
filesSelected=फ़ाइलें चयनित हैं
noFavourites=कोई पसंदीदा जोड़ा नहीं गया है
downloadComplete=Download Complete
bored=बोर हो रहे हैं?
alphabet=वर्णमाला
downloadPdf=पीडीएफ़ डाउनलोड करें

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Válasszon képeket
genericSubmit=Beküldés
processTimeWarning=Figyelmeztetés: Ez a folyamat akár egy percig is eltarthat a fájlmérettől függően
pageOrderPrompt=Egyedi oldalsorrend (Adjon meg vesszővel elválasztott oldalszámokat vagy függvényeket, például 2n+1):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Ugrás
true=Igaz
false=Hamis
@@ -20,7 +19,6 @@ save=Mentés
close=Bezárás
filesSelected=kiválasztott fájlok
noFavourites=Nincs hozzáadva kedvenc
downloadComplete=Download Complete
bored=Unatkozol?
alphabet=Ábécé
downloadPdf=PDF letöltése

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl=right to left)
@@ -11,7 +11,6 @@ imgPrompt=Pilih Gambar
genericSubmit=Kirim
processTimeWarning=Peringatan: Proses ini dapat memakan waktu hingga satu menit, tergantung pada ukuran berkas
pageOrderPrompt=Urutan Halaman Khusus (Masukkan daftar nomor halaman yang dipisahkan dengan koma atau Fungsi seperti 2n + 1) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Ke
true=Benar
false=Salah
@@ -20,7 +19,6 @@ save=Simpan
close=Tutup
filesSelected=berkas dipilih
noFavourites=Tidak ada favorit yang ditambahkan
downloadComplete=Download Complete
bored=Bosan Menunggu?
alphabet=Abjad
downloadPdf=Unduh PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Scegli immagine/i
genericSubmit=Invia
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) :
goToPage=Vai
true=Vero
false=Falso
@@ -20,7 +19,6 @@ save=Salva
close=Chiudi
filesSelected=file selezionati
noFavourites=Nessun preferito
downloadComplete=Download Complete
bored=Stanco di aspettare?
alphabet=Alfabeto
downloadPdf=Scarica PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=画像を選択
genericSubmit=送信
processTimeWarning=警告:この処理はファイルサイズによって1分程度かかることがあります
pageOrderPrompt=ページ順序 (ページ番号をカンマ区切り又は2n+1のような関数で入力):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=移動
true=True
false=False
@@ -20,7 +19,6 @@ save=保存
close=閉じる
filesSelected=選択されたファイル
noFavourites=お気に入りはありません
downloadComplete=Download Complete
bored=待ち時間が退屈
alphabet=\u30A2\u30EB\u30D5\u30A1\u30D9\u30C3\u30C8
downloadPdf=PDFをダウンロード
@@ -970,4 +968,3 @@ licenses.module=モジュール
licenses.version=バージョン
licenses.license=ライセンス

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=이미지 선택
genericSubmit=확인
processTimeWarning=경고: 파일 크기에 따라 1분 정도 소요될 수 있습니다
pageOrderPrompt=페이지 순서(쉼표로 구분된 페이지 번호 목록 입력):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=이동
true=
false=거짓
@@ -20,7 +19,6 @@ save=저장
close=닫기
filesSelected=개 파일 선택됨
noFavourites=즐겨찾기 없음
downloadComplete=Download Complete
bored=기다리는 게 지루하신가요?
alphabet=\uC54C\uD30C\uBCB3
downloadPdf=PDF 다운로드

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Selecteer afbeelding(en)
genericSubmit=Indienen
processTimeWarning=Waarschuwing: Dit proces kan tot een minuut duren afhankelijk van de bestandsgrootte
pageOrderPrompt=Aangepaste pagina volgorde (Voer een komma-gescheiden lijst van paginanummers of functies in, zoals 2n+1) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Ga
true=Waar
false=Onwaar
@@ -20,7 +19,6 @@ save=Opslaan
close=Sluiten
filesSelected=Bestanden geselecteerd
noFavourites=Geen favorieten toegevoegd
downloadComplete=Download Complete
bored=Verveeld met wachten?
alphabet=Alfabet
downloadPdf=Download PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Wybierz obraz(y)
genericSubmit=Wyślij
processTimeWarning=Ostrzeżenie: Ten proces może potrwać do minuty, w zależności od rozmiaru pliku
pageOrderPrompt=Kolejność stron (wprowadź listę numerów stron oddzielonych przecinkami) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Idź
true=Tak
false=Nie
@@ -20,7 +19,6 @@ save=Zapisz
close=Zamknij
filesSelected=wybrane pliki
noFavourites=Nie dodano ulubionych
downloadComplete=Download Complete
bored=Znudzony czekaniem?
alphabet=Alfabet
downloadPdf=Pobierz PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Selecione a(s) imagem(ns)
genericSubmit=Enviar
processTimeWarning=Aviso: esse processo pode levar até um minuto, dependendo do tamanho do arquivo
pageOrderPrompt=Ordem das páginas (digite uma lista separada por vírgulas de números de página):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Ir
true=Verdadeiro
false=Falso
@@ -20,7 +19,6 @@ save=Salvar
close=Fechar
filesSelected=arquivos selecionados
noFavourites=Nenhum favorito adicionado
downloadComplete=Download Complete
bored=Entediado esperando?
alphabet=Alfabeto
downloadPdf=baixar PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Selectează imagini
genericSubmit=Trimite
processTimeWarning=Avertisment: Acest proces poate dura până la un minut în funcție de dimensiunea fișierului
pageOrderPrompt=Ordinea paginilor (Introdu o listă separată prin virgulă de numere de pagină):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Mergi la pagină
true=Adevărat
false=Fals
@@ -20,7 +19,6 @@ save=Salvează
close=Închide
filesSelected=fișiere selectate
noFavourites=Niciun favorit adăugat
downloadComplete=Download Complete
bored=Plictisit așteptând?
alphabet=Alfabet
downloadPdf=Descarcă PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Выберите картинку(и)
genericSubmit=Отправить
processTimeWarning=Внимание: Этот процесс может занять до минуты в зависимости от размера файла.
pageOrderPrompt=Порядок страниц (введите список номеров страниц через запятую):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Вперед
true=Истина
false=Ложь
@@ -20,7 +19,6 @@ save=Сохранить
close=Закрыть
filesSelected=файлов выбрано
noFavourites=Нет избранного
downloadComplete=Download Complete
bored=Скучно ждать?
alphabet=Алфавит
downloadPdf=Скачать PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Odaberi sliku (slike)
genericSubmit=Prihvatiti
processTimeWarning=Warning:Upozorenje: Ovaj proces može trajati i do minut, u zavisnosti od veličine dokumenta
pageOrderPrompt=Prilagođeni redosled stranica (unesi listu brojeva stranica ili funkcija, kao što su 2n+1, razdvojene zarezima) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Idi
true=Tačno
false=Netačno
@@ -20,7 +19,6 @@ save=Sačuvaj
close=Zatvori
filesSelected=odabrani fajlovi
noFavourites=Nema dodatih favorita
downloadComplete=Download Complete
bored=Da li ti je dosadno dok čekaš?
alphabet=Alfabet
downloadPdf=Skini PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Välj bild(er)
genericSubmit=Skicka
processTimeWarning=Varning: Denna process kan ta upp till en minut beroende på filstorlek
pageOrderPrompt=Sidordning (Ange en kommaseparerad lista med sidnummer) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Gå till
true=True
false=Falskt
@@ -20,7 +19,6 @@ save=Spara
close=Stäng
filesSelected=filer valda
noFavourites=Inga favoriter har lagts till
downloadComplete=Download Complete
bored=Utråkad att vänta?
alphabet=Alfabet
downloadPdf=Ladda ner PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=Resim(leri) seçin
genericSubmit=Gönder
processTimeWarning=Uyarı: Bu işlem, dosya boyutuna bağlı olarak bir dakikaya kadar sürebilir.
pageOrderPrompt=Özel Sayfa Sırası (Virgülle ayrılmış sayfa numaraları veya 2n+1 gibi bir fonksiyon girin) :
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=Git
true=Doğru
false=Yanlış
@@ -20,7 +19,6 @@ save=Kaydet
close=Kapat
filesSelected=dosya seçildi
noFavourites=Favori eklenmedi
downloadComplete=Download Complete
bored=Sıkıldınız mı?
alphabet=Alfabe
downloadPdf=PDF İndir

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=选择图像
genericSubmit=提交
processTimeWarning=警告:此过程可能需要多达一分钟,具体时间取决于文件大小
pageOrderPrompt=页面顺序(输入逗号分隔的页码列表):
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=
true=
false=
@@ -20,7 +19,6 @@ save=保存
close=关闭
filesSelected=选中的文件
noFavourites=没有添加收藏夹
downloadComplete=Download Complete
bored=无聊等待吗?
alphabet=字母表
downloadPdf=下载PDF

View File

@@ -1,4 +1,4 @@
###########
###########
# Generic #
###########
# the direction that the language is written (ltr=left to right, rtl = right to left)
@@ -11,7 +11,6 @@ imgPrompt=選擇圖片
genericSubmit=送出
processTimeWarning=警告:此過程可能需要長達一分鐘,具體取決於檔案大小
pageOrderPrompt=自訂頁面順序(輸入以逗號分隔的頁碼或函式,如 2n+1
pageSelectionPrompt=Custom Page Selection (Enter a comma-separated list of page numbers 1,5,6 or Functions like 2n+1) :
goToPage=前往
true=
false=
@@ -20,7 +19,6 @@ save=儲存
close=關閉
filesSelected=已選擇的檔案
noFavourites=未新增收藏
downloadComplete=Download Complete
bored=等待時覺得無聊?
alphabet=字母表
downloadPdf=下載 PDF

View File

@@ -7,15 +7,15 @@ security:
csrfDisabled: true
loginAttemptCount: 5 # lock user account after 5 tries
loginResetTimeMinutes : 120 # lock account for 2 hours after x attempts
system:
defaultLocale: 'en-US' # Set the default language (e.g. 'de-DE', 'fr-FR', etc)
googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow
enableAlphaFunctionality: false # Set to enable functionality which might need more testing before it fully goes live (This feature might make no changes)
customApplications:
bookAndHtmlFormatsInstalled: false # Installs Calibre for book format conversion (For non docker it must be manually downloaded but will need to be true to show in UI)
#ui:
# appName: exampleAppName # Application's visible name
# homeDescription: I am a description # Short description or tagline shown on homepage.

View File

@@ -1,4 +0,0 @@
.buttons-container {
margin-top: 20px;
text-align: center;
}

View File

@@ -1,28 +0,0 @@
#box-drag-container {
position: relative;
margin: 20px 0;
}
#pdf-canvas {
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
width: 100%;
}
.draggable-buttons-box {
position: absolute;
top: 0;
padding: 10px;
width: 100%;
display: flex;
gap: 5px;
}
.draggable-buttons-box > button {
z-index: 10;
background-color: rgba(13, 110, 253, 0.1);
}
.draggable-canvas {
border: 1px solid red;
position: absolute;
touch-action: none;
user-select: none;
top: 0px;
left: 0;
}

View File

@@ -1,141 +1,135 @@
/* Dark Mode Styles */
body,
select,
textarea {
--body-background-color: 51, 51, 51;
--base-font-color: 255, 255, 255;
background-color: rgb(var(--body-background-color)) !important;
color: rgb(var(--base-font-color)) !important;
}
.card {
background-color: rgb(var(--body-background-color)) !important;
border: 1px solid #999;
color: rgb(var(--base-font-color)) !important;
}
a {
color: #add8e6;
}
a:hover {
color: #87ceeb; /* Slightly brighter blue on hover for accessibility */
}
.dark-card {
background-color: rgb(var(--body-background-color)) !important;
color: rgb(var(--base-font-color)) !important;
}
.jumbotron {
background-color: #222; /* or any other dark color */
color: rgb(var(--base-font-color)) !important; /* or any other light color */
}
.list-group {
background-color: #222 !important;
color: rgb(var(--base-font-color)) !important;
}
.list-group-item {
background-color: #222 !important;
color: rgb(var(--base-font-color)) !important;
}
#support-section {
background-color: #444 !important;
}
#pages-container-wrapper {
--background-color: rgba(255, 255, 255, 0.046) !important;
--scroll-bar-color: #4c4c4c !important;
--scroll-bar-thumb: #d3d3d3 !important;
--scroll-bar-thumb-hover: rgb(var(--base-font-color)) !important;
}
.favorite-icon img {
filter: brightness(0) invert(1) !important;
}
table thead {
background-color: #333 !important;
border: 1px solid #444;
}
table th,
table td {
border: 1px solid #444 !important;
color: white;
}
.btn {
background-color: #444 !important;
border: none;
color: #fff !important;
}
.btn-primary {
background-color: #007bff !important;
border: none;
color: #fff !important;
}
.btn-secondary {
background-color: #6c757d !important;
border: none;
color: #fff !important;
}
.btn-info {
background-color: #17a2b8 !important;
border: none;
color: #fff !important;
}
.btn-danger {
background-color: #dc3545 !important;
border: none;
color: #fff !important;
}
.btn-warning {
background-color: #ffc107 !important;
border: none;
color: #000 !important;
}
.btn-outline-secondary {
color: #fff !important;
border-color: #fff;
}
.btn-outline-secondary:hover {
background-color: #444 !important;
color: #007bff !important;
border-color: #007bff;
}
.blackwhite-icon {
filter: brightness(0) invert(1);
}
hr {
border-color: rgba(255, 255, 255, 0.6); /* semi-transparent white */
background-color: rgba(255, 255, 255, 0.6); /* for some browsers that might use background instead of border for <hr> */
}
.modal-content {
color: #fff !important;
border-color: #fff;
}
#global-buttons-container input {
background-color: #323948;
caret-color: #ffffff;
color: #ffffff;
}
#global-buttons-container input::placeholder {
color: #ffffff;
}
#global-buttons-container input:disabled::-webkit-input-placeholder {
/* WebKit browsers */
color: #6e6865;
}
#global-buttons-container input:disabled:-moz-placeholder {
/* Mozilla Firefox 4 to 18 */
color: #6e6865;
}
#global-buttons-container input:disabled::-moz-placeholder {
/* Mozilla Firefox 19+ */
color: #6e6865;
}
#global-buttons-container input:disabled:-ms-input-placeholder {
/* Internet Explorer 10+ */
color: #6e6865;
}
/* Dark Mode Styles */
body, select, textarea {
--body-background-color: 51, 51, 51;
--base-font-color: 255, 255, 255;
background-color: rgb(var(--body-background-color)) !important;
color: rgb(var(--base-font-color)) !important;
}
.card {
background-color: rgb(var(--body-background-color)) !important;
border: 1px solid #999;
color: rgb(var(--base-font-color)) !important;
}
a {
color: #add8e6;
}
a:hover {
color: #87ceeb; /* Slightly brighter blue on hover for accessibility */
}
.dark-card {
background-color: rgb(var(--body-background-color)) !important;
color: rgb(var(--base-font-color)) !important;
}
.jumbotron {
background-color: #222; /* or any other dark color */
color: rgb(var(--base-font-color)) !important; /* or any other light color */
}
.list-group {
background-color: #222 !important;
color: rgb(var(--base-font-color)) !important;
}
.list-group-item {
background-color: #222 !important;
color: rgb(var(--base-font-color)) !important;
}
#support-section {
background-color: #444 !important;
}
#pages-container-wrapper {
--background-color: rgba(255, 255, 255, 0.046) !important;
--scroll-bar-color: #4c4c4c !important;
--scroll-bar-thumb: #d3d3d3 !important;
--scroll-bar-thumb-hover: rgb(var(--base-font-color)) !important;
}
.favorite-icon img {
filter: brightness(0) invert(1) !important;
}
table thead {
background-color: #333 !important;
border: 1px solid #444;
}
table th, table td {
border: 1px solid #444 !important;
color: white;
}
.btn {
background-color: #444 !important;
border: none;
color: #fff !important;
}
.btn-primary {
background-color: #007bff !important;
border: none;
color: #fff !important;
}
.btn-secondary {
background-color: #6c757d !important;
border: none;
color: #fff !important;
}
.btn-info {
background-color: #17a2b8 !important;
border: none;
color: #fff !important;
}
.btn-danger {
background-color: #dc3545 !important;
border: none;
color: #fff !important;
}
.btn-warning {
background-color: #ffc107 !important;
border: none;
color: #000 !important;
}
.btn-outline-secondary {
color: #fff !important;
border-color: #fff;
}
.btn-outline-secondary:hover {
background-color: #444 !important;
color: #007bff !important;
border-color: #007bff;
}
.blackwhite-icon {
filter: brightness(0) invert(1);
}
hr {
border-color: rgba(255, 255, 255, 0.6); /* semi-transparent white */
background-color: rgba(255, 255, 255, 0.6); /* for some browsers that might use background instead of border for <hr> */
}
.modal-content {
color: #fff !important;
border-color: #fff;
}
#global-buttons-container input {
background-color: #323948;
caret-color: #ffffff;
color: #ffffff;
}
#global-buttons-container input::placeholder {
color: #ffffff;
}
#global-buttons-container input:disabled::-webkit-input-placeholder { /* WebKit browsers */
color: #6E6865;
}
#global-buttons-container input:disabled:-moz-placeholder { /* Mozilla Firefox 4 to 18 */
color: #6E6865;
}
#global-buttons-container input:disabled::-moz-placeholder { /* Mozilla Firefox 19+ */
color: #6E6865;
}
#global-buttons-container input:disabled:-ms-input-placeholder { /* Internet Explorer 10+ */
color: #6E6865;
}

View File

@@ -1,78 +1,78 @@
#drag-container {
position: fixed;
display: flex;
inset: 0;
pointer-events: none;
z-index: 10000;
visibility: hidden;
position: fixed;
display:flex;
inset: 0;
pointer-events: none;
z-index: 10000;
visibility: hidden;
}
#drag-container:not(:empty) {
visibility: visible;
visibility: visible;
}
#drag-container .dragged-img {
position: fixed;
max-width: 200px;
max-height: 200px;
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.58);
transform-origin: top left;
position: fixed;
max-width: 200px;
max-height: 200px;
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.58);
transform-origin: top left;
}
.drag-manager_dragging {
width: 0px;
visibility: hidden;
width: 0px;
visibility: hidden;
}
.drag-manager_draghover {
width: 375px !important;
width: 375px !important;
}
.drag-manager_draghover .insert-file-button-container {
display: none !important;
display: none !important;
}
.drag-manager_draghover .button-container {
visibility: hidden !important;
visibility: hidden !important;
}
html[lang-direction="ltr"] .drag-manager_draghover img {
left: calc(50% + 62.5px) !important;
html[lang-direction=ltr] .drag-manager_draghover img {
left: calc(50% + 62.5px) !important;
}
html[lang-direction="rtl"] .drag-manager_draghover img {
left: 125px;
html[lang-direction=rtl] .drag-manager_draghover img {
left: 125px
}
.drag-manager_dragging-container .hide-on-drag {
display: none !important;
display: none !important;
}
.drag-manager_endpoint {
width: 80px;
height: 100%;
background-color: #ffffff10;
transition: width 0.1s;
animation: end-drop-expand 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
width: 80px;
height: 100%;
background-color: #FFFFFF10;
transition: width 0.1s;
animation: end-drop-expand .3s ease;
display: flex;
align-items: center;
justify-content: center;
}
.drag-manager_endpoint svg {
width: 50px;
height: 50px;
width: 50px;
height: 50px;
}
.drag-manager_endpoint.drag-manager_draghover {
width: 150px !important;
width: 150px !important;
}
@keyframes end-drop-expand {
from {
width: 0;
}
to {
width: 80px;
}
}
from {
width: 0;
}
to {
width: 80px;
}
}

View File

@@ -1,88 +0,0 @@
h1 {
text-align: center;
margin-top: 10%;
}
p {
text-align: center;
margin-top: 2em;
}
.button:hover {
background-color: #005b7f;
}
.features-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr));
gap: 25px 30px;
}
.feature-card {
border: 1px solid rgba(0, 0, 0, 0.125);
border-radius: 0.25rem;
padding: 1.25rem;
display: flex;
flex-direction: column;
align-items: flex-start;
}
.feature-card .card-text {
flex: 1;
}
#support-section {
background-color: #f9f9f9;
padding: 4rem;
margin-top: 1rem;
text-align: center;
}
#support-section h1 {
margin-top: 0;
}
#support-section p {
margin-top: 0;
}
#button-group {
display: flex;
justify-content: center;
flex-wrap: wrap;
}
#github-button,
#discord-button {
display: inline-block;
padding: 1rem 2rem;
margin: 1rem;
background-color: #008cba;
color: #fff;
font-size: 1.2rem;
text-align: center;
text-decoration: none;
border-radius: 3rem;
transition: all 0.3s ease-in-out;
}
#github-button:hover,
#discord-button:hover,
#home-button:hover {
background-color: #005b7f;
}
#home-button {
display: block;
width: 200px;
height: 50px;
margin: 2em auto;
background-color: #008cba;
color: white;
text-align: center;
line-height: 50px;
text-decoration: none;
font-weight: bold;
border-radius: 25px;
transition: all 0.3s ease-in-out;
}

View File

@@ -1,97 +1,94 @@
#errorContainer {
margin: 20px; /* adjust this value as needed */
margin: 20px; /* adjust this value as needed */
}
#helpModalDialog {
width: 90%;
max-width: 800px;
width: 90%;
max-width: 800px;
}
#helpModal h1 {
text-align: center;
margin-top: 10%;
text-align: center;
margin-top: 10%;
}
#helpModal p {
text-align: center;
margin-top: 2em;
text-align: center;
margin-top: 2em;
}
#helpModal .button:hover {
background-color: #005b7f;
background-color: #005b7f;
}
#helpModal .features-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr));
gap: 25px 30px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr));
gap: 25px 30px;
}
#helpModal .feature-card {
border: 1px solid rgba(0, 0, 0, 0.125);
border-radius: 0.25rem;
padding: 1.25rem;
display: flex;
flex-direction: column;
align-items: flex-start;
border: 1px solid rgba(0, 0, 0, .125);
border-radius: 0.25rem;
padding: 1.25rem;
display: flex;
flex-direction: column;
align-items: flex-start;
}
#helpModal .feature-card .card-text {
flex: 1;
flex: 1;
}
#support-section {
background-color: #f9f9f9;
padding: 4rem;
margin-top: 1rem;
text-align: center;
background-color: #f9f9f9;
padding: 4rem;
margin-top: 1rem;
text-align: center;
}
#support-section h1 {
margin-top: 0;
margin-top: 0;
}
#support-section p {
margin-top: 0;
margin-top: 0;
}
#button-group {
display: flex;
justify-content: center;
flex-wrap: wrap;
display: flex;
justify-content: center;
flex-wrap: wrap;
}
#github-button,
#discord-button {
display: inline-block;
padding: 1rem 2rem;
margin: 1rem;
background-color: #008cba;
color: #fff;
font-size: 1.2rem;
text-align: center;
text-decoration: none;
border-radius: 3rem;
transition: all 0.3s ease-in-out;
#github-button, #discord-button {
display: inline-block;
padding: 1rem 2rem;
margin: 1rem;
background-color: #008CBA;
color: #fff;
font-size: 1.2rem;
text-align: center;
text-decoration: none;
border-radius: 3rem;
transition: all 0.3s ease-in-out;
}
#github-button:hover,
#discord-button:hover,
#home-button:hover {
background-color: #005b7f;
#github-button:hover, #discord-button:hover, #home-button:hover {
background-color: #005b7f;
}
#home-button {
display: block;
width: 200px;
height: 50px;
margin: 2em auto;
background-color: #008cba;
color: white;
text-align: center;
line-height: 50px;
text-decoration: none;
font-weight: bold;
border-radius: 25px;
transition: all 0.3s ease-in-out;
}
display: block;
width: 200px;
height: 50px;
margin: 2em auto;
background-color: #008CBA;
color: white;
text-align: center;
line-height: 50px;
text-decoration: none;
font-weight: bold;
border-radius: 25px;
transition: all 0.3s ease-in-out;
}

View File

@@ -1,10 +1,10 @@
.custom-file-label {
padding-right: 90px;
padding-right: 90px;
}
.selected-files {
margin-top: 10px;
max-height: 150px;
overflow-y: auto;
white-space: pre-wrap;
}
margin-top: 10px;
max-height: 150px;
overflow-y: auto;
white-space: pre-wrap;
}

View File

@@ -1,20 +0,0 @@
#footer {
display: flex;
flex-direction: column; /* Stack children vertically */
justify-content: center;
align-items: center;
width: 100%;
}
.footer-center {
display: flex;
align-items: center; /* Center children horizontally */
flex-grow: 1;
}
.footer-powered-by {
margin-top: auto; /* Pushes the text to the bottom */
color: grey;
text-align: center; /* Centers the text inside the div */
width: 100%; /* Full width to center the text properly */
}

View File

@@ -1,54 +1,49 @@
#game-container {
position: relative;
width: 100vh;
height: 0;
padding-bottom: 75%; /* 4:3 aspect ratio */
background-color: transparent;
margin: auto;
overflow: hidden;
border: 2px solid black; /* Add border */
position: relative;
width: 100vh;
height: 0;
padding-bottom: 75%; /* 4:3 aspect ratio */
background-color: transparent;
margin: auto;
overflow: hidden;
border: 2px solid black; /* Add border */
}
.pdf,
.player,
.projectile {
position: absolute;
.pdf, .player, .projectile {
position: absolute;
}
.pdf {
width: 50px;
height: 50px;
width: 50px;
height: 50px;
}
.player {
width: 50px;
height: 50px;
width: 50px;
height: 50px;
}
.projectile {
background-color: black !important;
width: 5px;
height: 10px;
background-color: black !important;
width: 5px;
height: 10px;
}
#score,
#level,
#lives,
#high-score {
color: black;
font-family: sans-serif;
position: absolute;
font-size: calc(14px + 0.25vw); /* Reduced font size */
#score, #level, #lives, #high-score {
color: black;
font-family: sans-serif;
position: absolute;
font-size: calc(14px + 0.25vw); /* Reduced font size */
}
#score {
top: 10px;
left: 10px;
top: 10px;
left: 10px;
}
#lives {
top: 10px;
left: calc(9vw); /* Adjusted position */
top: 10px;
left: calc(7vw); /* Adjusted position */
}
#high-score {
top: 10px;
left: calc(14vw); /* Adjusted position */
top: 10px;
left: calc(14vw); /* Adjusted position */
}
#level {
top: 10px;
right: 10px;
}
top: 10px;
right: 10px;
}

View File

@@ -1,94 +1,94 @@
#page-container {
min-height: 100vh;
display: flex;
flex-direction: column;
}
#content-wrap {
flex: 1;
}
#footer {
bottom: 0;
width: 100%;
}
.navbar {
height: auto; /* Adjusts height automatically based on content */
white-space: nowrap; /* Prevents wrapping of navbar contents */
}
/* TODO enable later
.navbar .container {
max-width: 100%; //Allows the container to expand up to full width
margin-left: auto;
margin-right: auto;
}*/
html[lang-direction="ltr"] * {
direction: ltr;
}
html[lang-direction="rtl"] * {
direction: rtl;
text-align: right;
}
.ignore-rtl {
direction: ltr !important;
text-align: left !important;
}
.align-top {
position: absolute;
top: 0;
}
.align-center-right {
position: absolute;
right: 0;
top: 50%;
}
.align-center-left {
position: absolute;
left: 0;
top: 50%;
}
.align-bottom {
position: absolute;
bottom: 0;
}
.btn-group > label:first-of-type {
border-top-left-radius: 0.25rem !important;
border-bottom-left-radius: 0.25rem !important;
}
html[lang-direction="rtl"] input.form-check-input {
position: relative;
margin-left: 0px;
}
html[lang-direction="rtl"] label.form-check-label {
display: inline;
}
.margin-auto-parent {
width: 100%;
display: flex;
}
.margin-center {
margin: 0 auto;
}
#pdf-canvas {
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
width: 100%;
}
.fixed-shadow-canvas {
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
width: 100%;
}
.shadow-canvas {
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
}
.hidden {
display: none;
}
#page-container {
min-height: 100vh;
display: flex;
flex-direction: column;
}
#content-wrap {
flex: 1;
}
#footer {
bottom: 0;
width: 100%;
}
.navbar {
height: auto; /* Adjusts height automatically based on content */
white-space: nowrap; /* Prevents wrapping of navbar contents */
}
/* TODO enable later
.navbar .container {
max-width: 100%; //Allows the container to expand up to full width
margin-left: auto;
margin-right: auto;
}*/
html[lang-direction=ltr] * {
direction: ltr;
}
html[lang-direction=rtl] * {
direction: rtl;
text-align: right;
}
.ignore-rtl {
direction: ltr !important;
text-align: left !important;
}
.align-top {
position: absolute;
top: 0;
}
.align-center-right {
position: absolute;
right: 0;
top: 50%;
}
.align-center-left {
position: absolute;
left: 0;
top: 50%;
}
.align-bottom {
position: absolute;
bottom: 0;
}
.btn-group > label:first-of-type {
border-top-left-radius: 0.25rem !important;
border-bottom-left-radius: 0.25rem !important;
}
html[lang-direction="rtl"] input.form-check-input {
position: relative;
margin-left: 0px;
}
html[lang-direction="rtl"] label.form-check-label {
display: inline;
}
.margin-auto-parent {
width: 100%;
display: flex;
}
.margin-center {
margin: 0 auto;
}
#pdf-canvas {
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
width: 100%;
}
.fixed-shadow-canvas {
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
width: 100%;
}
.shadow-canvas {
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
}
.hidden {
display: none;
}

View File

@@ -1,62 +1,64 @@
#searchBar {
background-image: url("../images/search.svg");
background-position: 16px 16px;
background-repeat: no-repeat;
width: 100%;
font-size: 16px;
margin-bottom: 12px;
padding: 12px 20px 12px 40px;
border: 1px solid #ddd;
background-image: url('../images/search.svg');
background-position: 16px 16px;
background-repeat: no-repeat;
width: 100%;
font-size: 16px;
margin-bottom: 12px;
padding: 12px 20px 12px 40px;
border: 1px solid #ddd;
}
.dark-mode-search {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' hei… 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z'/%3E%3C/svg%3E") !important;
color: #f8f9fa !important;
background-color: #212529 !important;
border-color: #343a40 !important;
}
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' hei… 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z'/%3E%3C/svg%3E") !important;
color: #f8f9fa !important;
background-color: #212529 !important;
border-color: #343a40 !important;
}
.features-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(15rem, 3fr));
gap: 25px 30px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(15rem, 3fr));
gap: 25px 30px;
}
.feature-card {
border: 2px solid rgba(0, 0, 0, 0.25);
border-radius: 0.25rem;
padding: 1.25rem;
display: flex;
flex-direction: column;
align-items: flex-start;
background: rgba(13, 110, 253, 0.05);
transition:
transform 0.3s,
border 0.3s;
transform-origin: center center;
outline: 2px solid transparent;
border: 2px solid rgba(0, 0, 0, .25);
border-radius: 0.25rem;
padding: 1.25rem;
display: flex;
flex-direction: column;
align-items: flex-start;
background: rgba(13, 110, 253, 0.05);
transition: transform 0.3s, border 0.3s;
transform-origin: center center;
outline: 2px solid transparent;
}
.feature-card a {
text-decoration: none;
color: inherit;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
text-decoration: none;
color: inherit;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
.feature-card .card-text {
flex: 1;
flex: 1;
}
.feature-card:hover {
outline: 1px solid rgba(0, 0, 0, 0.5);
cursor: pointer;
transform: scale(1.1);
outline: 1px solid rgba(0, 0, 0, .5);
cursor: pointer;
transform: scale(1.1);
}
.feature-card:hover .card-title {
text-decoration: underline;
text-decoration: underline;
}
.card-title.text-primary {
color: #000; /* Replace with your desired shade of blue */
@@ -65,27 +67,27 @@
.home-card-icon {
width: 30px;
height: 30px;
transform: translateY(-5px);
transform: translateY(-5px);
}
.home-card-icon-colour {
filter: invert(0.2) sepia(2) saturate(50) hue-rotate(190deg);
filter: invert(0.2) sepia(2) saturate(50) hue-rotate(190deg);
}
.favorite-icon {
display: none;
position: absolute;
top: 10px;
right: 10px;
display: none;
position: absolute;
top: 10px;
right: 10px;
}
/* Only show the favorite icons when the parent card is being hovered over */
.feature-card:hover .favorite-icon {
display: block;
display: block;
}
.favorite-icon img {
filter: brightness(0);
filter: brightness(0);
}
.jumbotron {
padding: 3rem 3rem; /* Reduce vertical padding */
padding: 3rem 3rem; /* Reduce vertical padding */
}

View File

@@ -1,43 +1,40 @@
#image-highlighter {
position: fixed;
display: flex;
inset: 0;
z-index: 10000;
background-color: rgba(0, 0, 0, 0);
visibility: hidden;
align-items: center;
justify-content: center;
transition:
visbility 0.1s linear,
background-color 0.1s linear;
position: fixed;
display:flex;
inset: 0;
z-index: 10000;
background-color: rgba(0, 0, 0, 0);
visibility: hidden;
align-items: center;
justify-content: center;
transition: visbility 0.1s linear, background-color 0.1s linear;
}
#image-highlighter > * {
max-width: 80vw;
max-height: 80vh;
animation: image-highlight 0.1s linear;
transition:
transform 0.1s linear,
opacity 0.1s linear;
max-width: 80vw;
max-height: 80vh;
animation: image-highlight .1s linear;
transition: transform .1s linear, opacity .1s linear;
}
#image-highlighter > *.remove {
transform: scale(0.8) !important;
opacity: 0 !important;
transform: scale(0.8) !important;
opacity: 0 !important;
}
#image-highlighter:not(:empty) {
background-color: rgba(0, 0, 0, 0.37);
visibility: visible;
background-color: rgba(0, 0, 0, 0.37);
visibility: visible;
}
@keyframes image-highlight {
from {
transform: scale(0.8);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
from {
transform: scale(0.8);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}

View File

@@ -1,9 +0,0 @@
td a {
text-decoration: none;
}
td a:hover,
td a:focus {
text-decoration: underline;
/* Adds underline on hover/focus for clarity */
}

View File

@@ -1,13 +1,14 @@
/* Dark Mode Styles */
body {
--body-background-color: 255, 255, 255;
--base-font-color: 33, 37, 41;
--body-background-color: 255, 255, 255;
--base-font-color: 33, 37, 41;
}
#global-buttons-container input {
background-color: #ffffff;
/*caret-color: #ffffff;*/
/*color: #ffffff;*/
background-color: #ffffff;
/*caret-color: #ffffff;*/
/*color: #ffffff;*/
}
/*#global-buttons-container input:disabled::-webkit-input-placeholder { !* WebKit browsers *!*/
/* color: #98A0AB;*/

View File

@@ -1,111 +0,0 @@
html,
body {
height: 100%;
}
body {
display: flex;
align-items: center;
padding-top: 40px;
padding-bottom: 40px;
background-color: #f5f5f5;
}
.form-signin {
width: 100%;
max-width: 330px;
padding: 15px;
margin: auto;
}
.form-signin .checkbox {
font-weight: 400;
}
.form-signin .form-floating:focus-within {
z-index: 2;
}
.form-signin input[type="text"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.container-flex {
display: flex;
flex-direction: column;
min-height: 100vh;
width: 100%; /* Set width to 100% */
align-items: center; /* Center its children horizontally */
}
.footer-bottom {
margin-top: auto;
}
body.light-mode input:-webkit-autofill,
body.light-mode input:-webkit-autofill:hover,
body.light-mode input:-webkit-autofill:focus,
body.light-mode input:-webkit-autofill:active {
-webkit-text-fill-color: #212529; /* Dark font color */
-webkit-box-shadow: 0 0 0 1000px #f8f9fa inset; /* Light background color */
}
/* Dark Mode */
body.dark-mode input:-webkit-autofill,
body.dark-mode input:-webkit-autofill:hover,
body.dark-mode input:-webkit-autofill:focus,
body.dark-mode input:-webkit-autofill:active {
-webkit-text-fill-color: #f8f9fa; /* Light font color */
-webkit-box-shadow: 0 0 0 1000px #212529 inset; /* Dark background color */
}
/* Light Mode */
body.light-mode .form-floating > input:focus + label {
color: #212529 !important; /* Dark text for light background */
}
/* Dark Mode */
body.dark-mode .form-floating > input:focus + label {
color: #fff !important; /* Light text for dark background */
}
body.light-mode .form-floating > label {
color: #212529 !important; /* Dark text for light background */
}
body.dark-mode .form-floating > label {
color: #fff !important; /* Light text for dark background */
}
/* Removing default styles for ul and li */
ul {
list-style: none;
padding: 0;
margin: 0;
}
li {
list-style: none;
}
/* Positioning the container of these elements to the top right */
.your-container-class {
position: absolute;
top: 0;
right: 0;
display: flex;
}
/* Styling for the dropdown */
.dropdown-menu {
min-width: 200px; /* or whatever width you prefer */
}
.navbar-icon {
width: 40px;
height: 40px;
}

View File

@@ -1,28 +1,29 @@
.list-group-item {
display: flex;
justify-content: space-between;
align-items: center;
}
.filename {
flex-grow: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 10px;
}
.arrows {
flex-shrink: 0;
display: flex;
justify-content: flex-end;
}
.arrows .btn {
margin: 0 3px;
}
.move-up span,
.move-down span {
font-weight: bold;
font-size: 1.2em;
}
.list-group-item {
display: flex;
justify-content: space-between;
align-items: center;
}
.filename {
flex-grow: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 10px;
}
.arrows {
flex-shrink: 0;
display: flex;
justify-content: flex-end;
}
.arrows .btn {
margin: 0 3px;
}
.move-up span,
.move-down span {
font-weight: bold;
font-size: 1.2em;
}

View File

@@ -1,119 +0,0 @@
.multi-tool-container {
max-width: 95vw;
margin: 0 auto;
}
#global-buttons-container {
display: flex;
gap: 10px;
align-items: start;
background-color: rgba(13, 110, 253, 0.1);
border: 1px solid rgba(0, 0, 0, 0.25);
backdrop-filter: blur(2px);
top: 10px;
z-index: 10;
padding: 10px;
border-radius: 8px;
}
#global-buttons-container > * {
padding: 0.6rem 0.75rem;
}
#global-buttons-container svg {
width: 20px;
height: 20px;
}
#export-button {
margin-left: auto;
}
#pages-container-wrapper {
--background-color: rgba(0, 0, 0, 0.025);
--scroll-bar-color: #f1f1f1;
--scroll-bar-thumb: #888;
--scroll-bar-thumb-hover: #555;
background-color: var(--background-color);
width: 100%;
display: flex;
flex-direction: column;
padding: 10px 25px;
border-radius: 10px;
overflow-y: hidden;
overflow-x: auto;
min-height: 275px;
margin: 0 0 30px 0;
}
#pages-container {
margin: auto;
gap: 0px;
display: flex;
align-items: center;
justify-content: center;
}
/* width */
#pages-container-wrapper::-webkit-scrollbar {
width: 10px;
height: 10px;
}
/* Track */
#pages-container-wrapper::-webkit-scrollbar-track {
background: var(--scroll-bar-color);
}
/* Handle */
#pages-container-wrapper::-webkit-scrollbar-thumb {
border-radius: 10px;
background: var(--scroll-bar-thumb);
}
/* Handle on hover */
#pages-container-wrapper::-webkit-scrollbar-thumb:hover {
background: var(--scroll-bar-thumb-hover);
}
.page-container {
height: 250px;
display: flex;
align-items: center;
flex-direction: column-reverse;
aspect-ratio: 1;
text-align: center;
position: relative;
user-select: none;
transition: width 1s linear;
}
.page-container img {
/* max-width: calc(100% - 15px); */
max-height: calc(100% - 15px);
max-width: 237px;
display: block;
position: absolute;
left: 50%;
top: 50%;
translate: -50% -50%;
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
border-radius: 4px;
transition: rotate 0.3s;
}
#add-pdf-button {
margin: 0 auto;
}
.page-number {
position: absolute;
top: 5px;
right: 5px;
color: white;
background-color: #007bff; /* Primary blue color */
padding: 3px 6px;
border-radius: 4px;
font-size: 12px;
z-index: 2;
}

View File

@@ -1,116 +1,80 @@
#navbarSearch {
top: 100%;
right: 0;
transition: all 0.3s;
max-height: 0;
overflow: hidden;
}
#navbarSearch.show {
max-height: 300px; /* Adjust this to your desired max height */
#navbarSearch {
top: 100%;
right: 0;
}
#searchForm {
width: 200px; /* Adjust this value as needed */
width: 200px; /* Adjust this value as needed */
}
/* Style the search results to match the navbar */
#searchResults {
max-height: 200px; /* Adjust this value as needed */
overflow-y: auto;
width: 100%;
max-width: 300px; /* Adjust to your preferred width */
transition: height 0.3s ease; /* Smooth height transition */
max-height: 200px; /* Adjust this value as needed */
overflow-y: auto;
width: 100%;
}
#searchResults .dropdown-item {
display: flex;
align-items: center;
white-space: nowrap;
height: 50px; /* Fixed height */
overflow: hidden; /* Hide overflow */
display: flex;
align-items: center;
white-space: nowrap;
height: 50px; /* Fixed height */
overflow: hidden; /* Hide overflow */
}
#searchResults .icon {
margin-right: 10px;
margin-right: 10px;
}
#searchResults .icon-text {
display: inline;
overflow: hidden; /* Hide overflow */
text-overflow: ellipsis; /* Add ellipsis for long text */
display: inline;
overflow: hidden; /* Hide overflow */
text-overflow: ellipsis; /* Add ellipsis for long text */
}
#search-icon i {
font-size: 24px; /* Adjust this to your desired size */
transition: color 0.3s;
}
#search-icon:hover i {
color: #666; /* Adjust this to your hover color */
}
.search-input {
transition:
border 0.3s,
box-shadow 0.3s;
}
.search-input:focus {
border-color: #666; /* Adjust this to your focus color */
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* Adjust this to your desired shadow */
}
/* Set a fixed height and styling for each search result item */
.search-results a {
display: flex;
align-items: center;
gap: 10px; /* space between icon and text */
height: 40px; /* Adjust based on your design */
overflow: hidden; /* Prevent content from overflowing */
white-space: nowrap; /* Prevent text from wrapping to next line */
text-overflow: ellipsis; /* Truncate text if it's too long */
}
.main-icon {
width: 36px;
height: 36px;
vertical-align: middle;
transform: translateY(-2px);
width: 36px;
height: 36px;
vertical-align: middle;
transform: translateY(-2px);
}
.icon {
width: 16px;
height: 16px;
vertical-align: middle;
transform: translateY(-2px);
width: 16px;
height: 16px;
vertical-align: middle;
transform: translateY(-2px);
}
.icon + .icon {
margin-left: -4px;
.icon+.icon {
margin-left: -4px;
}
.icon-text {
margin-left: 4px;
margin-left: 4px;
}
.nav-item-separator {
position: relative;
margin: 0 4px; /* Adjust the margin as needed */
position: relative;
margin: 0 4px; /* Adjust the margin as needed */
}
.nav-item-separator::before {
content: "";
position: absolute;
left: 0;
top: 10%; /* Adjust the top and bottom margins as needed */
bottom: 10%;
width: 1px;
background-color: #ccc; /* Adjust the color as needed */
content: '';
position: absolute;
left: 0;
top: 10%; /* Adjust the top and bottom margins as needed */
bottom: 10%;
width: 1px;
background-color: #ccc; /* Adjust the color as needed */
}
.navbar-icon {
width: 20px;
height: 20px;
transform: translateY(-2px);
}
width: 20px;
height: 20px;
transform: translateY(-2px);
}

View File

@@ -1,85 +1,87 @@
.pdf-actions_button-container {
z-index: 2;
display: flex;
opacity: 0;
transition: opacity 0.1s linear;
z-index: 2;
display:flex;
opacity: 0;
transition: opacity 0.1s linear;
}
.pdf-actions_container:hover .pdf-actions_button-container {
opacity: 1;
opacity: 1;
}
.pdf-actions_button-container > * {
padding: 0.25rem 0.5rem;
margin: 3px;
display: block;
padding: 0.25rem 0.5rem;
margin: 3px;
display: block;
}
.pdf-actions_container svg {
width: 16px;
height: 16px;
width: 16px;
height: 16px;
}
.pdf-actions_container:nth-child(1) .pdf-actions_move-left-button {
display: none;
display: none;
}
.pdf-actions_container:last-child .pdf-actions_move-right-button {
display: none;
display: none;
}
/* "insert pdf" buttons that appear on the right when hover */
.pdf-actions_insert-file-button-container {
translate: 0 -50%;
width: 80px;
height: 100%;
z-index: 1;
opacity: 0;
transition: opacity 0.2s;
translate: 0 -50%;
width: 80px;
height: 100%;
z-index: 1;
opacity: 0;
transition: opacity 0.2s;
}
.pdf-actions_insert-file-button-container.left {
left: -20px;
left: -20px;
}
.pdf-actions_insert-file-button-container.right {
right: -20px;
right: -20px;
}
html[lang-direction="ltr"] .pdf-actions_insert-file-button-container.right {
display: none;
html[lang-direction=ltr] .pdf-actions_insert-file-button-container.right {
display:none;
}
html[lang-direction="rtl"] .pdf-actions_insert-file-button-container.left {
display: none;
html[lang-direction=rtl] .pdf-actions_insert-file-button-container.left {
display:none;
}
.pdf-actions_insert-file-button-container.left .pdf-actions_insert-file-button {
left: 0;
translate: 0 -50%;
left: 0;
translate: 0 -50%;
}
.pdf-actions_insert-file-button-container.right .pdf-actions_insert-file-button {
right: 0;
translate: 0 -50%;
right: 0;
translate: 0 -50%;
}
html[lang-direction="ltr"] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.right {
display: block;
html[lang-direction=ltr] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.right {
display: block;
}
html[lang-direction="rtl"] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.left {
display: block;
html[lang-direction=rtl] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.left {
display: block;
}
.pdf-actions_insert-file-button-container:hover {
opacity: 1;
transition: opacity 0.05s;
opacity: 1;
transition: opacity 0.05s;
}
.pdf-actions_insert-file-button {
position: absolute;
top: 50%;
right: 50%;
translate: 50% -50%;
aspect-ratio: 1;
border-radius: 100px;
}
position: absolute;
top: 50%;
right: 50%;
translate: 50% -50%;
aspect-ratio: 1;
border-radius: 100px;
}

View File

@@ -1,21 +0,0 @@
.btn-margin {
margin-right: 2px;
}
.bordered-box {
border: 1px solid #ddd;
padding: 20px;
margin: 20px;
width: 70%;
}
.center-element {
width: 80%;
text-align: center;
margin: auto;
}
.element-margin {
margin: 10px 0;
/* Adjust this value to increase/decrease the margin as needed */
}

View File

@@ -1,113 +1,37 @@
/* Rainbow Mode Styles */
body {
background: linear-gradient(
90deg,
rgba(255, 0, 0, 1) 0%,
rgba(255, 154, 0, 1) 10%,
rgba(208, 222, 33, 1) 20%,
rgba(79, 220, 74, 1) 30%,
rgba(63, 218, 216, 1) 40%,
rgba(47, 201, 226, 1) 50%,
rgba(28, 127, 238, 1) 60%,
rgba(95, 21, 242, 1) 70%,
rgba(186, 12, 248, 1) 80%,
rgba(251, 7, 217, 1) 90%,
rgba(255, 0, 0, 1) 100%
);
color: #fff !important;
--body-background-color: 255, 255, 255;
--base-font-color: 33, 37, 41;
background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%);
color: #fff !important;
--body-background-color: 255, 255, 255;
--base-font-color: 33, 37, 41;
}
.dark-card {
background: linear-gradient(
90deg,
rgba(255, 0, 0, 1) 0%,
rgba(255, 154, 0, 1) 10%,
rgba(208, 222, 33, 1) 20%,
rgba(79, 220, 74, 1) 30%,
rgba(63, 218, 216, 1) 40%,
rgba(47, 201, 226, 1) 50%,
rgba(28, 127, 238, 1) 60%,
rgba(95, 21, 242, 1) 70%,
rgba(186, 12, 248, 1) 80%,
rgba(251, 7, 217, 1) 90%,
rgba(255, 0, 0, 1) 100%
) !important;
color: white !important;
background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%) !important;
color: white !important;
}
.jumbotron {
background: linear-gradient(
90deg,
rgba(255, 0, 0, 1) 0%,
rgba(255, 154, 0, 1) 10%,
rgba(208, 222, 33, 1) 20%,
rgba(79, 220, 74, 1) 30%,
rgba(63, 218, 216, 1) 40%,
rgba(47, 201, 226, 1) 50%,
rgba(28, 127, 238, 1) 60%,
rgba(95, 21, 242, 1) 70%,
rgba(186, 12, 248, 1) 80%,
rgba(251, 7, 217, 1) 90%,
rgba(255, 0, 0, 1) 100%
);
color: #fff !important;
background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%);
color: #fff !important;
}
.list-group {
background: linear-gradient(
90deg,
rgba(255, 0, 0, 1) 0%,
rgba(255, 154, 0, 1) 10%,
rgba(208, 222, 33, 1) 20%,
rgba(79, 220, 74, 1) 30%,
rgba(63, 218, 216, 1) 40%,
rgba(47, 201, 226, 1) 50%,
rgba(28, 127, 238, 1) 60%,
rgba(95, 21, 242, 1) 70%,
rgba(186, 12, 248, 1) 80%,
rgba(251, 7, 217, 1) 90%,
rgba(255, 0, 0, 1) 100%
) !important;
color: fff !important;
background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%) !important;
color: fff !important;
}
.list-group-item {
background: linear-gradient(
90deg,
rgba(255, 0, 0, 1) 0%,
rgba(255, 154, 0, 1) 10%,
rgba(208, 222, 33, 1) 20%,
rgba(79, 220, 74, 1) 30%,
rgba(63, 218, 216, 1) 40%,
rgba(47, 201, 226, 1) 50%,
rgba(28, 127, 238, 1) 60%,
rgba(95, 21, 242, 1) 70%,
rgba(186, 12, 248, 1) 80%,
rgba(251, 7, 217, 1) 90%,
rgba(255, 0, 0, 1) 100%
) !important;
color: fff !important;
background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%) !important;
color: fff !important;
}
#support-section {
background: linear-gradient(
90deg,
rgba(255, 0, 0, 1) 0%,
rgba(255, 154, 0, 1) 10%,
rgba(208, 222, 33, 1) 20%,
rgba(79, 220, 74, 1) 30%,
rgba(63, 218, 216, 1) 40%,
rgba(47, 201, 226, 1) 50%,
rgba(28, 127, 238, 1) 60%,
rgba(95, 21, 242, 1) 70%,
rgba(186, 12, 248, 1) 80%,
rgba(251, 7, 217, 1) 90%,
rgba(255, 0, 0, 1) 100%
) !important;
background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%) !important;
}
#pages-container-wrapper {
--background-color: rgba(255, 255, 255, 0.046) !important;
--scroll-bar-color: #4c4c4c !important;
--scroll-bar-thumb: #d3d3d3 !important;
--scroll-bar-thumb-hover: #ffffff !important;
}

View File

@@ -1,29 +0,0 @@
#pdf-preview {
margin: 0 auto;
display: block;
max-width: calc(100% - 30px);
max-height: calc(100% - 30px);
box-shadow: 0 0 4px rgba(100, 100, 100, 0.25);
transition: rotate 0.3s;
position: absolute;
top: 50%;
left: 50%;
translate: -50% -50%;
}
.previewContainer {
aspect-ratio: 1;
width: 100%;
border: 1px solid rgba(0, 0, 0, 0.125);
border-radius: 0.25rem;
margin: 1rem 0;
padding: 15px;
display: block;
overflow: hidden;
position: relative;
}
.buttonContainer {
display: flex;
justify-content: space-around;
}

View File

@@ -1,39 +0,0 @@
select#font-select,
select#font-select option {
height: 60px; /* Adjust as needed */
font-size: 30px; /* Adjust as needed */
}
.drawing-pad-container {
text-align: center;
}
#drawing-pad-canvas {
background: rgba(125, 125, 125, 0.2);
width: 100%;
height: 300px;
}
#box-drag-container {
position: relative;
margin: 20px 0;
}
.draggable-buttons-box {
position: absolute;
top: 0;
padding: 10px;
width: 100%;
display: flex;
gap: 5px;
}
.draggable-buttons-box > button {
z-index: 10;
background-color: rgba(13, 110, 253, 0.1);
}
.draggable-canvas {
border: 1px solid red;
position: absolute;
touch-action: none;
user-select: none;
top: 0px;
left: 0;
}

View File

@@ -1,10 +0,0 @@
.pdf-visual-aid {
width: 150px; /* Adjust as needed */
height: 200px; /* Adjust as needed */
border: 1px solid black; /* Represents the PDF page */
position: relative;
}
.line {
position: absolute;
background-color: red; /* Line color */
}

View File

@@ -1,41 +0,0 @@
.a4container {
position: relative;
width: 50%;
aspect-ratio: 0.707;
border: 1px solid #ddd;
box-sizing: border-box;
background-color: white;
}
.pageNumber {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
font-size: 1em;
color: #333;
cursor: pointer;
background-color: #ccc;
width: 15%;
height: 15%;
transform: translate(-50%, -50%);
}
.pageNumber:hover {
background-color: #eee;
}
#myForm {
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px;
}
.selectedPosition {
background-color: #0a0;
}
.selectedPosition.selectedHovered {
background-color: #006600;
}

View File

@@ -1,24 +1,26 @@
.tab-group {
}
.tab-container {
display: none;
display: none;
}
.tab-container.active {
display: block;
border: 1px solid rgba(var(--base-font-color), 0.25);
padding: 15px;
display: block;
border: 1px solid rgba(var(--base-font-color), 0.25);
padding: 15px;
}
.tab-buttons > button {
margin-bottom: -1px;
background: 0 0;
border: 1px solid transparent;
color: rgb(var(--base-font-color));
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
margin-bottom: -1px;
background: 0 0;
border: 1px solid transparent;
color: rgb(var(--base-font-color));
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
}
.tab-buttons > button.active {
background-color: rgb(var(--body-background-color));
border-color: rgba(var(--base-font-color), 0.25) rgba(var(--base-font-color), 0.25) rgb(var(--body-background-color));
}
background-color: rgb(var(--body-background-color));
border-color: rgba(var(--base-font-color), 0.25) rgba(var(--base-font-color), 0.25) rgb(var(--body-background-color));
}

View File

@@ -19,8 +19,8 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs173">
<linearGradient
id="XMLID_5_"
gradientUnits="userSpaceOnUse"
@@ -37,7 +37,7 @@
style="stop-color:#C2C2C9"
id="stop158" />
</linearGradient>
</defs><sodipodi:namedview
id="namedview171"
pagecolor="#ffffff"

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1235" height="650" viewBox="0 0 7410 3900">
<rect width="7410" height="3900" fill="#b22234"/>
<path d="M0,450H7410m0,600H0m0,600H7410m0,600H0m0,600H7410m0,600H0" stroke="#fff" stroke-width="300"/>
<rect width="2964" height="2100" fill="#3c3b6e"/>
<g fill="#fff">
<g id="s18">
<g id="s9">
<g id="s5">
<g id="s4">
<path id="s" d="M247,90 317.534230,307.082039 132.873218,172.917961H361.126782L176.465770,307.082039z"/>
<use xlink:href="#s" y="420"/>
<use xlink:href="#s" y="840"/>
<use xlink:href="#s" y="1260"/>
</g>
<use xlink:href="#s" y="1680"/>
</g>
<use xlink:href="#s4" x="247" y="210"/>
</g>
<use xlink:href="#s9" x="494"/>
</g>
<use xlink:href="#s18" x="988"/>
<use xlink:href="#s9" x="1976"/>
<use xlink:href="#s5" x="2470"/>
</g>
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1235" height="650" viewBox="0 0 7410 3900">
<rect width="7410" height="3900" fill="#b22234"/>
<path d="M0,450H7410m0,600H0m0,600H7410m0,600H0m0,600H7410m0,600H0" stroke="#fff" stroke-width="300"/>
<rect width="2964" height="2100" fill="#3c3b6e"/>
<g fill="#fff">
<g id="s18">
<g id="s9">
<g id="s5">
<g id="s4">
<path id="s" d="M247,90 317.534230,307.082039 132.873218,172.917961H361.126782L176.465770,307.082039z"/>
<use xlink:href="#s" y="420"/>
<use xlink:href="#s" y="840"/>
<use xlink:href="#s" y="1260"/>
</g>
<use xlink:href="#s" y="1680"/>
</g>
<use xlink:href="#s4" x="247" y="210"/>
</g>
<use xlink:href="#s9" x="494"/>
</g>
<use xlink:href="#s18" x="988"/>
<use xlink:href="#s9" x="1976"/>
<use xlink:href="#s5" x="2470"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 874 B

After

Width:  |  Height:  |  Size: 899 B

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="35px" height="35px" viewBox="0 -0.5 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Github-color</title>
<desc>Created with Sketch.</desc>
<defs>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg version="1.1" id="Icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
<svg version="1.1" id="Icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 32 32" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}

Before

Width:  |  Height:  |  Size: 690 B

After

Width:  |  Height:  |  Size: 691 B

View File

@@ -1,5 +1,5 @@
var toggleCount = 0;
var lastToggleTime = Date.now();
var toggleCount = 0
var lastToggleTime = Date.now()
var elements = {
lightModeStyles: null,
@@ -11,18 +11,18 @@ var elements = {
navbar: null,
navIcons: null,
navDropdownMenus: null,
};
}
function getElements() {
elements.lightModeStyles = document.getElementById("light-mode-styles");
elements.darkModeStyles = document.getElementById("dark-mode-styles");
elements.rainbowModeStyles = document.getElementById("rainbow-mode-styles");
elements.darkModeIcon = document.getElementById("dark-mode-icon");
elements.searchBar = document.getElementById("searchBar");
elements.formControls = document.querySelectorAll(".form-control");
elements.navbar = document.querySelectorAll("nav.navbar");
elements.navIcons = document.querySelectorAll("nav .icon, .navbar-icon");
elements.navDropdownMenus = document.querySelectorAll(".dropdown-menu");
elements.lightModeStyles = document.getElementById("light-mode-styles")
elements.darkModeStyles = document.getElementById("dark-mode-styles")
elements.rainbowModeStyles = document.getElementById("rainbow-mode-styles")
elements.darkModeIcon = document.getElementById("dark-mode-icon")
elements.searchBar = document.getElementById("searchBar")
elements.formControls = document.querySelectorAll(".form-control")
elements.navbar = document.querySelectorAll("nav.navbar")
elements.navIcons = document.querySelectorAll("nav .icon, .navbar-icon")
elements.navDropdownMenus = document.querySelectorAll("nav .dropdown-menu")
}
function setMode(mode) {
var event = new CustomEvent("modeChanged", { detail: mode });
@@ -48,22 +48,22 @@ function setMode(mode) {
elements.searchBar.classList.add("dark-mode-search");
}
if (elements && elements.formControls) {
elements.formControls.forEach((input) => input.classList.add("bg-dark", "text-white"));
elements.formControls.forEach(input => input.classList.add("bg-dark", "text-white"));
}
if (elements && elements.navbar) {
elements.navbar.forEach((navElement) => {
elements.navbar.forEach(navElement => {
navElement.classList.remove("navbar-light", "bg-light");
navElement.classList.add("navbar-dark", "bg-dark");
});
}
if (elements && elements.navDropdownMenus) {
elements.navDropdownMenus.forEach((menu) => menu.classList.add("dropdown-menu-dark"));
elements.navDropdownMenus.forEach(menu => menu.classList.add("dropdown-menu-dark"));
}
if (elements && elements.navIcons) {
elements.navIcons.forEach((icon) => (icon.style.filter = "invert(1)"));
elements.navIcons.forEach(icon => (icon.style.filter = "invert(1)"));
}
var tables = document.querySelectorAll(".table");
tables.forEach((table) => {
tables.forEach(table => {
table.classList.add("table-dark");
});
if (jumbotron) {
@@ -78,22 +78,22 @@ function setMode(mode) {
elements.searchBar.classList.remove("dark-mode-search");
}
if (elements && elements.formControls) {
elements.formControls.forEach((input) => input.classList.remove("bg-dark", "text-white"));
elements.formControls.forEach(input => input.classList.remove("bg-dark", "text-white"));
}
if (elements && elements.navbar) {
elements.navbar.forEach((navElement) => {
elements.navbar.forEach(navElement => {
navElement.classList.remove("navbar-dark", "bg-dark");
navElement.classList.add("navbar-light", "bg-light");
});
}
if (elements && elements.navDropdownMenus) {
elements.navDropdownMenus.forEach((menu) => menu.classList.remove("dropdown-menu-dark"));
elements.navDropdownMenus.forEach(menu => menu.classList.remove("dropdown-menu-dark"));
}
if (elements && elements.navIcons) {
elements.navIcons.forEach((icon) => (icon.style.filter = "none"));
elements.navIcons.forEach(icon => (icon.style.filter = "none"));
}
var tables = document.querySelectorAll(".table-dark");
tables.forEach((table) => {
tables.forEach(table => {
table.classList.remove("table-dark");
});
if (jumbotron) {
@@ -108,43 +108,43 @@ function setMode(mode) {
}
function toggleDarkMode() {
var currentTime = Date.now();
var currentTime = Date.now()
if (currentTime - lastToggleTime < 1000) {
toggleCount++;
toggleCount++
} else {
toggleCount = 1;
toggleCount = 1
}
lastToggleTime = currentTime;
lastToggleTime = currentTime
if (toggleCount >= 18) {
localStorage.setItem("dark-mode", "rainbow");
setMode("rainbow");
localStorage.setItem("dark-mode", "rainbow")
setMode("rainbow")
} else if (localStorage.getItem("dark-mode") == "on") {
localStorage.setItem("dark-mode", "off");
setMode("off");
localStorage.setItem("dark-mode", "off")
setMode("off")
} else {
localStorage.setItem("dark-mode", "on");
setMode("on");
localStorage.setItem("dark-mode", "on")
setMode("on")
}
}
document.addEventListener("DOMContentLoaded", function () {
getElements();
getElements()
var currentMode = localStorage.getItem("dark-mode");
var currentMode = localStorage.getItem("dark-mode")
if (currentMode === "on" || currentMode === "off" || currentMode === "rainbow") {
setMode(currentMode);
setMode(currentMode)
} else if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
setMode("on");
setMode("on")
} else {
setMode("off");
setMode("off")
}
var darkModeToggle = document.getElementById("dark-mode-toggle");
if (darkModeToggle !== null) {
darkModeToggle.addEventListener("click", function (event) {
event.preventDefault();
toggleDarkMode();
});
}
});
darkModeToggle.addEventListener("click", function (event) {
event.preventDefault();
toggleDarkMode();
});
}
})

View File

@@ -1,265 +1,242 @@
function showErrorBanner(message, stackTrace) {
const errorContainer = document.getElementById("errorContainer");
errorContainer.style.display = "block"; // Display the banner
document.querySelector("#errorContainer .alert-heading").textContent = "Error";
document.querySelector("#errorContainer p").textContent = message;
document.querySelector("#traceContent").textContent = stackTrace;
const errorContainer = document.getElementById("errorContainer");
errorContainer.style.display = "block"; // Display the banner
document.querySelector("#errorContainer .alert-heading").textContent = "Error";
document.querySelector("#errorContainer p").textContent = message;
document.querySelector("#traceContent").textContent = stackTrace;
}
let firstErrorOccurred = false;
let firstErrorOccurred = false;
$(document).ready(function () {
$("form").submit(async function (event) {
event.preventDefault();
firstErrorOccurred = false;
const url = this.action;
const files = $("#fileInput-input")[0].files;
const formData = new FormData(this);
// Remove empty file entries
for (let [key, value] of formData.entries()) {
if (value instanceof File && !value.name) {
formData.delete(key);
}
}
const override = $("#override").val() || "";
const originalButtonText = $("#submitBtn").text();
$("#submitBtn").text("Processing...");
console.log(override);
// Set a timeout to show the game button if operation takes more than 5 seconds
const timeoutId = setTimeout(() => {
var boredWaiting = localStorage.getItem("boredWaiting") || "disabled";
const showGameBtn = document.getElementById("show-game-btn");
if (boredWaiting === "enabled" && showGameBtn) {
showGameBtn.style.display = "block";
}
}, 5000);
try {
if (remoteCall === true) {
if (override === "multi" || (!multiple && files.length > 1 && override !== "single")) {
await submitMultiPdfForm(url, files);
} else {
await handleSingleDownload(url, formData);
$(document).ready(function() {
$('form').submit(async function(event) {
event.preventDefault();
firstErrorOccurred = false;
const url = this.action;
const files = $('#fileInput-input')[0].files;
const formData = new FormData(this);
// Remove empty file entries
for (let [key, value] of formData.entries()) {
if (value instanceof File && !value.name) {
formData.delete(key);
}
}
}
clearTimeout(timeoutId);
$("#submitBtn").text(originalButtonText);
// After process finishes, check for boredWaiting and gameDialog open status
const boredWaiting = localStorage.getItem("boredWaiting") || "disabled";
const gameDialog = document.getElementById('game-container-wrapper');
if (boredWaiting === "enabled" && gameDialog && gameDialog.open) {
// Display a green banner at the bottom of the screen saying "Download complete"
let downloadCompleteText = "Download Complete";
if(window.downloadCompleteText){
downloadCompleteText = window.downloadCompleteText;
const override = $('#override').val() || '';
const originalButtonText = $('#submitBtn').text();
$('#submitBtn').text('Processing...');
console.log(override);
try {
if(remoteCall === true) {
if (override === 'multi' || (!multiple && files.length > 1) && override !== 'single' ) {
await submitMultiPdfForm(url, files);
} else {
await handleSingleDownload(url, formData);
}
}
$('#submitBtn').text(originalButtonText);
} catch (error) {
handleDownloadError(error);
$('#submitBtn').text(originalButtonText);
console.error(error);
}
$("body").append('<div id="download-complete-banner" style="position:fixed;bottom:0;left:0;width:100%;background-color:green;color:white;text-align:center;padding:10px;font-size:16px;z-index:1000;">'+ downloadCompleteText + '</div>');
setTimeout(function() {
$("#download-complete-banner").fadeOut("slow", function() {
$(this).remove(); // Remove the banner after fading out
});
}, 5000); // Banner will fade out after 5 seconds
}
} catch (error) {
clearTimeout(timeoutId);
handleDownloadError(error);
$("#submitBtn").text(originalButtonText);
console.error(error);
}
});
});
});
async function handleSingleDownload(url, formData, isMulti = false, isZip = false) {
try {
const response = await fetch(url, { method: "POST", body: formData });
const contentType = response.headers.get("content-type");
if (!response.ok) {
if (contentType && contentType.includes("application/json")) {
return handleJsonResponse(response);
console.error("Throwing error banner, response was not okay");
}
throw new Error(`HTTP error! status: ${response.status}`);
}
const contentDisposition = response.headers.get("Content-Disposition");
let filename = getFilenameFromContentDisposition(contentDisposition);
async function handleSingleDownload(url, formData, isMulti = false , isZip = false) {
try {
const response = await fetch(url, { method: 'POST', body: formData });
const contentType = response.headers.get('content-type');
const blob = await response.blob();
if (contentType.includes("application/pdf") || contentType.includes("image/")) {
return handleResponse(blob, filename, !isMulti, isZip);
} else {
return handleResponse(blob, filename, false, isZip);
}
} catch (error) {
console.error("Error in handleSingleDownload:", error);
throw error; // Re-throw the error if you want it to be handled higher up.
}
if (!response.ok) {
if (contentType && contentType.includes('application/json')) {
return handleJsonResponse(response);
console.error('Throwing error banner, response was not okay');
}
throw new Error(`HTTP error! status: ${response.status}`);
}
const contentDisposition = response.headers.get('Content-Disposition');
let filename = getFilenameFromContentDisposition(contentDisposition);
const blob = await response.blob();
if (contentType.includes('application/pdf') || contentType.includes('image/')) {
return handleResponse(blob, filename, !isMulti, isZip);
} else {
return handleResponse(blob, filename, false, isZip);
}
} catch (error) {
console.error('Error in handleSingleDownload:', error);
throw error; // Re-throw the error if you want it to be handled higher up.
}
}
function getFilenameFromContentDisposition(contentDisposition) {
let filename;
let filename;
if (contentDisposition && contentDisposition.indexOf("attachment") !== -1) {
filename = decodeURIComponent(contentDisposition.split("filename=")[1].replace(/"/g, "")).trim();
} else {
// If the Content-Disposition header is not present or does not contain the filename, use a default filename
filename = "download";
}
if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) {
filename = decodeURIComponent(contentDisposition.split('filename=')[1].replace(/"/g, '')).trim();
} else {
// If the Content-Disposition header is not present or does not contain the filename, use a default filename
filename = 'download';
}
return filename;
return filename;
}
async function handleJsonResponse(response) {
const json = await response.json();
const errorMessage = JSON.stringify(json, null, 2);
if (
errorMessage.toLowerCase().includes("the password is incorrect") ||
errorMessage.toLowerCase().includes("Password is not provided") ||
errorMessage.toLowerCase().includes("PDF contains an encryption dictionary")
) {
if (!firstErrorOccurred) {
firstErrorOccurred = true;
alert(pdfPasswordPrompt);
}
} else {
showErrorBanner(json.error + ":" + json.message, json.trace);
}
const json = await response.json();
const errorMessage = JSON.stringify(json, null, 2);
if (errorMessage.toLowerCase().includes('the password is incorrect') || errorMessage.toLowerCase().includes('Password is not provided') || errorMessage.toLowerCase().includes('PDF contains an encryption dictionary')) {
if (!firstErrorOccurred) {
firstErrorOccurred = true;
alert(pdfPasswordPrompt);
}
} else {
showErrorBanner(json.error + ':' + json.message, json.trace);
}
}
async function handleResponse(blob, filename, considerViewOptions = false, isZip = false) {
if (!blob) return;
const downloadOption = localStorage.getItem("downloadOption");
if (considerViewOptions) {
if (downloadOption === "sameWindow") {
const url = URL.createObjectURL(blob);
window.location.href = url;
return;
} else if (downloadOption === "newWindow") {
const url = URL.createObjectURL(blob);
window.open(url, "_blank");
return;
}
}
if (!isZip) {
downloadFile(blob, filename);
}
return { filename, blob };
if (!blob) return;
const downloadOption = localStorage.getItem('downloadOption');
if (considerViewOptions) {
if (downloadOption === 'sameWindow') {
const url = URL.createObjectURL(blob);
window.location.href = url;
return;
} else if (downloadOption === 'newWindow') {
const url = URL.createObjectURL(blob);
window.open(url, '_blank');
return;
}
}
if(!isZip){
downloadFile(blob, filename);
}
return { filename, blob };
}
function handleDownloadError(error) {
const errorMessage = error.message;
showErrorBanner(errorMessage);
const errorMessage = error.message;
showErrorBanner(errorMessage);
}
let urls = []; // An array to hold all the URLs
function downloadFile(blob, filename) {
if (!(blob instanceof Blob)) {
console.error("Invalid blob passed to downloadFile function");
return;
}
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = filename;
a.click();
urls.push(url); // Store the URL so it doesn't get garbage collected too soon
if (!(blob instanceof Blob)) {
console.error('Invalid blob passed to downloadFile function');
return;
}
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
urls.push(url); // Store the URL so it doesn't get garbage collected too soon
return { filename, blob };
return { filename, blob };
}
async function submitMultiPdfForm(url, files) {
const zipThreshold = parseInt(localStorage.getItem("zipThreshold"), 10) || 4;
const zipFiles = files.length > zipThreshold;
let jszip = null;
// Show the progress bar
$("#progressBarContainer").show();
// Initialize the progress bar
let progressBar = $("#progressBar");
progressBar.css("width", "0%");
progressBar.attr("aria-valuenow", 0);
progressBar.attr("aria-valuemax", files.length);
if (zipFiles) {
jszip = new JSZip();
}
// Get the form with the method attribute set to POST
let postForm = document.querySelector('form[method="POST"]');
// Get existing form data
let formData;
if (postForm) {
formData = new FormData($(postForm)[0]); // Convert the form to a jQuery object and get the raw DOM element
} else {
console.log("No form with POST method found.");
}
//Remove file to reuse parameters for other runs
formData.delete("fileInput");
// Remove empty file entries
for (let [key, value] of formData.entries()) {
if (value instanceof File && !value.name) {
formData.delete(key);
}
}
const CONCURRENCY_LIMIT = 8;
const chunks = [];
for (let i = 0; i < Array.from(files).length; i += CONCURRENCY_LIMIT) {
chunks.push(Array.from(files).slice(i, i + CONCURRENCY_LIMIT));
}
for (const chunk of chunks) {
const promises = chunk.map(async (file) => {
let fileFormData = new FormData();
fileFormData.append("fileInput", file);
console.log(fileFormData);
// Add other form data
for (let pair of formData.entries()) {
fileFormData.append(pair[0], pair[1]);
console.log(pair[0] + ", " + pair[1]);
}
try {
const downloadDetails = await handleSingleDownload(url, fileFormData, true, zipFiles);
console.log(downloadDetails);
if (zipFiles) {
jszip.file(downloadDetails.filename, downloadDetails.blob);
} else {
//downloadFile(downloadDetails.blob, downloadDetails.filename);
const zipThreshold = parseInt(localStorage.getItem('zipThreshold'), 10) || 4;
const zipFiles = files.length > zipThreshold;
let jszip = null;
// Show the progress bar
$('#progressBarContainer').show();
// Initialize the progress bar
let progressBar = $('#progressBar');
progressBar.css('width', '0%');
progressBar.attr('aria-valuenow', 0);
progressBar.attr('aria-valuemax', files.length);
if (zipFiles) {
jszip = new JSZip();
}
// Get the form with the method attribute set to POST
let postForm = document.querySelector('form[method="POST"]');
// Get existing form data
let formData;
if (postForm) {
formData = new FormData($(postForm)[0]); // Convert the form to a jQuery object and get the raw DOM element
} else {
console.log("No form with POST method found.");
}
//Remove file to reuse parameters for other runs
formData.delete('fileInput');
// Remove empty file entries
for (let [key, value] of formData.entries()) {
if (value instanceof File && !value.name) {
formData.delete(key);
}
updateProgressBar(progressBar, Array.from(files).length);
} catch (error) {
handleDownloadError(error);
console.error(error);
}
});
await Promise.all(promises);
}
if (zipFiles) {
try {
const content = await jszip.generateAsync({ type: "blob" });
downloadFile(content, "files.zip");
} catch (error) {
console.error("Error generating ZIP file: " + error);
}
}
progressBar.css("width", "100%");
progressBar.attr("aria-valuenow", Array.from(files).length);
const CONCURRENCY_LIMIT = 8;
const chunks = [];
for (let i = 0; i < Array.from(files).length; i += CONCURRENCY_LIMIT) {
chunks.push(Array.from(files).slice(i, i + CONCURRENCY_LIMIT));
}
for (const chunk of chunks) {
const promises = chunk.map(async file => {
let fileFormData = new FormData();
fileFormData.append('fileInput', file);
console.log(fileFormData);
// Add other form data
for (let pair of formData.entries()) {
fileFormData.append(pair[0], pair[1]);
console.log(pair[0]+ ', ' + pair[1]);
}
try {
const downloadDetails = await handleSingleDownload(url, fileFormData, true, zipFiles);
console.log(downloadDetails);
if (zipFiles) {
jszip.file(downloadDetails.filename, downloadDetails.blob);
} else {
//downloadFile(downloadDetails.blob, downloadDetails.filename);
}
updateProgressBar(progressBar, Array.from(files).length);
} catch (error) {
handleDownloadError(error);
console.error(error);
}
});
await Promise.all(promises);
}
if (zipFiles) {
try {
const content = await jszip.generateAsync({ type: "blob" });
downloadFile(content, "files.zip");
} catch (error) {
console.error('Error generating ZIP file: ' + error);
}
}
progressBar.css('width', '100%');
progressBar.attr('aria-valuenow', Array.from(files).length);
}
function updateProgressBar(progressBar, files) {
let progress = (progressBar.attr("aria-valuenow") / files.length) * 100 + 100 / files.length;
progressBar.css("width", progress + "%");
progressBar.attr("aria-valuenow", parseInt(progressBar.attr("aria-valuenow")) + 1);
let progress = ((progressBar.attr('aria-valuenow') / files.length) * 100) + (100 / files.length);
progressBar.css('width', progress + '%');
progressBar.attr('aria-valuenow', parseInt(progressBar.attr('aria-valuenow')) + 1);
}
window.addEventListener("unload", () => {
for (const url of urls) {
URL.revokeObjectURL(url);
}
window.addEventListener('unload', () => {
for (const url of urls) {
URL.revokeObjectURL(url);
}
});

View File

@@ -1,287 +1,282 @@
const DraggableUtils = {
boxDragContainer: document.getElementById("box-drag-container"),
pdfCanvas: document.getElementById("pdf-canvas"),
nextId: 0,
pdfDoc: null,
pageIndex: 0,
documentsMap: new Map(),
init() {
interact(".draggable-canvas")
.draggable({
listeners: {
move: (event) => {
const target = event.target;
const x = (parseFloat(target.getAttribute("data-bs-x")) || 0) + event.dx;
const y = (parseFloat(target.getAttribute("data-bs-y")) || 0) + event.dy;
boxDragContainer: document.getElementById('box-drag-container'),
pdfCanvas: document.getElementById('pdf-canvas'),
nextId: 0,
pdfDoc: null,
pageIndex: 0,
documentsMap: new Map(),
target.style.transform = `translate(${x}px, ${y}px)`;
target.setAttribute("data-bs-x", x);
target.setAttribute("data-bs-y", y);
init() {
interact('.draggable-canvas')
.draggable({
listeners: {
move: (event) => {
const target = event.target;
const x = (parseFloat(target.getAttribute('data-bs-x')) || 0) + event.dx;
const y = (parseFloat(target.getAttribute('data-bs-y')) || 0) + event.dy;
this.onInteraction(target);
},
},
})
.resizable({
edges: { left: true, right: true, bottom: true, top: true },
listeners: {
move: (event) => {
var target = event.target;
var x = parseFloat(target.getAttribute("data-bs-x")) || 0;
var y = parseFloat(target.getAttribute("data-bs-y")) || 0;
target.style.transform = `translate(${x}px, ${y}px)`;
target.setAttribute('data-bs-x', x);
target.setAttribute('data-bs-y', y);
this.onInteraction(target);
},
},
})
.resizable({
edges: { left: true, right: true, bottom: true, top: true },
listeners: {
move: (event) => {
var target = event.target
var x = (parseFloat(target.getAttribute('data-bs-x')) || 0)
var y = (parseFloat(target.getAttribute('data-bs-y')) || 0)
// check if control key is pressed
if (event.ctrlKey) {
const aspectRatio = target.offsetWidth / target.offsetHeight;
// preserve aspect ratio
let width = event.rect.width;
let height = event.rect.height;
const aspectRatio = target.offsetWidth / target.offsetHeight;
// preserve aspect ratio
let width = event.rect.width;
let height = event.rect.height;
if (Math.abs(event.deltaRect.width) >= Math.abs(event.deltaRect.height)) {
height = width / aspectRatio;
} else {
width = height * aspectRatio;
}
if (Math.abs(event.deltaRect.width) >= Math.abs(event.deltaRect.height)) {
height = width / aspectRatio;
} else {
width = height * aspectRatio;
}
event.rect.width = width;
event.rect.height = height;
event.rect.width = width;
event.rect.height = height;
}
target.style.width = event.rect.width + "px";
target.style.height = event.rect.height + "px";
target.style.width = event.rect.width + 'px'
target.style.height = event.rect.height + 'px'
// translate when resizing from top or left edges
x += event.deltaRect.left;
y += event.deltaRect.top;
x += event.deltaRect.left
y += event.deltaRect.top
target.style.transform = "translate(" + x + "px," + y + "px)";
target.style.transform = 'translate(' + x + 'px,' + y + 'px)'
target.setAttribute("data-bs-x", x);
target.setAttribute("data-bs-y", y);
target.textContent = Math.round(event.rect.width) + "\u00D7" + Math.round(event.rect.height);
target.setAttribute('data-bs-x', x)
target.setAttribute('data-bs-y', y)
target.textContent = Math.round(event.rect.width) + '\u00D7' + Math.round(event.rect.height)
this.onInteraction(target);
},
},
},
modifiers: [
interact.modifiers.restrictSize({
min: { width: 5, height: 5 },
}),
],
inertia: true,
});
},
onInteraction(target) {
this.boxDragContainer.appendChild(target);
},
createDraggableCanvas() {
const createdCanvas = document.createElement("canvas");
createdCanvas.id = `draggable-canvas-${this.nextId++}`;
createdCanvas.classList.add("draggable-canvas");
const x = 0;
const y = 20;
createdCanvas.style.transform = `translate(${x}px, ${y}px)`;
createdCanvas.setAttribute("data-bs-x", x);
createdCanvas.setAttribute("data-bs-y", y);
createdCanvas.onclick = (e) => this.onInteraction(e.target);
this.boxDragContainer.appendChild(createdCanvas);
return createdCanvas;
},
createDraggableCanvasFromUrl(dataUrl) {
return new Promise((resolve) => {
var myImage = new Image();
myImage.src = dataUrl;
myImage.onload = () => {
var createdCanvas = this.createDraggableCanvas();
createdCanvas.width = myImage.width;
createdCanvas.height = myImage.height;
const imgAspect = myImage.width / myImage.height;
const pdfAspect = this.boxDragContainer.offsetWidth / this.boxDragContainer.offsetHeight;
var scaleMultiplier;
if (imgAspect > pdfAspect) {
scaleMultiplier = this.boxDragContainer.offsetWidth / myImage.width;
} else {
scaleMultiplier = this.boxDragContainer.offsetHeight / myImage.height;
}
var newWidth = createdCanvas.width;
var newHeight = createdCanvas.height;
if (scaleMultiplier < 1) {
newWidth = newWidth * scaleMultiplier;
newHeight = newHeight * scaleMultiplier;
}
createdCanvas.style.width = newWidth + "px";
createdCanvas.style.height = newHeight + "px";
var myContext = createdCanvas.getContext("2d");
myContext.drawImage(myImage, 0, 0);
resolve(createdCanvas);
};
});
},
deleteAllDraggableCanvases() {
this.boxDragContainer.querySelectorAll(".draggable-canvas").forEach((el) => el.remove());
},
deleteDraggableCanvas(element) {
if (element) {
element.remove();
}
},
getLastInteracted() {
return this.boxDragContainer.querySelector(".draggable-canvas:last-of-type");
},
storePageContents() {
var pagesMap = this.documentsMap.get(this.pdfDoc);
if (!pagesMap) {
pagesMap = {};
}
const elements = [...this.boxDragContainer.querySelectorAll(".draggable-canvas")];
const draggablesData = elements.map((el) => {
return {
element: el,
offsetWidth: el.offsetWidth,
offsetHeight: el.offsetHeight,
};
});
elements.forEach((el) => this.boxDragContainer.removeChild(el));
pagesMap[this.pageIndex] = draggablesData;
pagesMap[this.pageIndex + "-offsetWidth"] = this.pdfCanvas.offsetWidth;
pagesMap[this.pageIndex + "-offsetHeight"] = this.pdfCanvas.offsetHeight;
this.documentsMap.set(this.pdfDoc, pagesMap);
},
loadPageContents() {
var pagesMap = this.documentsMap.get(this.pdfDoc);
this.deleteAllDraggableCanvases();
if (!pagesMap) {
return;
}
const draggablesData = pagesMap[this.pageIndex];
if (draggablesData) {
draggablesData.forEach((draggableData) => this.boxDragContainer.appendChild(draggableData.element));
}
this.documentsMap.set(this.pdfDoc, pagesMap);
},
async renderPage(pdfDocument, pageIdx) {
this.pdfDoc = pdfDocument ? pdfDocument : this.pdfDoc;
this.pageIndex = pageIdx;
// persist
const page = await this.pdfDoc.getPage(this.pageIndex + 1);
// set the canvas size to the size of the page
if (page.rotate == 90 || page.rotate == 270) {
this.pdfCanvas.width = page.view[3];
this.pdfCanvas.height = page.view[2];
} else {
this.pdfCanvas.width = page.view[2];
this.pdfCanvas.height = page.view[3];
}
// render the page onto the canvas
var renderContext = {
canvasContext: this.pdfCanvas.getContext("2d"),
viewport: page.getViewport({ scale: 1 }),
};
await page.render(renderContext).promise;
//return pdfCanvas.toDataURL();
},
async incrementPage() {
if (this.pageIndex < this.pdfDoc.numPages - 1) {
this.storePageContents();
await this.renderPage(this.pdfDoc, this.pageIndex + 1);
this.loadPageContents();
}
},
async decrementPage() {
if (this.pageIndex > 0) {
this.storePageContents();
await this.renderPage(this.pdfDoc, this.pageIndex - 1);
this.loadPageContents();
}
},
parseTransform(element) {},
async getOverlayedPdfDocument() {
const pdfBytes = await this.pdfDoc.getData();
const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes, {
ignoreEncryption: true,
});
this.storePageContents();
const pagesMap = this.documentsMap.get(this.pdfDoc);
for (let pageIdx in pagesMap) {
if (pageIdx.includes("offset")) {
continue;
}
console.log(typeof pageIdx);
const page = pdfDocModified.getPage(parseInt(pageIdx));
const draggablesData = pagesMap[pageIdx];
const offsetWidth = pagesMap[pageIdx + "-offsetWidth"];
const offsetHeight = pagesMap[pageIdx + "-offsetHeight"];
for (const draggableData of draggablesData) {
// embed the draggable canvas
const draggableElement = draggableData.element;
const response = await fetch(draggableElement.toDataURL());
const draggableImgBytes = await response.arrayBuffer();
const pdfImageObject = await pdfDocModified.embedPng(draggableImgBytes);
// calculate the position in the pdf document
const tansform = draggableElement.style.transform.replace(/[^.,-\d]/g, "");
const transformComponents = tansform.split(",");
const draggablePositionPixels = {
x: parseFloat(transformComponents[0]),
y: parseFloat(transformComponents[1]),
width: draggableData.offsetWidth,
height: draggableData.offsetHeight,
};
const draggablePositionRelative = {
x: draggablePositionPixels.x / offsetWidth,
y: draggablePositionPixels.y / offsetHeight,
width: draggablePositionPixels.width / offsetWidth,
height: draggablePositionPixels.height / offsetHeight,
};
const draggablePositionPdf = {
x: draggablePositionRelative.x * page.getWidth(),
y: draggablePositionRelative.y * page.getHeight(),
width: draggablePositionRelative.width * page.getWidth(),
height: draggablePositionRelative.height * page.getHeight(),
};
// draw the image
page.drawImage(pdfImageObject, {
x: draggablePositionPdf.x,
y: page.getHeight() - draggablePositionPdf.y - draggablePositionPdf.height,
width: draggablePositionPdf.width,
height: draggablePositionPdf.height,
modifiers: [
interact.modifiers.restrictSize({
min: { width: 5, height: 5 },
}),
],
inertia: true,
});
}
}
},
onInteraction(target) {
this.boxDragContainer.appendChild(target);
},
this.loadPageContents();
return pdfDocModified;
},
};
createDraggableCanvas() {
const createdCanvas = document.createElement('canvas');
createdCanvas.id = `draggable-canvas-${this.nextId++}`;
createdCanvas.classList.add("draggable-canvas");
const x = 0;
const y = 20;
createdCanvas.style.transform = `translate(${x}px, ${y}px)`;
createdCanvas.setAttribute('data-bs-x', x);
createdCanvas.setAttribute('data-bs-y', y);
createdCanvas.onclick = e => this.onInteraction(e.target);
this.boxDragContainer.appendChild(createdCanvas);
return createdCanvas;
},
createDraggableCanvasFromUrl(dataUrl) {
return new Promise((resolve) => {
var myImage = new Image();
myImage.src = dataUrl;
myImage.onload = () => {
var createdCanvas = this.createDraggableCanvas();
createdCanvas.width = myImage.width;
createdCanvas.height = myImage.height;
const imgAspect = myImage.width / myImage.height;
const pdfAspect = this.boxDragContainer.offsetWidth / this.boxDragContainer.offsetHeight;
var scaleMultiplier;
if (imgAspect > pdfAspect) {
scaleMultiplier = this.boxDragContainer.offsetWidth / myImage.width;
} else {
scaleMultiplier = this.boxDragContainer.offsetHeight / myImage.height;
}
var newWidth = createdCanvas.width;
var newHeight = createdCanvas.height;
if (scaleMultiplier < 1) {
newWidth = newWidth * scaleMultiplier;
newHeight = newHeight * scaleMultiplier;
}
createdCanvas.style.width = newWidth+"px";
createdCanvas.style.height = newHeight+"px";
var myContext = createdCanvas.getContext("2d");
myContext.drawImage(myImage,0,0);
resolve(createdCanvas);
}
})
},
deleteAllDraggableCanvases() {
this.boxDragContainer.querySelectorAll(".draggable-canvas").forEach(el => el.remove());
},
deleteDraggableCanvas(element) {
if (element) {
element.remove();
}
},
getLastInteracted() {
return this.boxDragContainer.querySelector(".draggable-canvas:last-of-type");
},
storePageContents() {
var pagesMap = this.documentsMap.get(this.pdfDoc);
if (!pagesMap) {
pagesMap = {};
}
const elements = [...this.boxDragContainer.querySelectorAll(".draggable-canvas")];
const draggablesData = elements.map(el => {return{element:el, offsetWidth:el.offsetWidth, offsetHeight:el.offsetHeight}});
elements.forEach(el => this.boxDragContainer.removeChild(el));
pagesMap[this.pageIndex] = draggablesData;
pagesMap[this.pageIndex+"-offsetWidth"] = this.pdfCanvas.offsetWidth;
pagesMap[this.pageIndex+"-offsetHeight"] = this.pdfCanvas.offsetHeight;
this.documentsMap.set(this.pdfDoc, pagesMap);
},
loadPageContents() {
var pagesMap = this.documentsMap.get(this.pdfDoc);
this.deleteAllDraggableCanvases();
if (!pagesMap) {
return;
}
const draggablesData = pagesMap[this.pageIndex];
if (draggablesData) {
draggablesData.forEach(draggableData => this.boxDragContainer.appendChild(draggableData.element));
}
this.documentsMap.set(this.pdfDoc, pagesMap);
},
async renderPage(pdfDocument, pageIdx) {
this.pdfDoc = pdfDocument ? pdfDocument : this.pdfDoc;
this.pageIndex = pageIdx;
// persist
const page = await this.pdfDoc.getPage(this.pageIndex+1);
// set the canvas size to the size of the page
if (page.rotate == 90 || page.rotate == 270) {
this.pdfCanvas.width = page.view[3];
this.pdfCanvas.height = page.view[2];
} else {
this.pdfCanvas.width = page.view[2];
this.pdfCanvas.height = page.view[3];
}
// render the page onto the canvas
var renderContext = {
canvasContext: this.pdfCanvas.getContext("2d"),
viewport: page.getViewport({ scale: 1 })
};
await page.render(renderContext).promise;
//return pdfCanvas.toDataURL();
},
async incrementPage() {
if (this.pageIndex < this.pdfDoc.numPages-1) {
this.storePageContents();
await this.renderPage(this.pdfDoc, this.pageIndex+1);
this.loadPageContents();
}
},
async decrementPage() {
if (this.pageIndex > 0) {
this.storePageContents();
await this.renderPage(this.pdfDoc, this.pageIndex-1);
this.loadPageContents();
}
},
parseTransform(element) {
},
async getOverlayedPdfDocument() {
const pdfBytes = await this.pdfDoc.getData();
const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes, { ignoreEncryption: true });
this.storePageContents();
const pagesMap = this.documentsMap.get(this.pdfDoc);
for (let pageIdx in pagesMap) {
if (pageIdx.includes("offset")) {
continue;
}
console.log(typeof pageIdx);
const page = pdfDocModified.getPage(parseInt(pageIdx));
const draggablesData = pagesMap[pageIdx];
const offsetWidth = pagesMap[pageIdx+"-offsetWidth"];
const offsetHeight = pagesMap[pageIdx+"-offsetHeight"];
for (const draggableData of draggablesData) {
// embed the draggable canvas
const draggableElement = draggableData.element;
const response = await fetch(draggableElement.toDataURL());
const draggableImgBytes = await response.arrayBuffer();
const pdfImageObject = await pdfDocModified.embedPng(draggableImgBytes);
// calculate the position in the pdf document
const tansform = draggableElement.style.transform.replace(/[^.,-\d]/g, '');
const transformComponents = tansform.split(",");
const draggablePositionPixels = {
x: parseFloat(transformComponents[0]),
y: parseFloat(transformComponents[1]),
width: draggableData.offsetWidth,
height: draggableData.offsetHeight,
};
const draggablePositionRelative = {
x: draggablePositionPixels.x / offsetWidth,
y: draggablePositionPixels.y / offsetHeight,
width: draggablePositionPixels.width / offsetWidth,
height: draggablePositionPixels.height / offsetHeight,
}
const draggablePositionPdf = {
x: draggablePositionRelative.x * page.getWidth(),
y: draggablePositionRelative.y * page.getHeight(),
width: draggablePositionRelative.width * page.getWidth(),
height: draggablePositionRelative.height * page.getHeight(),
}
// draw the image
page.drawImage(pdfImageObject, {
x: draggablePositionPdf.x,
y: page.getHeight() - draggablePositionPdf.y - draggablePositionPdf.height,
width: draggablePositionPdf.width,
height: draggablePositionPdf.height,
});
}
}
this.loadPageContents();
return pdfDocModified;
},
}
document.addEventListener("DOMContentLoaded", () => {
DraggableUtils.init();
DraggableUtils.init();
});

View File

@@ -1,50 +1,50 @@
var traceVisible = false;
function toggletrace() {
var traceDiv = document.getElementById("trace");
if (!traceVisible) {
traceDiv.style.maxHeight = "500px";
traceVisible = true;
} else {
traceDiv.style.maxHeight = "0px";
traceVisible = false;
}
adjustContainerHeight();
var traceDiv = document.getElementById("trace");
if (!traceVisible) {
traceDiv.style.maxHeight = "500px";
traceVisible = true;
} else {
traceDiv.style.maxHeight = "0px";
traceVisible = false;
}
adjustContainerHeight();
}
function copytrace() {
var flip = false;
if (!traceVisible) {
toggletrace();
flip = true;
}
var traceContent = document.getElementById("traceContent");
var range = document.createRange();
range.selectNode(traceContent);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand("copy");
window.getSelection().removeAllRanges();
if (flip) {
toggletrace();
}
var flip = false
if (!traceVisible) {
toggletrace()
flip = true
}
var traceContent = document.getElementById("traceContent");
var range = document.createRange();
range.selectNode(traceContent);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand("copy");
window.getSelection().removeAllRanges();
if (flip) {
toggletrace()
}
}
function dismissError() {
var errorContainer = document.getElementById("errorContainer");
errorContainer.style.display = "none";
errorContainer.style.height = "0";
var errorContainer = document.getElementById("errorContainer");
errorContainer.style.display = "none";
errorContainer.style.height = "0";
}
function adjustContainerHeight() {
var errorContainer = document.getElementById("errorContainer");
var traceDiv = document.getElementById("trace");
if (traceVisible) {
errorContainer.style.height = errorContainer.scrollHeight - traceDiv.scrollHeight + traceDiv.offsetHeight + "px";
} else {
errorContainer.style.height = "auto";
}
var errorContainer = document.getElementById("errorContainer");
var traceDiv = document.getElementById("trace");
if (traceVisible) {
errorContainer.style.height = errorContainer.scrollHeight - traceDiv.scrollHeight + traceDiv.offsetHeight + "px";
} else {
errorContainer.style.height = "auto";
}
}
function showHelp() {
$("#helpModal").modal("show");
}
$('#helpModal').modal('show');
}

View File

@@ -1,45 +1,45 @@
function updateFavoritesDropdown() {
var dropdown = document.querySelector("#favoritesDropdown");
// Check if dropdown exists
if (!dropdown) {
console.error('Dropdown element with ID "favoritesDropdown" not found!');
return; // Exit the function
}
dropdown.innerHTML = ""; // Clear the current favorites
var hasFavorites = false;
for (var i = 0; i < localStorage.length; i++) {
var key = localStorage.key(i);
if (localStorage.getItem(key) === "favorite") {
// Find the corresponding navbar entry
var navbarEntry = document.querySelector(`a[href='${key}']`);
if (navbarEntry) {
// Create a new dropdown entry
var dropdownItem = document.createElement("a");
dropdownItem.className = "dropdown-item";
dropdownItem.href = navbarEntry.href;
dropdownItem.innerHTML = navbarEntry.innerHTML;
dropdown.appendChild(dropdownItem);
hasFavorites = true;
} else {
console.warn(`Navbar entry not found for key: ${key}`);
}
var dropdown = document.querySelector('#favoritesDropdown');
// Check if dropdown exists
if (!dropdown) {
console.error('Dropdown element with ID "favoritesDropdown" not found!');
return; // Exit the function
}
}
dropdown.innerHTML = ''; // Clear the current favorites
// Show or hide the default item based on whether there are any favorites
if (!hasFavorites) {
var defaultItem = document.createElement("a");
defaultItem.className = "dropdown-item";
defaultItem.textContent = noFavourites;
dropdown.appendChild(defaultItem);
}
var hasFavorites = false;
for (var i = 0; i < localStorage.length; i++) {
var key = localStorage.key(i);
if (localStorage.getItem(key) === 'favorite') {
// Find the corresponding navbar entry
var navbarEntry = document.querySelector(`a[href='${key}']`);
if (navbarEntry) {
// Create a new dropdown entry
var dropdownItem = document.createElement('a');
dropdownItem.className = 'dropdown-item';
dropdownItem.href = navbarEntry.href;
dropdownItem.innerHTML = navbarEntry.innerHTML;
dropdown.appendChild(dropdownItem);
hasFavorites = true;
} else {
console.warn(`Navbar entry not found for key: ${key}`);
}
}
}
// Show or hide the default item based on whether there are any favorites
if (!hasFavorites) {
var defaultItem = document.createElement('a');
defaultItem.className = 'dropdown-item';
defaultItem.textContent = noFavourites;
dropdown.appendChild(defaultItem);
}
}
// Ensure that the DOM content has been fully loaded before calling the function
document.addEventListener("DOMContentLoaded", function () {
console.log("DOMContentLoaded event fired");
updateFavoritesDropdown();
document.addEventListener('DOMContentLoaded', function() {
console.log('DOMContentLoaded event fired');
updateFavoritesDropdown();
});

View File

@@ -1,107 +1,104 @@
document.addEventListener("DOMContentLoaded", function () {
document.querySelectorAll(".custom-file-chooser").forEach(setupFileInput);
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.custom-file-chooser').forEach(setupFileInput);
});
function setupFileInput(chooser) {
const elementId = chooser.getAttribute("data-bs-element-id");
const filesSelected = chooser.getAttribute("data-bs-files-selected");
const pdfPrompt = chooser.getAttribute("data-bs-pdf-prompt");
const elementId = chooser.getAttribute('data-bs-element-id');
const filesSelected = chooser.getAttribute('data-bs-files-selected');
const pdfPrompt = chooser.getAttribute('data-bs-pdf-prompt');
let allFiles = [];
let overlay;
let dragCounter = 0;
let allFiles = [];
let overlay;
let dragCounter = 0;
const dragenterListener = function () {
dragCounter++;
if (!overlay) {
overlay = document.createElement("div");
overlay.style.position = "fixed";
overlay.style.top = 0;
overlay.style.left = 0;
overlay.style.width = "100%";
overlay.style.height = "100%";
overlay.style.background = "rgba(0, 0, 0, 0.5)";
overlay.style.color = "#fff";
overlay.style.zIndex = "1000";
overlay.style.display = "flex";
overlay.style.alignItems = "center";
overlay.style.justifyContent = "center";
overlay.style.pointerEvents = "none";
overlay.innerHTML = "<p>Drop files anywhere to upload</p>";
document.getElementById("content-wrap").appendChild(overlay);
}
};
const dragenterListener = function() {
dragCounter++;
if (!overlay) {
overlay = document.createElement('div');
overlay.style.position = 'fixed';
overlay.style.top = 0;
overlay.style.left = 0;
overlay.style.width = '100%';
overlay.style.height = '100%';
overlay.style.background = 'rgba(0, 0, 0, 0.5)';
overlay.style.color = '#fff';
overlay.style.zIndex = '1000';
overlay.style.display = 'flex';
overlay.style.alignItems = 'center';
overlay.style.justifyContent = 'center';
overlay.style.pointerEvents = 'none';
overlay.innerHTML = '<p>Drop files anywhere to upload</p>';
document.getElementById('content-wrap').appendChild(overlay);
}
};
const dragleaveListener = function () {
dragCounter--;
if (dragCounter === 0) {
if (overlay) {
overlay.remove();
overlay = null;
}
}
};
const dragleaveListener = function() {
dragCounter--;
if (dragCounter === 0) {
if (overlay) {
overlay.remove();
overlay = null;
}
}
};
const dropListener = function (e) {
e.preventDefault();
const dt = e.dataTransfer;
const files = dt.files;
const dropListener = function(e) {
e.preventDefault();
const dt = e.dataTransfer;
const files = dt.files;
for (let i = 0; i < files.length; i++) {
allFiles.push(files[i]);
}
for (let i = 0; i < files.length; i++) {
allFiles.push(files[i]);
}
const dataTransfer = new DataTransfer();
allFiles.forEach((file) => dataTransfer.items.add(file));
const dataTransfer = new DataTransfer();
allFiles.forEach(file => dataTransfer.items.add(file));
const fileInput = document.getElementById(elementId);
fileInput.files = dataTransfer.files;
const fileInput = document.getElementById(elementId);
fileInput.files = dataTransfer.files;
if (overlay) {
overlay.remove();
overlay = null;
}
if (overlay) {
overlay.remove();
overlay = null;
}
dragCounter = 0;
dragCounter = 0;
fileInput.dispatchEvent(new Event("change", { bubbles: true }));
};
fileInput.dispatchEvent(new Event('change', { bubbles: true }));
};
["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => {
document.body.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
document.body.addEventListener("dragenter", dragenterListener);
document.body.addEventListener("dragleave", dragleaveListener);
document.body.addEventListener("drop", dropListener);
$("#" + elementId).on("change", function (e) {
allFiles = Array.from(e.target.files);
handleFileInputChange(this);
});
function handleFileInputChange(inputElement) {
const files = allFiles;
const fileNames = files.map((f) => f.name);
const selectedFilesContainer = $(inputElement).siblings(".selected-files");
selectedFilesContainer.empty();
fileNames.forEach((fileName) => {
selectedFilesContainer.append("<div>" + fileName + "</div>");
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
document.body.addEventListener(eventName, preventDefaults, false);
});
if (fileNames.length === 1) {
$(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames[0]);
} else if (fileNames.length > 1) {
$(inputElement)
.siblings(".custom-file-label")
.addClass("selected")
.html(fileNames.length + " " + filesSelected);
} else {
$(inputElement).siblings(".custom-file-label").addClass("selected").html(pdfPrompt);
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
document.body.addEventListener('dragenter', dragenterListener);
document.body.addEventListener('dragleave', dragleaveListener);
document.body.addEventListener('drop', dropListener);
$("#" + elementId).on("change", function(e) {
allFiles = Array.from(e.target.files);
handleFileInputChange(this);
});
function handleFileInputChange(inputElement) {
const files = allFiles;
const fileNames = files.map(f => f.name);
const selectedFilesContainer = $(inputElement).siblings(".selected-files");
selectedFilesContainer.empty();
fileNames.forEach(fileName => {
selectedFilesContainer.append("<div>" + fileName + "</div>");
});
if (fileNames.length === 1) {
$(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames[0]);
} else if (fileNames.length > 1) {
$(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames.length + " " + filesSelected);
} else {
$(inputElement).siblings(".custom-file-label").addClass("selected").html(pdfPrompt);
}
}
}
}

View File

@@ -1,276 +1,292 @@
function initializeGame() {
const gameContainer = document.getElementById("game-container");
const player = document.getElementById("player");
const gameContainer = document.getElementById('game-container');
const player = document.getElementById('player');
let playerSize = gameContainer.clientWidth * 0.0625; // 5% of container width
player.style.width = playerSize + 'px';
player.style.height = playerSize + 'px';
let playerX = gameContainer.clientWidth / 2 - playerSize / 2;
let playerY = gameContainer.clientHeight * 0.1;
const scoreElement = document.getElementById('score');
const levelElement = document.getElementById('level');
const livesElement = document.getElementById('lives');
const highScoreElement = document.getElementById('high-score');
let playerSize = gameContainer.clientWidth * 0.0625; // 5% of container width
player.style.width = playerSize + "px";
player.style.height = playerSize + "px";
let pdfSize = gameContainer.clientWidth * 0.0625; // 5% of container width
let projectileWidth = gameContainer.clientWidth * 0.00625;// 0.00625; // 0.5% of container width
let projectileHeight = gameContainer.clientHeight * 0.01667; // 1% of container height
let playerX = gameContainer.clientWidth / 2 - playerSize / 2;
let playerY = gameContainer.clientHeight * 0.1;
const scoreElement = document.getElementById("score");
const levelElement = document.getElementById("level");
const livesElement = document.getElementById("lives");
const highScoreElement = document.getElementById("high-score");
let paused = false;
const fireRate = 200; // Time between shots in milliseconds
let lastProjectileTime = 0;
let lives = 3;
let highScore = localStorage.getItem('highScore') ? parseInt(localStorage.getItem('highScore')) : 0;
updateHighScore();
let pdfSize = gameContainer.clientWidth * 0.0625; // 5% of container width
let projectileWidth = gameContainer.clientWidth * 0.00625; // 0.00625; // 0.5% of container width
let projectileHeight = gameContainer.clientHeight * 0.01667; // 1% of container height
let paused = false;
const fireRate = 200; // Time between shots in milliseconds
let lastProjectileTime = 0;
let lives = 3;
const keysPressed = {};
const pdfs = [];
const projectiles = [];
let score = 0;
let level = 1;
let pdfSpeed = 0.5;
let gameOver = false;
let highScore = localStorage.getItem("highScore") ? parseInt(localStorage.getItem("highScore")) : 0;
updateHighScore();
function handleKeys() {
if (keysPressed['ArrowLeft']) {
playerX -= 10;
}
if (keysPressed['ArrowRight']) {
playerX += 10;
}
if (keysPressed[' '] && !gameOver) {
const currentTime = new Date().getTime();
if (currentTime - lastProjectileTime >= fireRate) {
shootProjectile();
lastProjectileTime = currentTime;
}
}
updatePlayerPosition();
}
const PLAYER_MOVE_SPEED = 5;
const BASE_PDF_SPEED = 1;
const LEVEL_INCREASE_PDF_SPEED = 0.2;
const BASE_SPAWN_INTERVAL_MS = 1250; // milliseconds before a new enemy spawns
const LEVEL_INCREASE_FACTOR_MS = 25; // milliseconds to decrease the spawn interval per level
const MAX_SPAWN_RATE_REDUCTION_MS = 800; // Max milliseconds from the base spawn interval
let keysPressed = {};
const pdfs = [];
const projectiles = [];
let score = 0;
let level = 1;
let pdfSpeed = BASE_PDF_SPEED;
let gameOver = false;
function handleKeys() {
if (keysPressed["ArrowLeft"]) {
playerX -= PLAYER_MOVE_SPEED;
playerX = Math.max(0, playerX)
}
if (keysPressed["ArrowRight"]) {
playerX += PLAYER_MOVE_SPEED;
playerX = Math.min(gameContainer.clientWidth - playerSize, playerX);
}
if (keysPressed[" "] && !gameOver) {
const currentTime = new Date().getTime();
if (currentTime - lastProjectileTime >= fireRate) {
shootProjectile();
lastProjectileTime = currentTime;
}
}
updatePlayerPosition();
}
function onKeydown(event) {
if (event.key === " ") {
event.preventDefault();
}
keysPressed[event.key] = true;
handleKeys();
}
function onKeyUp(event) {
keysPressed[event.key] = false;
}
document.removeEventListener("keydown", onKeydown);
document.removeEventListener("keyup", onKeyUp);
document.addEventListener("keydown", onKeydown);
document.addEventListener("keyup", onKeyUp);
function updatePlayerPosition() {
player.style.left = playerX + "px";
player.style.bottom = playerY + "px";
}
function updateLives() {
livesElement.textContent = "Lives: " + lives;
}
function updateHighScore() {
highScoreElement.textContent = "High Score: " + highScore;
}
function shootProjectile() {
const projectile = document.createElement("div");
projectile.classList.add("projectile");
projectile.style.backgroundColor = "black";
projectile.style.width = projectileWidth + "px";
projectile.style.height = projectileHeight + "px";
projectile.style.left = playerX + playerSize / 2 - projectileWidth / 2 + "px";
projectile.style.top = gameContainer.clientHeight - playerY - playerSize + "px";
gameContainer.appendChild(projectile);
projectiles.push(projectile);
}
function spawnPdf() {
const pdf = document.createElement("img");
pdf.src = "images/file-earmark-pdf.svg";
pdf.classList.add("pdf");
pdf.style.width = pdfSize + "px";
pdf.style.height = pdfSize + "px";
pdf.style.left = Math.floor(Math.random() * (gameContainer.clientWidth - (2*pdfSize))) + pdfSize + "px";
pdf.style.top = "0px";
gameContainer.appendChild(pdf);
pdfs.push(pdf);
}
function resetEnemies() {
pdfs.forEach((pdf) => gameContainer.removeChild(pdf));
pdfs.length = 0;
}
function updateGame() {
if (gameOver || paused) return;
handleKeys();
for (let pdfIndex = 0; pdfIndex < pdfs.length; pdfIndex++) {
const pdf = pdfs[pdfIndex];
const pdfY = parseFloat(pdf.style.top) + pdfSpeed;
if (pdfY + 50 > gameContainer.clientHeight) {
gameContainer.removeChild(pdf);
pdfs.splice(pdfIndex, 1);
// Deduct 2 points when a PDF gets past the player
score -= 0;
updateScore();
// Decrease lives and check if game over
lives--;
updateLives();
if (lives <= 0) {
endGame();
return;
document.addEventListener('keydown', (event) => {
if (event.key === ' ') {
event.preventDefault();
}
} else {
pdf.style.top = pdfY + "px";
// Check for collision with player
if (collisionDetected(player, pdf)) {
lives--;
updateLives();
resetEnemies();
if (lives <= 0) {
endGame();
return;
}
}
}
}
projectiles.forEach((projectile, projectileIndex) => {
const projectileY = parseInt(projectile.style.top) - 10;
if (projectileY < 0) {
gameContainer.removeChild(projectile);
projectiles.splice(projectileIndex, 1);
} else {
projectile.style.top = projectileY + "px";
}
for (let pdfIndex = 0; pdfIndex < pdfs.length; pdfIndex++) {
const pdf = pdfs[pdfIndex];
if (collisionDetected(projectile, pdf)) {
gameContainer.removeChild(pdf);
gameContainer.removeChild(projectile);
pdfs.splice(pdfIndex, 1);
projectiles.splice(projectileIndex, 1);
score = score + 10;
updateScore();
break;
}
}
keysPressed[event.key] = true;
handleKeys();
});
setTimeout(updateGame, 1000 / 60);
}
document.addEventListener('keyup', (event) => {
keysPressed[event.key] = false;
});
function updatePlayerPosition() {
player.style.left = playerX + 'px';
player.style.bottom = playerY + 'px';
}
function updateLives() {
livesElement.textContent = 'Lives: ' + lives;
}
function updateHighScore() {
highScoreElement.textContent = 'High Score: ' + highScore;
}
function shootProjectile() {
const projectile = document.createElement('div');
projectile.classList.add('projectile');
projectile.style.backgroundColor = 'black';
projectile.style.width = projectileWidth + 'px';
projectile.style.height = projectileHeight + 'px';
projectile.style.left = (playerX + playerSize / 2 - projectileWidth / 2) + 'px';
projectile.style.top = (gameContainer.clientHeight - playerY - playerSize) + 'px';
gameContainer.appendChild(projectile);
projectiles.push(projectile);
}
function spawnPdf() {
const pdf = document.createElement('img');
pdf.src = 'images/file-earmark-pdf.svg';
pdf.classList.add('pdf');
pdf.style.width = pdfSize + 'px';
pdf.style.height = pdfSize + 'px';
pdf.style.left = Math.floor(Math.random() * (gameContainer.clientWidth - pdfSize)) + 'px';
pdf.style.top = '0px';
gameContainer.appendChild(pdf);
pdfs.push(pdf);
}
function resetEnemies() {
pdfs.forEach((pdf) => gameContainer.removeChild(pdf));
pdfs.length = 0;
}
function updateGame() {
if (gameOver || paused) return;
for (let pdfIndex = 0; pdfIndex < pdfs.length; pdfIndex++) {
const pdf = pdfs[pdfIndex];
const pdfY = parseFloat(pdf.style.top) + pdfSpeed;
if (pdfY + 50 > gameContainer.clientHeight) {
gameContainer.removeChild(pdf);
pdfs.splice(pdfIndex, 1);
// Deduct 2 points when a PDF gets past the player
score -= 0;
updateScore();
// Decrease lives and check if game over
lives--;
updateLives();
if (lives <= 0) {
endGame();
return;
}
} else {
pdf.style.top = pdfY + 'px';
// Check for collision with player
if (collisionDetected(player, pdf)) {
lives--;
updateLives();
resetEnemies();
if (lives <= 0) {
endGame();
return;
}
}
}
};
projectiles.forEach((projectile, projectileIndex) => {
const projectileY = parseInt(projectile.style.top) - 10;
if (projectileY < 0) {
gameContainer.removeChild(projectile);
projectiles.splice(projectileIndex, 1);
} else {
projectile.style.top = projectileY + 'px';
}
for (let pdfIndex = 0; pdfIndex < pdfs.length; pdfIndex++) {
const pdf = pdfs[pdfIndex];
if (collisionDetected(projectile, pdf)) {
gameContainer.removeChild(pdf);
gameContainer.removeChild(projectile);
pdfs.splice(pdfIndex, 1);
projectiles.splice(projectileIndex, 1);
score = score + 10;
updateScore();
break;
}
}
});
setTimeout(updateGame, 1000 / 60);
}
function resetGame() {
playerX = gameContainer.clientWidth / 2;
playerY = 50;
updatePlayerPosition();
pdfs.forEach((pdf) => gameContainer.removeChild(pdf));
projectiles.forEach((projectile) => gameContainer.removeChild(projectile));
pdfs.length = 0;
projectiles.length = 0;
score = 0;
level = 1;
lives = 3;
gameOver = false;
updateScore();
updateLives();
levelElement.textContent = 'Level: ' + level;
pdfSpeed = 1;
clearTimeout(spawnPdfTimeout); // Clear the existing spawnPdfTimeout
setTimeout(updateGame, 1000 / 60);
spawnPdfInterval();
}
function updateScore() {
scoreElement.textContent = 'Score: ' + score;
checkLevelUp();
}
function checkLevelUp() {
const newLevel = Math.floor(score / 100) + 1;
if (newLevel > level) {
level = newLevel;
levelElement.textContent = 'Level: ' + level;
pdfSpeed += 0.2;
}
}
function collisionDetected(a, b) {
const rectA = a.getBoundingClientRect();
const rectB = b.getBoundingClientRect();
return (
rectA.left < rectB.right &&
rectA.right > rectB.left &&
rectA.top < rectB.bottom &&
rectA.bottom > rectB.top
);
}
function endGame() {
gameOver = true;
if (score > highScore) {
highScore = score;
localStorage.setItem('highScore', highScore);
updateHighScore();
}
alert('Game Over! Your final score is: ' + score);
document.getElementById('game-container-wrapper').close();
}
let spawnPdfTimeout;
const BASE_SPAWN_INTERVAL_MS = 1250; // milliseconds before a new enemy spawns
const LEVEL_INCREASE_FACTOR_MS = 0; // milliseconds to decrease the spawn interval per level
const MAX_SPAWN_RATE_REDUCTION_MS = 800; // Max milliseconds from the base spawn interval
function spawnPdfInterval() {
console.log("spawnPdfInterval");
if (gameOver || paused) {
console.log("spawnPdfInterval 2");
clearTimeout(spawnPdfTimeout);
return;
}
console.log("spawnPdfInterval 3");
spawnPdf();
let spawnRateReduction = Math.min(level * LEVEL_INCREASE_FACTOR_MS, MAX_SPAWN_RATE_REDUCTION_MS);
let spawnRate = BASE_SPAWN_INTERVAL_MS - spawnRateReduction;
spawnPdfTimeout = setTimeout(spawnPdfInterval, spawnRate);
}
function resetGame() {
playerX = gameContainer.clientWidth / 2;
playerY = 50;
updatePlayerPosition();
pdfs.forEach((pdf) => gameContainer.removeChild(pdf));
projectiles.forEach((projectile) => gameContainer.removeChild(projectile));
pdfs.length = 0;
projectiles.length = 0;
score = 0;
level = 1;
lives = 3;
gameOver = false;
updateScore();
updateLives();
levelElement.textContent = "Level: " + level;
pdfSpeed = BASE_PDF_SPEED;
clearTimeout(spawnPdfTimeout); // Clear the existing spawnPdfTimeout
setTimeout(updateGame, 1000 / 60);
updateGame();
spawnPdfInterval();
}
function updateScore() {
scoreElement.textContent = "Score: " + score;
checkLevelUp();
}
function checkLevelUp() {
const newLevel = Math.floor(score / 100) + 1;
if (newLevel > level) {
level = newLevel;
levelElement.textContent = "Level: " + level;
pdfSpeed += LEVEL_INCREASE_PDF_SPEED;
}
}
document.addEventListener('visibilitychange', function() {
if (document.hidden) {
paused = true;
} else {
paused = false;
updateGame();
spawnPdfInterval();
}
function collisionDetected(a, b) {
const rectA = a.getBoundingClientRect();
const rectB = b.getBoundingClientRect();
return rectA.left < rectB.right && rectA.right > rectB.left && rectA.top < rectB.bottom && rectA.bottom > rectB.top;
}
});
function endGame() {
gameOver = true;
if (score > highScore) {
highScore = score;
localStorage.setItem("highScore", highScore);
updateHighScore();
}
alert("Game Over! Your final score is: " + score);
document.getElementById("game-container-wrapper").close();
}
let spawnPdfTimeout;
function spawnPdfInterval() {
if (gameOver || paused) {
clearTimeout(spawnPdfTimeout);
return;
}
spawnPdf();
let spawnRateReduction = Math.min(level * LEVEL_INCREASE_FACTOR_MS, MAX_SPAWN_RATE_REDUCTION_MS);
let spawnRate = BASE_SPAWN_INTERVAL_MS - spawnRateReduction;
spawnPdfTimeout = setTimeout(spawnPdfInterval, spawnRate);
}
updatePlayerPosition();
updateGame();
spawnPdfInterval();
document.addEventListener("visibilitychange", function () {
if (document.hidden) {
paused = true;
} else {
paused = false;
updateGame();
spawnPdfInterval();
}
});
window.resetGame = resetGame;
window.resetGame = resetGame;
}
window.initializeGame = initializeGame;

Some files were not shown because too many files have changed in this diff Show More