@ -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 |
@ -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"] |
||||
|
@ -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" |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
@ -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 |
||||
|
@ -1,6 +1,6 @@ |
||||
____ _____ ___ ____ _ ___ _ _ ____ ____ ____ _____ |
||||
____ _____ ___ ____ _ ___ _ _ ____ ____ ____ _____ |
||||
/ ___|_ _|_ _| _ \| | |_ _| \ | |/ ___| | _ \| _ \| ___| |
||||
\___ \ | | | || |_) | | | || \| | | _ _____| |_) | | | | |_ |
||||
___) || | | || _ <| |___ | || |\ | |_| |_____| __/| |_| | _| |
||||
|____/ |_| |___|_| \_\_____|___|_| \_|\____| |_| |____/|_| |
||||
\___ \ | | | || |_) | | | || \| | | _ _____| |_) | | | | |_ |
||||
___) || | | || _ <| |___ | || |\ | |_| |_____| __/| |_| | _| |
||||
|____/ |_| |___|_| \_\_____|___|_| \_|\____| |_| |____/|_| |
||||
Powered by Spring Boot ${spring-boot.version} |
@ -1,135 +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; |
||||
} |
||||
|
||||
|
@ -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; |
||||
} |
@ -1,29 +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; |
||||
|
||||
} |
||||
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 899 B After Width: | Height: | Size: 874 B |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 691 B After Width: | Height: | Size: 690 B |
@ -1,285 +1,285 @@ |
||||
class PdfContainer { |
||||
fileName; |
||||
pagesContainer; |
||||
pagesContainerWrapper; |
||||
pdfAdapters; |
||||
downloadLink; |
||||
|
||||
constructor(id, wrapperId, pdfAdapters) { |
||||
this.pagesContainer = document.getElementById(id) |
||||
this.pagesContainerWrapper = document.getElementById(wrapperId); |
||||
this.downloadLink = null; |
||||
this.movePageTo = this.movePageTo.bind(this); |
||||
this.addPdfs = this.addPdfs.bind(this); |
||||
this.addPdfsFromFiles = this.addPdfsFromFiles.bind(this); |
||||
this.rotateElement = this.rotateElement.bind(this); |
||||
this.rotateAll = this.rotateAll.bind(this); |
||||
this.exportPdf = this.exportPdf.bind(this); |
||||
this.updateFilename = this.updateFilename.bind(this); |
||||
this.setDownloadAttribute = this.setDownloadAttribute.bind(this); |
||||
this.preventIllegalChars = this.preventIllegalChars.bind(this); |
||||
|
||||
this.pdfAdapters = pdfAdapters; |
||||
|
||||
this.pdfAdapters.forEach(adapter => { |
||||
adapter.setActions({ |
||||
movePageTo: this.movePageTo, |
||||
addPdfs: this.addPdfs, |
||||
rotateElement: this.rotateElement, |
||||
updateFilename: this.updateFilename |
||||
}) |
||||
}) |
||||
|
||||
window.addPdfs = this.addPdfs; |
||||
window.exportPdf = this.exportPdf; |
||||
window.rotateAll = this.rotateAll; |
||||
|
||||
const filenameInput = document.getElementById('filename-input'); |
||||
const downloadBtn = document.getElementById('export-button'); |
||||
|
||||
filenameInput.onkeyup = this.updateFilename; |
||||
filenameInput.onkeydown = this.preventIllegalChars; |
||||
filenameInput.disabled = false; |
||||
filenameInput.innerText = ""; |
||||
downloadBtn.disabled = true; |
||||
} |
||||
|
||||
movePageTo(startElement, endElement, scrollTo = false) { |
||||
const childArray = Array.from(this.pagesContainer.childNodes); |
||||
const startIndex = childArray.indexOf(startElement); |
||||
const endIndex = childArray.indexOf(endElement); |
||||
this.pagesContainer.removeChild(startElement); |
||||
if(!endElement) { |
||||
this.pagesContainer.append(startElement); |
||||
} else { |
||||
this.pagesContainer.insertBefore(startElement, endElement); |
||||
} |
||||
|
||||
if(scrollTo) { |
||||
const { width } = startElement.getBoundingClientRect(); |
||||
const vector = (endIndex !== -1 && startIndex > endIndex) |
||||
? 0-width |
||||
: width; |
||||
|
||||
this.pagesContainerWrapper.scroll({ |
||||
left: this.pagesContainerWrapper.scrollLeft + vector, |
||||
}) |
||||
} |
||||
} |
||||
|
||||
addPdfs(nextSiblingElement) { |
||||
var input = document.createElement('input'); |
||||
input.type = 'file'; |
||||
input.multiple = true; |
||||
input.setAttribute("accept", "application/pdf"); |
||||
input.onchange = async(e) => { |
||||
const files = e.target.files; |
||||
|
||||
this.addPdfsFromFiles(files, nextSiblingElement); |
||||
this.updateFilename(files ? files[0].name : ""); |
||||
} |
||||
|
||||
input.click(); |
||||
} |
||||
|
||||
async addPdfsFromFiles(files, nextSiblingElement) { |
||||
this.fileName = files[0].name; |
||||
for (var i=0; i < files.length; i++) { |
||||
await this.addPdfFile(files[i], nextSiblingElement); |
||||
} |
||||
|
||||
document.querySelectorAll(".enable-on-file").forEach(element => { |
||||
element.disabled = false; |
||||
}); |
||||
} |
||||
|
||||
rotateElement(element, deg) { |
||||
var lastTransform = element.style.rotate; |
||||
if (!lastTransform) { |
||||
lastTransform = "0"; |
||||
} |
||||
const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, '')); |
||||
const newAngle = lastAngle + deg; |
||||
|
||||
element.style.rotate = newAngle + "deg"; |
||||
} |
||||
|
||||
async addPdfFile(file, nextSiblingElement) { |
||||
const { renderer, pdfDocument } = await this.loadFile(file); |
||||
|
||||
for (var i=0; i < renderer.pageCount; i++) { |
||||
const div = document.createElement('div'); |
||||
|
||||
div.classList.add("page-container"); |
||||
|
||||
var img = document.createElement('img'); |
||||
img.classList.add('page-image') |
||||
const imageSrc = await renderer.renderPage(i) |
||||
img.src = imageSrc; |
||||
img.pageIdx = i; |
||||
img.rend = renderer; |
||||
img.doc = pdfDocument; |
||||
div.appendChild(img); |
||||
|
||||
this.pdfAdapters.forEach((adapter) => { |
||||
adapter.adapt?.(div) |
||||
}) |
||||
if (nextSiblingElement) { |
||||
this.pagesContainer.insertBefore(div, nextSiblingElement); |
||||
} else { |
||||
this.pagesContainer.appendChild(div); |
||||
} |
||||
} |
||||
} |
||||
|
||||
async loadFile(file) { |
||||
var objectUrl = URL.createObjectURL(file); |
||||
var pdfDocument = await this.toPdfLib(objectUrl); |
||||
var renderer = await this.toRenderer(objectUrl); |
||||
return { renderer, pdfDocument }; |
||||
} |
||||
|
||||
async toRenderer(objectUrl) { |
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js' |
||||
const pdf = await pdfjsLib.getDocument(objectUrl).promise; |
||||
return { |
||||
document: pdf, |
||||
pageCount: pdf.numPages, |
||||
renderPage: async function(pageIdx) { |
||||
const page = await this.document.getPage(pageIdx+1); |
||||
|
||||
const canvas = document.createElement("canvas"); |
||||
|
||||
// set the canvas size to the size of the page
|
||||
if (page.rotate == 90 || page.rotate == 270) { |
||||
canvas.width = page.view[3]; |
||||
canvas.height = page.view[2]; |
||||
} else { |
||||
canvas.width = page.view[2]; |
||||
canvas.height = page.view[3]; |
||||
} |
||||
|
||||
// render the page onto the canvas
|
||||
var renderContext = { |
||||
canvasContext: canvas.getContext("2d"), |
||||
viewport: page.getViewport({ scale: 1 }) |
||||
}; |
||||
|
||||
await page.render(renderContext).promise; |
||||
return canvas.toDataURL(); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
async toPdfLib(objectUrl) { |
||||
const existingPdfBytes = await fetch(objectUrl).then(res => res.arrayBuffer()); |
||||
const pdfDoc = await PDFLib.PDFDocument.load(existingPdfBytes, { ignoreEncryption: true }); |
||||
return pdfDoc; |
||||
} |
||||
|
||||
|
||||
|
||||
rotateAll(deg) { |
||||
for (var i=0; i<this.pagesContainer.childNodes.length; i++) { |
||||
const img = this.pagesContainer.childNodes[i].querySelector("img"); |
||||
if (!img) continue; |
||||
this.rotateElement(img, deg) |
||||
} |
||||
} |
||||
|
||||
async exportPdf() { |
||||
const pdfDoc = await PDFLib.PDFDocument.create(); |
||||
const pageContainers = this.pagesContainer.querySelectorAll('.page-container'); // Select all .page-container elements
|
||||
for (var i = 0; i < pageContainers.length; i++) { |
||||
const img = pageContainers[i].querySelector("img"); // Find the img element within each .page-container
|
||||
if (!img) continue; |
||||
const pages = await pdfDoc.copyPages(img.doc, [img.pageIdx]) |
||||
const page = pages[0]; |
||||
|
||||
const rotation = img.style.rotate; |
||||
if (rotation) { |
||||
const rotationAngle = parseInt(rotation.replace(/[^\d-]/g, '')); |
||||
page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle)) |
||||
} |
||||
|
||||
pdfDoc.addPage(page); |
||||
} |
||||
const pdfBytes = await pdfDoc.save(); |
||||
const pdfBlob = new Blob([pdfBytes], { type: 'application/pdf' }); |
||||
const url = URL.createObjectURL(pdfBlob); |
||||
const downloadOption = localStorage.getItem('downloadOption'); |
||||
|
||||
const filenameInput = document.getElementById('filename-input'); |
||||
|
||||
let inputArr = filenameInput.value.split('.'); |
||||
|
||||
if (inputArr !== null && inputArr !== undefined && inputArr.length > 0) { |
||||
|
||||
inputArr = inputArr.filter(n => n); // remove all empty strings, nulls or undefined
|
||||
|
||||
if (inputArr.length > 1) { |
||||
inputArr.pop(); // remove right part after last dot
|
||||
} |
||||
|
||||
filenameInput.value = inputArr.join(''); |
||||
this.fileName = filenameInput.value; |
||||
} |
||||
|
||||
if (!filenameInput.value.includes('.pdf')) { |
||||
filenameInput.value = filenameInput.value + '.pdf'; |
||||
this.fileName = filenameInput.value; |
||||
} |
||||
|
||||
if (downloadOption === 'sameWindow') { |
||||
// Open the file in the same window
|
||||
window.location.href = url; |
||||
} else if (downloadOption === 'newWindow') { |
||||
// Open the file in a new window
|
||||
window.open(url, '_blank'); |
||||
} else { |
||||
// Download the file
|
||||
this.downloadLink = document.createElement('a'); |
||||
this.downloadLink.id = 'download-link'; |
||||
this.downloadLink.href = url; |
||||
// downloadLink.download = this.fileName ? this.fileName : 'managed.pdf';
|
||||
// downloadLink.download = this.fileName;
|
||||
this.downloadLink.setAttribute('download', this.fileName ? this.fileName : 'managed.pdf'); |
||||
this.downloadLink.setAttribute('target', '_blank'); |
||||
this.downloadLink.onclick = this.setDownloadAttribute; |
||||
this.downloadLink.click(); |
||||
} |
||||
} |
||||
|
||||
setDownloadAttribute() { |
||||
this.downloadLink.setAttribute("download", this.fileName ? this.fileName : 'managed.pdf'); |
||||
} |
||||
|
||||
updateFilename(fileName = "") { |
||||
const filenameInput = document.getElementById('filename-input'); |
||||
const pagesContainer = document.getElementById('pages-container'); |
||||
const downloadBtn = document.getElementById('export-button'); |
||||
|
||||
downloadBtn.disabled = pagesContainer.childElementCount === 0 |
||||
|
||||
if (!this.fileName) { |
||||
this.fileName = fileName; |
||||
} |
||||
|
||||
if (!filenameInput.value) { |
||||
filenameInput.value = this.fileName; |
||||
} |
||||
} |
||||
|
||||
preventIllegalChars(e) { |
||||
// const filenameInput = document.getElementById('filename-input');
|
||||
//
|
||||
// filenameInput.value = filenameInput.value.replace('.pdf', '');
|
||||
//
|
||||
// // prevent .
|
||||
// if (filenameInput.value.includes('.')) {
|
||||
// filenameInput.value.replace('.','');
|
||||
// }
|
||||
} |
||||
} |
||||
|
||||
export default PdfContainer; |
||||
class PdfContainer { |
||||
fileName; |
||||
pagesContainer; |
||||
pagesContainerWrapper; |
||||
pdfAdapters; |
||||
downloadLink; |
||||
|
||||
constructor(id, wrapperId, pdfAdapters) { |
||||
this.pagesContainer = document.getElementById(id) |
||||
this.pagesContainerWrapper = document.getElementById(wrapperId); |
||||
this.downloadLink = null; |
||||
this.movePageTo = this.movePageTo.bind(this); |
||||
this.addPdfs = this.addPdfs.bind(this); |
||||
this.addPdfsFromFiles = this.addPdfsFromFiles.bind(this); |
||||
this.rotateElement = this.rotateElement.bind(this); |
||||
this.rotateAll = this.rotateAll.bind(this); |
||||
this.exportPdf = this.exportPdf.bind(this); |
||||
this.updateFilename = this.updateFilename.bind(this); |
||||
this.setDownloadAttribute = this.setDownloadAttribute.bind(this); |
||||
this.preventIllegalChars = this.preventIllegalChars.bind(this); |
||||
|
||||
this.pdfAdapters = pdfAdapters; |
||||
|
||||
this.pdfAdapters.forEach(adapter => { |
||||
adapter.setActions({ |
||||
movePageTo: this.movePageTo, |
||||
addPdfs: this.addPdfs, |
||||
rotateElement: this.rotateElement, |
||||
updateFilename: this.updateFilename |
||||
}) |
||||
}) |
||||
|
||||
window.addPdfs = this.addPdfs; |
||||
window.exportPdf = this.exportPdf; |
||||
window.rotateAll = this.rotateAll; |
||||
|
||||
const filenameInput = document.getElementById('filename-input'); |
||||
const downloadBtn = document.getElementById('export-button'); |
||||
|
||||
filenameInput.onkeyup = this.updateFilename; |
||||
filenameInput.onkeydown = this.preventIllegalChars; |
||||
filenameInput.disabled = false; |
||||
filenameInput.innerText = ""; |
||||
downloadBtn.disabled = true; |
||||
} |
||||
|
||||
movePageTo(startElement, endElement, scrollTo = false) { |
||||
const childArray = Array.from(this.pagesContainer.childNodes); |
||||
const startIndex = childArray.indexOf(startElement); |
||||
const endIndex = childArray.indexOf(endElement); |
||||
this.pagesContainer.removeChild(startElement); |
||||
if(!endElement) { |
||||
this.pagesContainer.append(startElement); |
||||
} else { |
||||
this.pagesContainer.insertBefore(startElement, endElement); |
||||
} |
||||
|
||||
if(scrollTo) { |
||||
const { width } = startElement.getBoundingClientRect(); |
||||
const vector = (endIndex !== -1 && startIndex > endIndex) |
||||
? 0-width |
||||
: width; |
||||
|
||||
this.pagesContainerWrapper.scroll({ |
||||
left: this.pagesContainerWrapper.scrollLeft + vector, |
||||
}) |
||||
} |
||||
} |
||||
|
||||
addPdfs(nextSiblingElement) { |
||||
var input = document.createElement('input'); |
||||
input.type = 'file'; |
||||
input.multiple = true; |
||||
input.setAttribute("accept", "application/pdf"); |
||||
input.onchange = async(e) => { |
||||
const files = e.target.files; |
||||
|
||||
this.addPdfsFromFiles(files, nextSiblingElement); |
||||
this.updateFilename(files ? files[0].name : ""); |
||||
} |
||||
|
||||
input.click(); |
||||
} |
||||
|
||||
async addPdfsFromFiles(files, nextSiblingElement) { |
||||
this.fileName = files[0].name; |
||||
for (var i=0; i < files.length; i++) { |
||||
await this.addPdfFile(files[i], nextSiblingElement); |
||||
} |
||||
|
||||
document.querySelectorAll(".enable-on-file").forEach(element => { |
||||
element.disabled = false; |
||||
}); |
||||
} |
||||
|
||||
rotateElement(element, deg) { |
||||
var lastTransform = element.style.rotate; |
||||
if (!lastTransform) { |
||||
lastTransform = "0"; |
||||
} |
||||
const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, '')); |
||||
const newAngle = lastAngle + deg; |
||||
|
||||
element.style.rotate = newAngle + "deg"; |
||||
} |
||||
|
||||
async addPdfFile(file, nextSiblingElement) { |
||||
const { renderer, pdfDocument } = await this.loadFile(file); |
||||
|
||||
for (var i=0; i < renderer.pageCount; i++) { |
||||
const div = document.createElement('div'); |
||||
|
||||
div.classList.add("page-container"); |
||||
|
||||
var img = document.createElement('img'); |
||||
img.classList.add('page-image') |
||||
const imageSrc = await renderer.renderPage(i) |
||||
img.src = imageSrc; |
||||
img.pageIdx = i; |
||||
img.rend = renderer; |
||||
img.doc = pdfDocument; |
||||
div.appendChild(img); |
||||
|
||||
this.pdfAdapters.forEach((adapter) => { |
||||
adapter.adapt?.(div) |
||||
}) |
||||
if (nextSiblingElement) { |
||||
this.pagesContainer.insertBefore(div, nextSiblingElement); |
||||
} else { |
||||
this.pagesContainer.appendChild(div); |
||||
} |
||||
} |
||||
} |
||||
|
||||
async loadFile(file) { |
||||
var objectUrl = URL.createObjectURL(file); |
||||
var pdfDocument = await this.toPdfLib(objectUrl); |
||||
var renderer = await this.toRenderer(objectUrl); |
||||
return { renderer, pdfDocument }; |
||||
} |
||||
|
||||
async toRenderer(objectUrl) { |
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js' |
||||
const pdf = await pdfjsLib.getDocument(objectUrl).promise; |
||||
return { |
||||
document: pdf, |
||||
pageCount: pdf.numPages, |
||||
renderPage: async function(pageIdx) { |
||||
const page = await this.document.getPage(pageIdx+1); |
||||
|
||||
const canvas = document.createElement("canvas"); |
||||
|
||||
// set the canvas size to the size of the page
|
||||
if (page.rotate == 90 || page.rotate == 270) { |
||||
canvas.width = page.view[3]; |
||||
canvas.height = page.view[2]; |
||||
} else { |
||||
canvas.width = page.view[2]; |
||||
canvas.height = page.view[3]; |
||||
} |
||||
|
||||
// render the page onto the canvas
|
||||
var renderContext = { |
||||
canvasContext: canvas.getContext("2d"), |
||||
viewport: page.getViewport({ scale: 1 }) |
||||
}; |
||||
|
||||
await page.render(renderContext).promise; |
||||
return canvas.toDataURL(); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
async toPdfLib(objectUrl) { |
||||
const existingPdfBytes = await fetch(objectUrl).then(res => res.arrayBuffer()); |
||||
const pdfDoc = await PDFLib.PDFDocument.load(existingPdfBytes, { ignoreEncryption: true }); |
||||
return pdfDoc; |
||||
} |
||||
|
||||
|
||||
|
||||
rotateAll(deg) { |
||||
for (var i=0; i<this.pagesContainer.childNodes.length; i++) { |
||||
const img = this.pagesContainer.childNodes[i].querySelector("img"); |
||||
if (!img) continue; |
||||
this.rotateElement(img, deg) |
||||
} |
||||
} |
||||
|
||||
async exportPdf() { |
||||
const pdfDoc = await PDFLib.PDFDocument.create(); |
||||
const pageContainers = this.pagesContainer.querySelectorAll('.page-container'); // Select all .page-container elements
|
||||
for (var i = 0; i < pageContainers.length; i++) { |
||||
const img = pageContainers[i].querySelector("img"); // Find the img element within each .page-container
|
||||
if (!img) continue; |
||||
const pages = await pdfDoc.copyPages(img.doc, [img.pageIdx]) |
||||
const page = pages[0]; |
||||
|
||||
const rotation = img.style.rotate; |
||||
if (rotation) { |
||||
const rotationAngle = parseInt(rotation.replace(/[^\d-]/g, '')); |
||||
page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle)) |
||||
} |
||||
|
||||
pdfDoc.addPage(page); |
||||
} |
||||
const pdfBytes = await pdfDoc.save(); |
||||
const pdfBlob = new Blob([pdfBytes], { type: 'application/pdf' }); |
||||
const url = URL.createObjectURL(pdfBlob); |
||||
const downloadOption = localStorage.getItem('downloadOption'); |
||||
|
||||
const filenameInput = document.getElementById('filename-input'); |
||||
|
||||
let inputArr = filenameInput.value.split('.'); |
||||
|
||||
if (inputArr !== null && inputArr !== undefined && inputArr.length > 0) { |
||||
|
||||
inputArr = inputArr.filter(n => n); // remove all empty strings, nulls or undefined
|
||||
|
||||
if (inputArr.length > 1) { |
||||
inputArr.pop(); // remove right part after last dot
|
||||
} |
||||
|
||||
filenameInput.value = inputArr.join(''); |
||||
this.fileName = filenameInput.value; |
||||
} |
||||
|
||||
if (!filenameInput.value.includes('.pdf')) { |
||||
filenameInput.value = filenameInput.value + '.pdf'; |
||||
this.fileName = filenameInput.value; |
||||
} |
||||
|
||||
if (downloadOption === 'sameWindow') { |
||||
// Open the file in the same window
|
||||
window.location.href = url; |
||||
} else if (downloadOption === 'newWindow') { |
||||
// Open the file in a new window
|
||||
window.open(url, '_blank'); |
||||
} else { |
||||
// Download the file
|
||||
this.downloadLink = document.createElement('a'); |
||||
this.downloadLink.id = 'download-link'; |
||||
this.downloadLink.href = url; |
||||
// downloadLink.download = this.fileName ? this.fileName : 'managed.pdf';
|
||||
// downloadLink.download = this.fileName;
|
||||
this.downloadLink.setAttribute('download', this.fileName ? this.fileName : 'managed.pdf'); |
||||
this.downloadLink.setAttribute('target', '_blank'); |
||||
this.downloadLink.onclick = this.setDownloadAttribute; |
||||
this.downloadLink.click(); |
||||
} |
||||
} |
||||
|
||||
setDownloadAttribute() { |
||||
this.downloadLink.setAttribute("download", this.fileName ? this.fileName : 'managed.pdf'); |
||||
} |
||||
|
||||
updateFilename(fileName = "") { |
||||
const filenameInput = document.getElementById('filename-input'); |
||||
const pagesContainer = document.getElementById('pages-container'); |
||||
const downloadBtn = document.getElementById('export-button'); |
||||
|
||||
downloadBtn.disabled = pagesContainer.childElementCount === 0 |
||||
|
||||
if (!this.fileName) { |
||||
this.fileName = fileName; |
||||
} |
||||
|
||||
if (!filenameInput.value) { |
||||
filenameInput.value = this.fileName; |
||||
} |
||||
} |
||||
|
||||
preventIllegalChars(e) { |
||||
// const filenameInput = document.getElementById('filename-input');
|
||||
//
|
||||
// filenameInput.value = filenameInput.value.replace('.pdf', '');
|
||||
//
|
||||
// // prevent .
|
||||
// if (filenameInput.value.includes('.')) {
|
||||
// filenameInput.value.replace('.','');
|
||||
// }
|
||||
} |
||||
} |
||||
|
||||
export default PdfContainer; |
||||
|
@ -1,75 +1,75 @@ |
||||
// Toggle search bar when the search icon is clicked
|
||||
document.querySelector('#search-icon').addEventListener('click', function(e) { |
||||
e.preventDefault(); |
||||
var searchBar = document.querySelector('#navbarSearch'); |
||||
searchBar.classList.toggle('show'); |
||||
}); |
||||
window.onload = function() { |
||||
var items = document.querySelectorAll('.dropdown-item, .nav-link'); |
||||
var dummyContainer = document.createElement('div'); |
||||
dummyContainer.style.position = 'absolute'; |
||||
dummyContainer.style.visibility = 'hidden'; |
||||
dummyContainer.style.whiteSpace = 'nowrap'; // Ensure we measure full width
|
||||
document.body.appendChild(dummyContainer); |
||||
|
||||
var maxWidth = 0; |
||||
|
||||
items.forEach(function(item) { |
||||
var clone = item.cloneNode(true); |
||||
dummyContainer.appendChild(clone); |
||||
var width = clone.offsetWidth; |
||||
if (width > maxWidth) { |
||||
maxWidth = width; |
||||
} |
||||
dummyContainer.removeChild(clone); |
||||
}); |
||||
|
||||
document.body.removeChild(dummyContainer); |
||||
|
||||
// Store max width for later use
|
||||
window.navItemMaxWidth = maxWidth; |
||||
}; |
||||
|
||||
// Show search results as user types in search box
|
||||
document.querySelector('#navbarSearchInput').addEventListener('input', function(e) { |
||||
var searchText = e.target.value.toLowerCase(); |
||||
var items = document.querySelectorAll('.dropdown-item, .nav-link'); |
||||
var resultsBox = document.querySelector('#searchResults'); |
||||
|
||||
// Clear any previous results
|
||||
resultsBox.innerHTML = ''; |
||||
|
||||
items.forEach(function(item) { |
||||
var titleElement = item.querySelector('.icon-text'); |
||||
var iconElement = item.querySelector('.icon'); |
||||
var itemHref = item.getAttribute('href'); |
||||
var tags = item.getAttribute('data-bs-tags') || ""; // If no tags, default to empty string
|
||||
|
||||
if (titleElement && iconElement && itemHref !== '#') { |
||||
var title = titleElement.innerText; |
||||
if ((title.toLowerCase().indexOf(searchText) !== -1 || tags.toLowerCase().indexOf(searchText) !== -1) && !resultsBox.querySelector(`a[href="${item.getAttribute('href')}"]`)) { |
||||
var result = document.createElement('a'); |
||||
result.href = itemHref; |
||||
result.classList.add('dropdown-item'); |
||||
|
||||
var resultIcon = document.createElement('img'); |
||||
resultIcon.src = iconElement.src; |
||||
resultIcon.alt = 'icon'; |
||||
resultIcon.classList.add('icon'); |
||||
result.appendChild(resultIcon); |
||||
|
||||
var resultText = document.createElement('span'); |
||||
resultText.textContent = title; |
||||
resultText.classList.add('icon-text'); |
||||
result.appendChild(resultText); |
||||
|
||||
resultsBox.appendChild(result); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
// Set the width of the search results box to the maximum width
|
||||
resultsBox.style.width = window.navItemMaxWidth + 'px'; |
||||
}); |
||||
|
||||
|
||||
// Toggle search bar when the search icon is clicked
|
||||
document.querySelector('#search-icon').addEventListener('click', function(e) { |
||||
e.preventDefault(); |
||||
var searchBar = document.querySelector('#navbarSearch'); |
||||
searchBar.classList.toggle('show'); |
||||
}); |
||||
window.onload = function() { |
||||
var items = document.querySelectorAll('.dropdown-item, .nav-link'); |
||||
var dummyContainer = document.createElement('div'); |
||||
dummyContainer.style.position = 'absolute'; |
||||
dummyContainer.style.visibility = 'hidden'; |
||||
dummyContainer.style.whiteSpace = 'nowrap'; // Ensure we measure full width
|
||||
document.body.appendChild(dummyContainer); |
||||
|
||||
var maxWidth = 0; |
||||
|
||||
items.forEach(function(item) { |
||||
var clone = item.cloneNode(true); |
||||
dummyContainer.appendChild(clone); |
||||
var width = clone.offsetWidth; |
||||
if (width > maxWidth) { |
||||
maxWidth = width; |
||||
} |
||||
dummyContainer.removeChild(clone); |
||||
}); |
||||
|
||||
document.body.removeChild(dummyContainer); |
||||
|
||||
// Store max width for later use
|
||||
window.navItemMaxWidth = maxWidth; |
||||
}; |
||||
|
||||
// Show search results as user types in search box
|
||||
document.querySelector('#navbarSearchInput').addEventListener('input', function(e) { |
||||
var searchText = e.target.value.toLowerCase(); |
||||
var items = document.querySelectorAll('.dropdown-item, .nav-link'); |
||||
var resultsBox = document.querySelector('#searchResults'); |
||||
|
||||
// Clear any previous results
|
||||
resultsBox.innerHTML = ''; |
||||
|
||||
items.forEach(function(item) { |
||||
var titleElement = item.querySelector('.icon-text'); |
||||
var iconElement = item.querySelector('.icon'); |
||||
var itemHref = item.getAttribute('href'); |
||||
var tags = item.getAttribute('data-bs-tags') || ""; // If no tags, default to empty string
|
||||
|
||||
if (titleElement && iconElement && itemHref !== '#') { |
||||
var title = titleElement.innerText; |
||||
if ((title.toLowerCase().indexOf(searchText) !== -1 || tags.toLowerCase().indexOf(searchText) !== -1) && !resultsBox.querySelector(`a[href="${item.getAttribute('href')}"]`)) { |
||||
var result = document.createElement('a'); |
||||
result.href = itemHref; |
||||
result.classList.add('dropdown-item'); |
||||
|
||||
var resultIcon = document.createElement('img'); |
||||
resultIcon.src = iconElement.src; |
||||
resultIcon.alt = 'icon'; |
||||
resultIcon.classList.add('icon'); |
||||
result.appendChild(resultIcon); |
||||
|
||||
var resultText = document.createElement('span'); |
||||
resultText.textContent = title; |
||||
resultText.classList.add('icon-text'); |
||||
result.appendChild(resultText); |
||||
|
||||
resultsBox.appendChild(result); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
// Set the width of the search results box to the maximum width
|
||||
resultsBox.style.width = window.navItemMaxWidth + 'px'; |
||||
}); |
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 931 B After Width: | Height: | Size: 930 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@ -1,30 +1,30 @@ |
||||
<!DOCTYPE html> |
||||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> |
||||
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{BookToPDF.title}, header=#{BookToPDF.header})}"></th:block>
|
||||
<body> |
||||
<th:block th:insert="~{fragments/common :: game}"></th:block> |
||||
<div id="page-container"> |
||||
<div id="content-wrap"> |
||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div> |
||||
<br> <br> |
||||
<div class="container"> |
||||
<div class="row justify-content-center"> |
||||
<div class="col-md-6"> |
||||
<h2 th:text="#{BookToPDF.header}"></h2> |
||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/book/pdf}"> |
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> |
||||
<br> |
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{BookToPDF.submit}"></button> |
||||
|
||||
</form> |
||||
<p class="mt-3" th:text="#{BookToPDF.help}"></p> |
||||
<p class="mt-3" th:text="#{BookToPDF.credit}"></p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div th:insert="~{fragments/footer.html :: footer}"></div> |
||||
</div> |
||||
</body> |
||||
</html> |
||||
<!DOCTYPE html> |
||||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> |
||||
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{BookToPDF.title}, header=#{BookToPDF.header})}"></th:block> |
||||
<body> |
||||
<th:block th:insert="~{fragments/common :: game}"></th:block> |
||||
<div id="page-container"> |
||||
<div id="content-wrap"> |
||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div> |
||||
<br> <br> |
||||
<div class="container"> |
||||
<div class="row justify-content-center"> |
||||
<div class="col-md-6"> |
||||
<h2 th:text="#{BookToPDF.header}"></h2> |
||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/book/pdf}"> |
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> |
||||
<br> |
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{BookToPDF.submit}"></button> |
||||
|
||||
</form> |
||||
<p class="mt-3" th:text="#{BookToPDF.help}"></p> |
||||
<p class="mt-3" th:text="#{BookToPDF.credit}"></p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div th:insert="~{fragments/footer.html :: footer}"></div> |
||||
</div> |
||||
</body> |
||||
</html> |
||||
|
@ -1,36 +1,36 @@ |
||||
<!DOCTYPE html> |
||||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> |
||||
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{HTMLToPDF.title}, header=#{HTMLToPDF.header})}"></th:block>
|
||||
<body> |
||||
<th:block th:insert="~{fragments/common :: game}"></th:block> |
||||
<div id="page-container"> |
||||
<div id="content-wrap"> |
||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div> |
||||
<br> <br> |
||||
<div class="container"> |
||||
<div class="row justify-content-center"> |
||||
<div class="mb-3"> |
||||
<h2 th:text="#{HTMLToPDF.header}"></h2> |
||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/html/pdf}"> |
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='text/html,application/zip' )}"></div> |
||||
|
||||
<div class="mb-3"> |
||||
<label for="zoom" th:text="#{HTMLToPDF.zoom}" class="form-label"></label> |
||||
<input type="number" step="0.1" class="form-control" id="zoom" name="zoom" value="1" /> |
||||
</div> |
||||
|
||||
<br> |
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{HTMLToPDF.submit}"></button> |
||||
|
||||
</form> |
||||
<p class="mt-3" th:text="#{HTMLToPDF.help}"></p> |
||||
<p class="mt-3" th:text="#{HTMLToPDF.credit}"></p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div th:insert="~{fragments/footer.html :: footer}"></div> |
||||
</div> |
||||
</body> |
||||
</html> |
||||
<!DOCTYPE html> |
||||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> |
||||
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{HTMLToPDF.title}, header=#{HTMLToPDF.header})}"></th:block> |
||||
<body> |
||||
<th:block th:insert="~{fragments/common :: game}"></th:block> |
||||
<div id="page-container"> |
||||
<div id="content-wrap"> |
||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div> |
||||
<br> <br> |
||||
<div class="container"> |
||||
<div class="row justify-content-center"> |
||||
<div class="mb-3"> |
||||
<h2 th:text="#{HTMLToPDF.header}"></h2> |
||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/html/pdf}"> |
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='text/html,application/zip' )}"></div> |
||||
|
||||
<div class="mb-3"> |
||||
<label for="zoom" th:text="#{HTMLToPDF.zoom}" class="form-label"></label> |
||||
<input type="number" step="0.1" class="form-control" id="zoom" name="zoom" value="1" /> |
||||
</div> |
||||
|
||||
<br> |
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{HTMLToPDF.submit}"></button> |
||||
|
||||
</form> |
||||
<p class="mt-3" th:text="#{HTMLToPDF.help}"></p> |
||||
<p class="mt-3" th:text="#{HTMLToPDF.credit}"></p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div th:insert="~{fragments/footer.html :: footer}"></div> |
||||
</div> |
||||
</body> |
||||
</html> |
||||
|
@ -1,92 +1,92 @@ |
||||
<!DOCTYPE html> |
||||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> |
||||
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{imageToPDF.title}, header=#{imageToPDF.header})}"></th:block>
|
||||
|
||||
|
||||
<body> |
||||
<th:block th:insert="~{fragments/common :: game}"></th:block> |
||||
<div id="page-container"> |
||||
<div id="content-wrap"> |
||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div> |
||||
<br> <br> |
||||
<div class="container"> |
||||
<div class="row justify-content-center"> |
||||
<div class="col-md-6"> |
||||
<h2 th:text="#{imageToPDF.header}"></h2> |
||||
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/img/pdf}"> |
||||
|
||||
|
||||
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*', inputText=#{imgPrompt})}"></div> |
||||
|
||||
<div class="mb-3"> |
||||
<label for="fitOption" th:text="#{imageToPDF.selectLabel}">Fit Options</label> |
||||
<select class="form-control" id="fitOption" name="fitOption"> |
||||
<option value="fillPage" th:text="#{imageToPDF.fillPage}">Fill Page</option> |
||||
<option value="fitDocumentToImage" th:text="#{imageToPDF.fitDocumentToImage}">Fit Document to Image</option> |
||||
<option value="maintainAspectRatio" th:text="#{imageToPDF.maintainAspectRatio}">Maintain Aspect Ratio</option> |
||||
</select> |
||||
</div> |
||||
|
||||
|
||||
<div class="form-check"> |
||||
<input type="checkbox" class="form-check-input" name="autoRotate" id="autoRotate"> |
||||
<label class="ms-3" for="autoRotate" th:text=#{imageToPDF.selectText.2}></label> |
||||
</div> |
||||
<div class="mb-3"> |
||||
<label th:text="#{pdfToImage.colorType}"></label> |
||||
<select class="form-control" id="colorType" name="colorType"> |
||||
<option value="color" th:text="#{pdfToImage.color}"></option> |
||||
<option value="greyscale" th:text="#{pdfToImage.grey}"></option> |
||||
<option value="blackwhite" th:text="#{pdfToImage.blackwhite}"></option> |
||||
</select> |
||||
</div> |
||||
<br> |
||||
<input type="hidden" id="override" name="override" value="multi"> |
||||
<div class="mb-3"> |
||||
<label th:text=#{imageToPDF.selectText.3}></label> |
||||
<select class="form-control" id="conversionType" name="conversionType" disabled> |
||||
<option value="merge" th:text=#{imageToPDF.selectText.4}></option> |
||||
<option value="convert" th:text=#{imageToPDF.selectText.5} selected></option> |
||||
</select> |
||||
</div> |
||||
|
||||
<br> <br> |
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{imageToPDF.submit}"></button> |
||||
<script> |
||||
$('#fileInput-input').on('change', function() { |
||||
var files = document.getElementById("fileInput-input").files; |
||||
var conversionType = document.getElementById("conversionType"); |
||||
console.log("files.length=" + files.length) |
||||
if (files.length > 1) { |
||||
conversionType.disabled = false; |
||||
} else { |
||||
conversionType.disabled = true; |
||||
} |
||||
}); |
||||
|
||||
$('#conversionType').change(function() { |
||||
var selectedValue = $(this).val(); |
||||
var override = document.getElementById("override"); |
||||
console.log("selectedValue=" + selectedValue) |
||||
if (selectedValue === 'merge') { |
||||
override.value = "single"; |
||||
} else if (selectedValue === 'convert') { |
||||
override.value = "multi"; |
||||
} |
||||
}); |
||||
|
||||
</script> |
||||
|
||||
</form> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
</div> |
||||
<div th:insert="~{fragments/footer.html :: footer}"></div> |
||||
</div> |
||||
</body> |
||||
<!DOCTYPE html> |
||||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> |
||||
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{imageToPDF.title}, header=#{imageToPDF.header})}"></th:block> |
||||
|
||||
|
||||
<body> |
||||
<th:block th:insert="~{fragments/common :: game}"></th:block> |
||||
<div id="page-container"> |
||||
<div id="content-wrap"> |
||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div> |
||||
<br> <br> |
||||
<div class="container"> |
||||
<div class="row justify-content-center"> |
||||
<div class="col-md-6"> |
||||
<h2 th:text="#{imageToPDF.header}"></h2> |
||||
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/img/pdf}"> |
||||
|
||||
|
||||
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*', inputText=#{imgPrompt})}"></div> |
||||
|
||||
<div class="mb-3"> |
||||
<label for="fitOption" th:text="#{imageToPDF.selectLabel}">Fit Options</label> |
||||
<select class="form-control" id="fitOption" name="fitOption"> |
||||
<option value="fillPage" th:text="#{imageToPDF.fillPage}">Fill Page</option> |
||||
<option value="fitDocumentToImage" th:text="#{imageToPDF.fitDocumentToImage}">Fit Document to Image</option> |
||||
<option value="maintainAspectRatio" th:text="#{imageToPDF.maintainAspectRatio}">Maintain Aspect Ratio</option> |
||||
</select> |
||||
</div> |
||||
|
||||
|
||||
<div class="form-check"> |
||||
<input type="checkbox" class="form-check-input" name="autoRotate" id="autoRotate"> |
||||
<label class="ms-3" for="autoRotate" th:text=#{imageToPDF.selectText.2}></label> |
||||
</div> |
||||
<div class="mb-3"> |
||||
<label th:text="#{pdfToImage.colorType}"></label> |
||||
<select class="form-control" id="colorType" name="colorType"> |
||||
<option value="color" th:text="#{pdfToImage.color}"></option> |
||||
<option value="greyscale" th:text="#{pdfToImage.grey}"></option> |
||||
<option value="blackwhite" th:text="#{pdfToImage.blackwhite}"></option> |
||||
</select> |
||||
</div> |
||||
<br> |
||||
<input type="hidden" id="override" name="override" value="multi"> |
||||
<div class="mb-3"> |
||||
<label th:text=#{imageToPDF.selectText.3}></label> |
||||
<select class="form-control" id="conversionType" name="conversionType" disabled> |
||||
<option value="merge" th:text=#{imageToPDF.selectText.4}></option> |
||||
<option value="convert" th:text=#{imageToPDF.selectText.5} selected></option> |
||||
</select> |
||||
</div> |
||||
|
||||
<br> <br> |
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{imageToPDF.submit}"></button> |
||||
<script> |
||||
$('#fileInput-input').on('change', function() { |
||||
var files = document.getElementById("fileInput-input").files; |
||||
var conversionType = document.getElementById("conversionType"); |
||||
console.log("files.length=" + files.length) |
||||
if (files.length > 1) { |
||||
conversionType.disabled = false; |
||||
} else { |
||||
conversionType.disabled = true; |
||||
} |
||||
}); |
||||
|
||||
$('#conversionType').change(function() { |
||||
var selectedValue = $(this).val(); |
||||
var override = document.getElementById("override"); |
||||
console.log("selectedValue=" + selectedValue) |
||||
if (selectedValue === 'merge') { |
||||
override.value = "single"; |
||||
} else if (selectedValue === 'convert') { |
||||
override.value = "multi"; |
||||
} |
||||
}); |
||||
|
||||
</script> |
||||
|
||||
</form> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
</div> |
||||
<div th:insert="~{fragments/footer.html :: footer}"></div> |
||||
</div> |
||||
</body> |
||||
</html> |
@ -1,29 +1,29 @@ |
||||
<!DOCTYPE html> |
||||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> |
||||
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{PDFToHTML.title}, header=#{PDFToHTML.header})}"></th:block>
|
||||
<body> |
||||
<th:block th:insert="~{fragments/common :: game}"></th:block> |
||||
<div id="page-container"> |
||||
<div id="content-wrap"> |
||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div> |
||||
<br> <br> |
||||
<div class="container"> |
||||
<div class="row justify-content-center"> |
||||
<div class="col-md-6"> |
||||
<h2 th:text="#{PDFToHTML.header}"></h2> |
||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/html}"> |
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> |
||||
<br> |
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToHTML.submit}"></button> |
||||
|
||||
</form> |
||||
<p class="mt-3" th:text="#{PDFToHTML.credit}"></p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div th:insert="~{fragments/footer.html :: footer}"></div> |
||||
</div> |
||||
</body> |
||||
</html> |
||||
<!DOCTYPE html> |
||||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> |
||||
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{PDFToHTML.title}, header=#{PDFToHTML.header})}"></th:block> |
||||
<body> |
||||
<th:block th:insert="~{fragments/common :: game}"></th:block> |
||||
<div id="page-container"> |
||||
<div id="content-wrap"> |
||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div> |
||||
<br> <br> |
||||
<div class="container"> |
||||
<div class="row justify-content-center"> |
||||
<div class="col-md-6"> |
||||
<h2 th:text="#{PDFToHTML.header}"></h2> |
||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/html}"> |
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> |
||||
<br> |
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToHTML.submit}"></button> |
||||
|
||||
</form> |
||||
<p class="mt-3" th:text="#{PDFToHTML.credit}"></p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div th:insert="~{fragments/footer.html :: footer}"></div> |
||||
</div> |
||||
</body> |
||||
</html> |
||||
|
@ -1,61 +1,61 @@ |
||||
<!DOCTYPE html> |
||||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> |
||||
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{pdfToImage.title}, header=#{pdfToImage.header})}"></th:block>
|
||||
|
||||
|
||||
<body> |
||||
<th:block th:insert="~{fragments/common :: game}"></th:block> |
||||
<div id="page-container"> |
||||
<div id="content-wrap"> |
||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div> |
||||
|
||||
<br> <br> |
||||
<div class="container"> |
||||
<div class="row justify-content-center"> |
||||
<div class="col-md-6"> |
||||
<h2 th:text="#{pdfToImage.header}"></h2> |
||||
<p th:text="#{processTimeWarning}"></p> |
||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/img}"> |
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> |
||||
<div class="mb-3"> |
||||
<label th:text="#{pdfToImage.selectText}"></label> |
||||
<select class="form-control" name="imageFormat"> |
||||
<option value="png">PNG</option> |
||||
<option value="jpg">JPG</option> |
||||
<option value="gif">GIF</option> |
||||
<option value="tiff">TIFF</option> |
||||
<option value="bmp">BMP</option> |
||||
</select> |
||||
</div> |
||||
<div class="mb-3"> |
||||
<label th:text="#{pdfToImage.singleOrMultiple}"></label> |
||||
<select class="form-control" name="singleOrMultiple"> |
||||
<option value="multiple" th:text="#{pdfToImage.multi}"></option> |
||||
<option value="single" th:text="#{pdfToImage.single}"></option> |
||||
</select> |
||||
</div> |
||||
<div class="mb-3"> |
||||
<label th:text="#{pdfToImage.colorType}"></label> |
||||
<select class="form-control" name="colorType"> |
||||
<option value="color" th:text="#{pdfToImage.color}"></option> |
||||
<option value="greyscale" th:text="#{pdfToImage.grey}"></option> |
||||
<option value="blackwhite" th:text="#{pdfToImage.blackwhite}"></option> |
||||
</select> |
||||
</div> |
||||
<div class="mb-3"> |
||||
<label for="dpi">DPI:</label> |
||||
<input type="number" name="dpi" class="form-control" id="dpi" min="1" step="1" value="300" required> |
||||
</div> |
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfToImage.submit}"></button> |
||||
</form> |
||||
|
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
</div> |
||||
<div th:insert="~{fragments/footer.html :: footer}"></div> |
||||
</div> |
||||
</body> |
||||
</html> |
||||
<!DOCTYPE html> |
||||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> |
||||
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{pdfToImage.title}, header=#{pdfToImage.header})}"></th:block> |
||||
|
||||
|
||||
<body> |
||||
<th:block th:insert="~{fragments/common :: game}"></th:block> |
||||
<div id="page-container"> |
||||
<div id="content-wrap"> |
||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div> |
||||
|
||||
<br> <br> |
||||
<div class="container"> |
||||
<div class="row justify-content-center"> |
||||
<div class="col-md-6"> |
||||
<h2 th:text="#{pdfToImage.header}"></h2> |
||||
<p th:text="#{processTimeWarning}"></p> |
||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/img}"> |
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> |
||||
<div class="mb-3"> |
||||
<label th:text="#{pdfToImage.selectText}"></label> |
||||
<select class="form-control" name="imageFormat"> |
||||
<option value="png">PNG</option> |
||||
<option value="jpg">JPG</option> |
||||
<option value="gif">GIF</option> |
||||
<option value="tiff">TIFF</option> |
||||
<option value="bmp">BMP</option> |
||||
</select> |
||||
</div> |
||||
<div class="mb-3"> |
||||
<label th:text="#{pdfToImage.singleOrMultiple}"></label> |
||||
<select class="form-control" name="singleOrMultiple"> |
||||
<option value="multiple" th:text="#{pdfToImage.multi}"></option> |
||||
<option value="single" th:text="#{pdfToImage.single}"></option> |
||||
</select> |
||||
</div> |
||||
<div class="mb-3"> |
||||
<label th:text="#{pdfToImage.colorType}"></label> |
||||
<select class="form-control" name="colorType"> |
||||
<option value="color" th:text="#{pdfToImage.color}"></option> |
||||
<option value="greyscale" th:text="#{pdfToImage.grey}"></option> |
||||
<option value="blackwhite" th:text="#{pdfToImage.blackwhite}"></option> |
||||
</select> |
||||
</div> |
||||
<div class="mb-3"> |
||||
<label for="dpi">DPI:</label> |
||||
<input type="number" name="dpi" class="form-control" id="dpi" min="1" step="1" value="300" required> |
||||
</div> |
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfToImage.submit}"></button> |
||||
</form> |
||||
|
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
</div> |
||||
<div th:insert="~{fragments/footer.html :: footer}"></div> |
||||
</div> |
||||
</body> |
||||
</html> |
||||
|
@ -1,35 +1,35 @@ |
||||
<!DOCTYPE html> |
||||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> |
||||
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{PDFToText.title}, header=#{PDFToText.header})}"></th:block>
|
||||
<body> |
||||
<th:block th:insert="~{fragments/common :: game}"></th:block> |
||||
<div id="page-container"> |
||||
<div id="content-wrap"> |
||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div> |
||||
<br> <br> |
||||
<div class="container"> |
||||
<div class="row justify-content-center"> |
||||
<div class="col-md-6"> |
||||
<h2 th:text="#{PDFToText.header}"></h2> |
||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/text}"> |
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> |
||||
|
||||
<div class="mb-3"> |
||||
<label th:text="#{PDFToText.selectText.1}"></label> |
||||
<select class="form-control" name="outputFormat"> |
||||
<option value="rtf">RTF</option> |
||||
<option value="txt">TXT</option> |
||||
</select> |
||||
</div> |
||||
<br> |
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToText.submit}"></button> |
||||
|
||||
</form> |
||||
<p class="mt-3" th:text="#{PDFToText.credit}"></p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div th:insert="~{fragments/footer.html :: footer}"></div> |
||||
<!DOCTYPE html> |
||||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> |
||||
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{PDFToText.title}, header=#{PDFToText.header})}"></th:block> |
||||
<body> |
||||
<th:block th:insert="~{fragments/common :: game}"></th:block> |
||||
<div id="page-container"> |
||||
<div id="content-wrap"> |
||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div> |
||||
<br> <br> |
||||
<div class="container"> |
||||
<div class="row justify-content-center"> |
||||
<div class="col-md-6"> |
||||
<h2 th:text="#{PDFToText.header}"></h2> |
||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/text}"> |
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> |
||||
|
||||
<div class="mb-3"> |
||||
<label th:text="#{PDFToText.selectText.1}"></label> |
||||
<select class="form-control" name="outputFormat"> |
||||
<option value="rtf">RTF</option> |
||||
<option value="txt">TXT</option> |
||||
</select> |
||||
</div> |
||||
<br> |
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToText.submit}"></button> |
||||
|
||||
</form> |
||||
<p class="mt-3" th:text="#{PDFToText.credit}"></p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div th:insert="~{fragments/footer.html :: footer}"></div> |
||||
</div> |
@ -1,29 +1,29 @@ |
||||
<!DOCTYPE html> |
||||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> |
||||
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{URLToPDF.title}, header=#{URLToPDF.header})}"></th:block>
|
||||
<body> |
||||
<th:block th:insert="~{fragments/common :: game}"></th:block> |
||||
<div id="page-container"> |
||||
<div id="content-wrap"> |
||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div> |
||||
<br> <br> |
||||
<div class="container"> |
||||
<div class="row justify-content-center"> |
||||
<div class="col-md-6"> |
||||
<h2 th:text="#{URLToPDF.header}"></h2> |
||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/url/pdf}"> |
||||
<input type="text" class="form-control" id="urlInput" name="urlInput"> |
||||
<br> |
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{URLToPDF.submit}"></button> |
||||
|
||||
</form> |
||||
<p class="mt-3" th:text="#{URLToPDF.credit}"></p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div th:insert="~{fragments/footer.html :: footer}"></div> |
||||
</div> |
||||
</body> |
||||
</html> |
||||
<!DOCTYPE html> |
||||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> |
||||
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{URLToPDF.title}, header=#{URLToPDF.header})}"></th:block> |
||||
<body> |
||||
<th:block th:insert="~{fragments/common :: game}"></th:block> |
||||
<div id="page-container"> |
||||
<div id="content-wrap"> |
||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div> |
||||
<br> <br> |
||||
<div class="container"> |
||||
<div class="row justify-content-center"> |
||||
<div class="col-md-6"> |
||||
<h2 th:text="#{URLToPDF.header}"></h2> |
||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/url/pdf}"> |
||||
<input type="text" class="form-control" id="urlInput" name="urlInput"> |
||||
<br> |
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{URLToPDF.submit}"></button> |
||||
|
||||
</form> |
||||
<p class="mt-3" th:text="#{URLToPDF.credit}"></p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div th:insert="~{fragments/footer.html :: footer}"></div> |
||||
</div> |
||||
</body> |
||||
</html> |
||||
|