Compare commits
11 Commits
v0.34.0
...
bug/rememb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2062c19ab | ||
|
|
6760fddd6f | ||
|
|
20a75d577d | ||
|
|
559581c59d | ||
|
|
e7356a1d38 | ||
|
|
1405e4f5ee | ||
|
|
322e7dee0d | ||
|
|
918e977c6a | ||
|
|
a31633e5b8 | ||
|
|
ed551cec91 | ||
|
|
3f14e77725 |
117
.github/scripts/check_language_properties.py
vendored
117
.github/scripts/check_language_properties.py
vendored
@@ -9,9 +9,8 @@ The script also provides functionality to update the translation files to match
|
|||||||
adjusting the format.
|
adjusting the format.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
python check_language_properties.py --reference-file <path_to_reference_file> --branch <branch_name> [--actor <actor_name>] [--files <list_of_changed_files>]
|
python script_name.py --reference-file <path_to_reference_file> --branch <branch_name> [--files <list_of_changed_files>]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
@@ -19,10 +18,6 @@ import argparse
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
# Maximum size for properties files (e.g., 200 KB)
|
|
||||||
MAX_FILE_SIZE = 200 * 1024
|
|
||||||
|
|
||||||
|
|
||||||
def parse_properties_file(file_path):
|
def parse_properties_file(file_path):
|
||||||
"""Parses a .properties file and returns a list of objects (including comments, empty lines, and line numbers)."""
|
"""Parses a .properties file and returns a list of objects (including comments, empty lines, and line numbers)."""
|
||||||
properties_list = []
|
properties_list = []
|
||||||
@@ -100,7 +95,7 @@ def write_json_file(file_path, updated_properties):
|
|||||||
def update_missing_keys(reference_file, file_list, branch=""):
|
def update_missing_keys(reference_file, file_list, branch=""):
|
||||||
reference_properties = parse_properties_file(reference_file)
|
reference_properties = parse_properties_file(reference_file)
|
||||||
for file_path in file_list:
|
for file_path in file_list:
|
||||||
basename_current_file = os.path.basename(os.path.join(branch, file_path))
|
basename_current_file = os.path.basename(branch + file_path)
|
||||||
if (
|
if (
|
||||||
basename_current_file == os.path.basename(reference_file)
|
basename_current_file == os.path.basename(reference_file)
|
||||||
or not file_path.endswith(".properties")
|
or not file_path.endswith(".properties")
|
||||||
@@ -108,7 +103,7 @@ def update_missing_keys(reference_file, file_list, branch=""):
|
|||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
current_properties = parse_properties_file(os.path.join(branch, file_path))
|
current_properties = parse_properties_file(branch + file_path)
|
||||||
updated_properties = []
|
updated_properties = []
|
||||||
for ref_entry in reference_properties:
|
for ref_entry in reference_properties:
|
||||||
ref_entry_copy = copy.deepcopy(ref_entry)
|
ref_entry_copy = copy.deepcopy(ref_entry)
|
||||||
@@ -119,79 +114,60 @@ def update_missing_keys(reference_file, file_list, branch=""):
|
|||||||
if ref_entry_copy["key"] == current_entry["key"]:
|
if ref_entry_copy["key"] == current_entry["key"]:
|
||||||
ref_entry_copy["value"] = current_entry["value"]
|
ref_entry_copy["value"] = current_entry["value"]
|
||||||
updated_properties.append(ref_entry_copy)
|
updated_properties.append(ref_entry_copy)
|
||||||
write_json_file(os.path.join(branch, file_path), updated_properties)
|
write_json_file(branch + file_path, updated_properties)
|
||||||
|
|
||||||
|
|
||||||
def check_for_missing_keys(reference_file, file_list, branch):
|
def check_for_missing_keys(reference_file, file_list, branch):
|
||||||
update_missing_keys(reference_file, file_list, branch)
|
update_missing_keys(reference_file, file_list, branch + "/")
|
||||||
|
|
||||||
|
|
||||||
def read_properties(file_path):
|
def read_properties(file_path):
|
||||||
if os.path.isfile(file_path) and os.path.exists(file_path):
|
with open(file_path, "r", encoding="utf-8") as file:
|
||||||
with open(file_path, "r", encoding="utf-8") as file:
|
return file.read().splitlines()
|
||||||
return file.read().splitlines()
|
|
||||||
return [""]
|
|
||||||
|
|
||||||
|
|
||||||
def check_for_differences(reference_file, file_list, branch, actor):
|
def check_for_differences(reference_file, file_list, branch):
|
||||||
reference_branch = reference_file.split("/")[0]
|
reference_branch = reference_file.split("/")[0]
|
||||||
basename_reference_file = os.path.basename(reference_file)
|
basename_reference_file = os.path.basename(reference_file)
|
||||||
|
|
||||||
report = []
|
report = []
|
||||||
report.append(f"#### 🔄 Reference Branch: `{reference_branch}`")
|
report.append(
|
||||||
|
f"### 📋 Checking with the file `{basename_reference_file}` from the `{reference_branch}` - Checking the `{branch}`"
|
||||||
|
)
|
||||||
reference_lines = read_properties(reference_file)
|
reference_lines = read_properties(reference_file)
|
||||||
has_differences = False
|
has_differences = False
|
||||||
|
|
||||||
only_reference_file = True
|
only_reference_file = True
|
||||||
|
|
||||||
file_arr = file_list
|
for file_path in file_list:
|
||||||
|
basename_current_file = os.path.basename(branch + "/" + file_path)
|
||||||
if len(file_list) == 1:
|
|
||||||
file_arr = file_list[0].split()
|
|
||||||
base_dir = os.path.abspath(os.path.join(os.getcwd(), "src", "main", "resources"))
|
|
||||||
|
|
||||||
for file_path in file_arr:
|
|
||||||
absolute_path = os.path.abspath(file_path)
|
|
||||||
# Verify that file is within the expected directory
|
|
||||||
if not absolute_path.startswith(base_dir):
|
|
||||||
raise ValueError(f"Unsafe file found: {file_path}")
|
|
||||||
# Verify file size before processing
|
|
||||||
if os.path.getsize(os.path.join(branch, file_path)) > MAX_FILE_SIZE:
|
|
||||||
raise ValueError(
|
|
||||||
f"The file {file_path} is too large and could pose a security risk."
|
|
||||||
)
|
|
||||||
|
|
||||||
basename_current_file = os.path.basename(os.path.join(branch, file_path))
|
|
||||||
if (
|
if (
|
||||||
basename_current_file == basename_reference_file
|
basename_current_file == basename_reference_file
|
||||||
or not file_path.startswith(
|
|
||||||
os.path.join("src", "main", "resources", "messages_")
|
|
||||||
)
|
|
||||||
or not file_path.endswith(".properties")
|
or not file_path.endswith(".properties")
|
||||||
or not basename_current_file.startswith("messages_")
|
or not basename_current_file.startswith("messages_")
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
only_reference_file = False
|
only_reference_file = False
|
||||||
report.append(f"#### 📃 **File Check:** `{basename_current_file}`")
|
report.append(f"#### 🗂️ **Checking File:** `{basename_current_file}`...")
|
||||||
current_lines = read_properties(os.path.join(branch, file_path))
|
current_lines = read_properties(branch + "/" + file_path)
|
||||||
reference_line_count = len(reference_lines)
|
reference_line_count = len(reference_lines)
|
||||||
current_line_count = len(current_lines)
|
current_line_count = len(current_lines)
|
||||||
|
|
||||||
if reference_line_count != current_line_count:
|
if reference_line_count != current_line_count:
|
||||||
report.append("")
|
report.append("")
|
||||||
report.append("1. **Test Status:** ❌ **_Failed_**")
|
report.append("- **Test 1 Status:** ❌ Failed")
|
||||||
report.append(" - **Issue:**")
|
|
||||||
has_differences = True
|
has_differences = True
|
||||||
if reference_line_count > current_line_count:
|
if reference_line_count > current_line_count:
|
||||||
report.append(
|
report.append(
|
||||||
f" - **_Mismatched line count_**: {reference_line_count} (reference) vs {current_line_count} (current). Comments, empty lines, or translation strings are missing."
|
f" - **Issue:** Missing lines! Comments, empty lines, or translation strings are missing. Details: {reference_line_count} (reference) vs {current_line_count} (current)."
|
||||||
)
|
)
|
||||||
elif reference_line_count < current_line_count:
|
elif reference_line_count < current_line_count:
|
||||||
report.append(
|
report.append(
|
||||||
f" - **_Too many lines_**: {reference_line_count} (reference) vs {current_line_count} (current). Please verify if there is an additional line that needs to be removed."
|
f" - **Issue:** Too many lines! Check your translation files! Details: {reference_line_count} (reference) vs {current_line_count} (current)."
|
||||||
)
|
)
|
||||||
|
# update_missing_keys(reference_file, [file_path], branch + "/")
|
||||||
else:
|
else:
|
||||||
report.append("1. **Test Status:** ✅ **_Passed_**")
|
report.append("- **Test 1 Status:** ✅ Passed")
|
||||||
|
|
||||||
# Check for missing or extra keys
|
# Check for missing or extra keys
|
||||||
current_keys = []
|
current_keys = []
|
||||||
@@ -216,42 +192,32 @@ def check_for_differences(reference_file, file_list, branch, actor):
|
|||||||
has_differences = True
|
has_differences = True
|
||||||
missing_keys_str = "`, `".join(missing_keys_list)
|
missing_keys_str = "`, `".join(missing_keys_list)
|
||||||
extra_keys_str = "`, `".join(extra_keys_list)
|
extra_keys_str = "`, `".join(extra_keys_list)
|
||||||
report.append("2. **Test Status:** ❌ **_Failed_**")
|
report.append("- **Test 2 Status:** ❌ Failed")
|
||||||
report.append(" - **Issue:**")
|
|
||||||
if missing_keys_list:
|
if missing_keys_list:
|
||||||
spaces_keys_list = []
|
|
||||||
for key in missing_keys_list:
|
|
||||||
if " " in key:
|
|
||||||
spaces_keys_list.append(key)
|
|
||||||
if spaces_keys_list:
|
|
||||||
spaces_keys_str = "`, `".join(spaces_keys_list)
|
|
||||||
report.append(
|
|
||||||
f" - **_Keys containing unnecessary spaces_**: `{spaces_keys_str}`!"
|
|
||||||
)
|
|
||||||
report.append(
|
report.append(
|
||||||
f" - **_Extra keys in `{basename_current_file}`_**: `{missing_keys_str}` that are not present in **_`{basename_reference_file}`_**."
|
f" - **Issue:** There are keys in ***{basename_current_file}*** `{missing_keys_str}` that are not present in ***{basename_reference_file}***!"
|
||||||
)
|
)
|
||||||
if extra_keys_list:
|
if extra_keys_list:
|
||||||
report.append(
|
report.append(
|
||||||
f" - **_Missing keys in `{basename_reference_file}`_**: `{extra_keys_str}` that are not present in **_`{basename_current_file}`_**."
|
f" - **Issue:** There are keys in ***{basename_reference_file}*** `{extra_keys_str}` that are not present in ***{basename_current_file}***!"
|
||||||
)
|
)
|
||||||
|
# update_missing_keys(reference_file, [file_path], branch + "/")
|
||||||
else:
|
else:
|
||||||
report.append("2. **Test Status:** ✅ **_Passed_**")
|
report.append("- **Test 2 Status:** ✅ Passed")
|
||||||
|
# if has_differences:
|
||||||
|
# report.append("")
|
||||||
|
# report.append(f"#### 🚧 ***{basename_current_file}*** will be corrected...")
|
||||||
report.append("")
|
report.append("")
|
||||||
report.append("---")
|
report.append("---")
|
||||||
report.append("")
|
report.append("")
|
||||||
|
# update_file_list = glob.glob(branch + "/src/**/messages_*.properties", recursive=True)
|
||||||
|
# update_missing_keys(reference_file, update_file_list)
|
||||||
|
# report.append("---")
|
||||||
|
# report.append("")
|
||||||
if has_differences:
|
if has_differences:
|
||||||
report.append("## ❌ Overall Check Status: **_Failed_**")
|
report.append("## ❌ Overall Check Status: **_Failed_**")
|
||||||
report.append("")
|
|
||||||
report.append(
|
|
||||||
f"@{actor} please check your translation if it conforms to the standard. Follow the format of [messages_en_GB.properties](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/messages_en_GB.properties)"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
report.append("## ✅ Overall Check Status: **_Success_**")
|
report.append("## ✅ Overall Check Status: **_Success_**")
|
||||||
report.append("")
|
|
||||||
report.append(
|
|
||||||
f"Thanks @{actor} for your help in keeping the translations up to date."
|
|
||||||
)
|
|
||||||
|
|
||||||
if not only_reference_file:
|
if not only_reference_file:
|
||||||
print("\n".join(report))
|
print("\n".join(report))
|
||||||
@@ -259,11 +225,6 @@ def check_for_differences(reference_file, file_list, branch, actor):
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description="Find missing keys")
|
parser = argparse.ArgumentParser(description="Find missing keys")
|
||||||
parser.add_argument(
|
|
||||||
"--actor",
|
|
||||||
required=False,
|
|
||||||
help="Actor from PR.",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--reference-file",
|
"--reference-file",
|
||||||
required=True,
|
required=True,
|
||||||
@@ -283,21 +244,11 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Sanitize --actor input to avoid injection attacks
|
|
||||||
if args.actor:
|
|
||||||
args.actor = re.sub(r"[^a-zA-Z0-9_\\-]", "", args.actor)
|
|
||||||
|
|
||||||
# Sanitize --branch input to avoid injection attacks
|
|
||||||
if args.branch:
|
|
||||||
args.branch = re.sub(r"[^a-zA-Z0-9\\-]", "", args.branch)
|
|
||||||
|
|
||||||
file_list = args.files
|
file_list = args.files
|
||||||
if file_list is None:
|
if file_list is None:
|
||||||
file_list = glob.glob(
|
file_list = glob.glob(
|
||||||
os.path.join(
|
os.getcwd() + "/src/**/messages_*.properties", recursive=True
|
||||||
os.getcwd(), "src", "main", "resources", "messages_*.properties"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
update_missing_keys(args.reference_file, file_list)
|
update_missing_keys(args.reference_file, file_list)
|
||||||
else:
|
else:
|
||||||
check_for_differences(args.reference_file, file_list, args.branch, args.actor)
|
check_for_differences(args.reference_file, file_list, args.branch)
|
||||||
|
|||||||
179
.github/workflows/PR-Demo-Comment.yml
vendored
179
.github/workflows/PR-Demo-Comment.yml
vendored
@@ -1,179 +0,0 @@
|
|||||||
name: PR Deployment via Comment
|
|
||||||
|
|
||||||
on:
|
|
||||||
issue_comment:
|
|
||||||
types: [created]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check-comment:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: |
|
|
||||||
github.event.issue.pull_request &&
|
|
||||||
(
|
|
||||||
contains(github.event.comment.body, 'prdeploy') ||
|
|
||||||
contains(github.event.comment.body, 'deploypr')
|
|
||||||
)
|
|
||||||
&&
|
|
||||||
(
|
|
||||||
github.event.comment.user.login == 'frooodle' ||
|
|
||||||
github.event.comment.user.login == 'sf298' ||
|
|
||||||
github.event.comment.user.login == 'Ludy87' ||
|
|
||||||
github.event.comment.user.login == 'LaserKaspar' ||
|
|
||||||
github.event.comment.user.login == 'sbplat' ||
|
|
||||||
github.event.comment.user.login == 'reecebrowne'
|
|
||||||
)
|
|
||||||
outputs:
|
|
||||||
pr_number: ${{ steps.get-pr.outputs.pr_number }}
|
|
||||||
pr_repository: ${{ steps.get-pr-info.outputs.repository }}
|
|
||||||
pr_ref: ${{ steps.get-pr-info.outputs.ref }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Get PR data
|
|
||||||
id: get-pr
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const prNumber = context.payload.issue.number;
|
|
||||||
console.log(`PR Number: ${prNumber}`);
|
|
||||||
core.setOutput('pr_number', prNumber);
|
|
||||||
|
|
||||||
- name: Get PR repository and ref
|
|
||||||
id: get-pr-info
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const { owner, repo } = context.repo;
|
|
||||||
const prNumber = context.payload.issue.number;
|
|
||||||
|
|
||||||
const { data: pr } = await github.rest.pulls.get({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
pull_number: prNumber,
|
|
||||||
});
|
|
||||||
|
|
||||||
// For forks, use the full repository name, for internal PRs use the current repo
|
|
||||||
const repository = pr.head.repo.fork ? pr.head.repo.full_name : `${owner}/${repo}`;
|
|
||||||
|
|
||||||
console.log(`PR Repository: ${repository}`);
|
|
||||||
console.log(`PR Branch: ${pr.head.ref}`);
|
|
||||||
|
|
||||||
core.setOutput('repository', repository);
|
|
||||||
core.setOutput('ref', pr.head.ref);
|
|
||||||
|
|
||||||
deploy-pr:
|
|
||||||
needs: check-comment
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout PR
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: ${{ needs.check-comment.outputs.pr_repository }}
|
|
||||||
ref: ${{ needs.check-comment.outputs.pr_ref }}
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Set up JDK
|
|
||||||
uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
java-version: '17'
|
|
||||||
distribution: 'temurin'
|
|
||||||
|
|
||||||
- name: Run Gradle Command
|
|
||||||
run: ./gradlew clean build
|
|
||||||
env:
|
|
||||||
DOCKER_ENABLE_SECURITY: false
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Get version number
|
|
||||||
id: versionNumber
|
|
||||||
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_HUB_API }}
|
|
||||||
|
|
||||||
- name: Build and push PR-specific image
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile
|
|
||||||
push: true
|
|
||||||
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:pr-${{ needs.check-comment.outputs.pr_number }}
|
|
||||||
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
|
||||||
platforms: linux/amd64
|
|
||||||
|
|
||||||
- name: Set up SSH
|
|
||||||
run: |
|
|
||||||
mkdir -p ~/.ssh/
|
|
||||||
echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key
|
|
||||||
sudo chmod 600 ../private.key
|
|
||||||
|
|
||||||
- name: Deploy to VPS
|
|
||||||
run: |
|
|
||||||
# First create the docker-compose content locally
|
|
||||||
cat > docker-compose.yml << 'EOF'
|
|
||||||
version: '3.3'
|
|
||||||
services:
|
|
||||||
stirling-pdf:
|
|
||||||
container_name: stirling-pdf-pr-${{ needs.check-comment.outputs.pr_number }}
|
|
||||||
image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:pr-${{ needs.check-comment.outputs.pr_number }}
|
|
||||||
ports:
|
|
||||||
- "${{ needs.check-comment.outputs.pr_number }}:8080"
|
|
||||||
volumes:
|
|
||||||
- /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/data:/usr/share/tessdata:rw
|
|
||||||
- /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/config:/configs:rw
|
|
||||||
- /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/logs:/logs:rw
|
|
||||||
environment:
|
|
||||||
DOCKER_ENABLE_SECURITY: "false"
|
|
||||||
SECURITY_ENABLELOGIN: "false"
|
|
||||||
SYSTEM_DEFAULTLOCALE: en-GB
|
|
||||||
UI_APPNAME: "Stirling-PDF PR#${{ needs.check-comment.outputs.pr_number }}"
|
|
||||||
UI_HOMEDESCRIPTION: "PR#${{ needs.check-comment.outputs.pr_number }} for Stirling-PDF Latest"
|
|
||||||
UI_APPNAMENAVBAR: "PR#${{ needs.check-comment.outputs.pr_number }}"
|
|
||||||
SYSTEM_MAXFILESIZE: "100"
|
|
||||||
METRICS_ENABLED: "true"
|
|
||||||
SYSTEM_GOOGLEVISIBILITY: "false"
|
|
||||||
restart: on-failure:5
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Then copy the file and execute commands
|
|
||||||
scp -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null docker-compose.yml ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }}:/tmp/docker-compose.yml
|
|
||||||
|
|
||||||
ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH'
|
|
||||||
# Create PR-specific directories
|
|
||||||
mkdir -p /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/{data,config,logs}
|
|
||||||
|
|
||||||
# Move docker-compose file to correct location
|
|
||||||
mv /tmp/docker-compose.yml /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/docker-compose.yml
|
|
||||||
|
|
||||||
# Start or restart the container
|
|
||||||
cd /stirling/PR-${{ needs.check-comment.outputs.pr_number }}
|
|
||||||
docker-compose pull
|
|
||||||
docker-compose up -d
|
|
||||||
ENDSSH
|
|
||||||
|
|
||||||
- name: Post deployment URL to PR
|
|
||||||
if: success()
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const { GITHUB_REPOSITORY } = process.env;
|
|
||||||
const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/');
|
|
||||||
const prNumber = ${{ needs.check-comment.outputs.pr_number }};
|
|
||||||
|
|
||||||
const deploymentUrl = `http://${{ secrets.VPS_HOST }}:${prNumber}`;
|
|
||||||
const commentBody = `## 🚀 PR Test Deployment\n\n` +
|
|
||||||
`Your PR has been deployed for testing!\n\n` +
|
|
||||||
`🔗 **Test URL:** [${deploymentUrl}](${deploymentUrl})\n\n` +
|
|
||||||
`This deployment will be automatically cleaned up when the PR is closed.\n\n`;
|
|
||||||
|
|
||||||
await github.rest.issues.createComment({
|
|
||||||
owner: repoOwner,
|
|
||||||
repo: repoName,
|
|
||||||
issue_number: prNumber,
|
|
||||||
body: commentBody
|
|
||||||
});
|
|
||||||
78
.github/workflows/PR-Demo-cleanup.yml
vendored
78
.github/workflows/PR-Demo-cleanup.yml
vendored
@@ -1,78 +0,0 @@
|
|||||||
name: PR Deployment cleanup
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, synchronize, reopened, closed]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
env:
|
|
||||||
SERVER_IP: ${{ secrets.VPS_IP }} # Add this to your GitHub secrets
|
|
||||||
CLEANUP_PERFORMED: 'false' # Add flag to track if cleanup occurred
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
cleanup:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.event.action == 'closed'
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Set up SSH
|
|
||||||
run: |
|
|
||||||
mkdir -p ~/.ssh/
|
|
||||||
echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key
|
|
||||||
sudo chmod 600 ../private.key
|
|
||||||
|
|
||||||
- name: Cleanup PR deployment
|
|
||||||
id: cleanup
|
|
||||||
run: |
|
|
||||||
CLEANUP_STATUS=$(ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH'
|
|
||||||
if [ -d "/stirling/PR-${{ github.event.pull_request.number }}" ]; then
|
|
||||||
echo "Found PR directory, proceeding with cleanup..."
|
|
||||||
|
|
||||||
# Stop and remove containers
|
|
||||||
cd /stirling/PR-${{ github.event.pull_request.number }}
|
|
||||||
docker-compose down || true
|
|
||||||
|
|
||||||
# Go back to root before removal
|
|
||||||
cd /
|
|
||||||
|
|
||||||
# Remove PR-specific directories
|
|
||||||
rm -rf /stirling/PR-${{ github.event.pull_request.number }}
|
|
||||||
|
|
||||||
# Remove the Docker image
|
|
||||||
docker rmi --no-prune ${{ secrets.DOCKER_HUB_USERNAME }}/test:pr-${{ github.event.pull_request.number }} || true
|
|
||||||
|
|
||||||
echo "PERFORMED_CLEANUP"
|
|
||||||
else
|
|
||||||
echo "PR directory not found, nothing to clean up"
|
|
||||||
echo "NO_CLEANUP_NEEDED"
|
|
||||||
fi
|
|
||||||
ENDSSH
|
|
||||||
)
|
|
||||||
|
|
||||||
if [[ $CLEANUP_STATUS == *"PERFORMED_CLEANUP"* ]]; then
|
|
||||||
echo "cleanup_performed=true" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "cleanup_performed=false" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Post cleanup notice to PR
|
|
||||||
if: steps.cleanup.outputs.cleanup_performed == 'true'
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const { GITHUB_REPOSITORY } = process.env;
|
|
||||||
const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/');
|
|
||||||
const prNumber = context.issue.number;
|
|
||||||
|
|
||||||
const commentBody = `## 🧹 Deployment Cleanup\n\n` +
|
|
||||||
`The test deployment for this PR has been cleaned up.`;
|
|
||||||
|
|
||||||
await github.rest.issues.createComment({
|
|
||||||
owner: repoOwner,
|
|
||||||
repo: repoName,
|
|
||||||
issue_number: prNumber,
|
|
||||||
body: commentBody
|
|
||||||
});
|
|
||||||
119
.github/workflows/check_properties.yml
vendored
119
.github/workflows/check_properties.yml
vendored
@@ -6,22 +6,18 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- "src/main/resources/messages_*.properties"
|
- "src/main/resources/messages_*.properties"
|
||||||
push:
|
push:
|
||||||
branches: ["main"]
|
|
||||||
paths:
|
paths:
|
||||||
- "src/main/resources/messages_en_GB.properties"
|
- "src/main/resources/messages_en_GB.properties"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-files:
|
check-files:
|
||||||
if: github.event_name == 'pull_request_target'
|
if: github.event_name == 'pull_request_target'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout main branch first
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: main
|
|
||||||
path: main-branch
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Checkout PR branch
|
- name: Checkout PR branch
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -30,6 +26,13 @@ jobs:
|
|||||||
path: pr-branch
|
path: pr-branch
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Checkout main branch
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: main
|
||||||
|
path: main-branch
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
@@ -46,73 +49,56 @@ jobs:
|
|||||||
echo "Fetching PR changed files..."
|
echo "Fetching PR changed files..."
|
||||||
cd pr-branch
|
cd pr-branch
|
||||||
gh repo set-default ${{ github.repository }}
|
gh repo set-default ${{ github.repository }}
|
||||||
# Store files in a safe way, only allowing valid properties files
|
gh pr view ${{ github.event.pull_request.number }} --json files -q ".files[].path" > ../changed_files.txt
|
||||||
echo "Getting list of changed files from PR..."
|
|
||||||
gh pr view ${{ github.event.pull_request.number }} --json files -q ".files[].path" | grep -E '^src/main/resources/messages_[a-zA-Z_]+\.properties$' > ../changed_files.txt
|
|
||||||
cd ..
|
cd ..
|
||||||
|
echo $(cat changed_files.txt)
|
||||||
echo "Processing changed files..."
|
BRANCH_PATH="pr-branch"
|
||||||
mapfile -t CHANGED_FILES < changed_files.txt
|
echo "BRANCH_PATH=${BRANCH_PATH}" >> $GITHUB_ENV
|
||||||
|
CHANGED_FILES=$(cat changed_files.txt | tr '\n' ' ')
|
||||||
CHANGED_FILES_STR="${CHANGED_FILES[*]}"
|
echo "CHANGED_FILES=${CHANGED_FILES}" >> $GITHUB_ENV
|
||||||
echo "CHANGED_FILES=${CHANGED_FILES_STR}" >> $GITHUB_ENV
|
echo "Changed files: ${CHANGED_FILES}"
|
||||||
|
echo "Branch: ${BRANCH_PATH}"
|
||||||
echo "Changed files: ${CHANGED_FILES_STR}"
|
|
||||||
|
|
||||||
- name: Determine reference file
|
- name: Determine reference file
|
||||||
id: determine-file
|
id: determine-file
|
||||||
run: |
|
run: |
|
||||||
echo "Determining reference file..."
|
echo "Determining reference file..."
|
||||||
if grep -Fxq "src/main/resources/messages_en_GB.properties" changed_files.txt; then
|
if echo "${{ env.CHANGED_FILES }}" | grep -q 'src/main/resources/messages_en_GB.properties'; then
|
||||||
echo "Using PR branch reference file"
|
|
||||||
echo "REFERENCE_FILE=pr-branch/src/main/resources/messages_en_GB.properties" >> $GITHUB_ENV
|
echo "REFERENCE_FILE=pr-branch/src/main/resources/messages_en_GB.properties" >> $GITHUB_ENV
|
||||||
else
|
else
|
||||||
echo "Using main branch reference file"
|
|
||||||
echo "REFERENCE_FILE=main-branch/src/main/resources/messages_en_GB.properties" >> $GITHUB_ENV
|
echo "REFERENCE_FILE=main-branch/src/main/resources/messages_en_GB.properties" >> $GITHUB_ENV
|
||||||
fi
|
fi
|
||||||
|
echo "REFERENCE_FILE=${{ env.REFERENCE_FILE }}"
|
||||||
|
|
||||||
- name: Show REFERENCE_FILE
|
- name: Show REFERENCE_FILE
|
||||||
run: echo "Reference file is set to ${REFERENCE_FILE}"
|
run: echo "Reference file is set to ${{ env.REFERENCE_FILE }}"
|
||||||
|
|
||||||
- name: Run Python script to check files
|
- name: Run Python script to check files
|
||||||
id: run-check
|
id: run-check
|
||||||
run: |
|
run: |
|
||||||
echo "Running Python script to check files..."
|
python main-branch/.github/scripts/check_language_properties.py --reference-file ${{ env.REFERENCE_FILE }} --branch ${{ env.BRANCH_PATH }} --files ${{ env.CHANGED_FILES }} > failure.txt || true
|
||||||
python main-branch/.github/scripts/check_language_properties.py \
|
|
||||||
--actor ${{ github.event.pull_request.user.login }} \
|
|
||||||
--reference-file "${REFERENCE_FILE}" \
|
|
||||||
--branch pr-branch \
|
|
||||||
--files "${CHANGED_FILES[@]}" > result.txt || true
|
|
||||||
|
|
||||||
- name: Capture output
|
- name: Capture output
|
||||||
id: capture-output
|
id: capture-output
|
||||||
run: |
|
run: |
|
||||||
if [ -f result.txt ] && [ -s result.txt ]; then
|
if [ -f failure.txt ] && [ -s failure.txt ]; then
|
||||||
echo "Test, capturing output..."
|
echo "Test failed, capturing output..."
|
||||||
SCRIPT_OUTPUT=$(cat result.txt)
|
ERROR_OUTPUT=$(cat failure.txt)
|
||||||
echo "SCRIPT_OUTPUT<<EOF" >> $GITHUB_ENV
|
echo "ERROR_OUTPUT<<EOF" >> $GITHUB_ENV
|
||||||
echo "$SCRIPT_OUTPUT" >> $GITHUB_ENV
|
echo "$ERROR_OUTPUT" >> $GITHUB_ENV
|
||||||
echo "EOF" >> $GITHUB_ENV
|
echo "EOF" >> $GITHUB_ENV
|
||||||
echo "${SCRIPT_OUTPUT}"
|
echo $ERROR_OUTPUT
|
||||||
|
|
||||||
# Set FAIL_JOB to true if SCRIPT_OUTPUT contains ❌
|
|
||||||
if [[ "$SCRIPT_OUTPUT" == *"❌"* ]]; then
|
|
||||||
echo "FAIL_JOB=true" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "FAIL_JOB=false" >> $GITHUB_ENV
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
echo "No update found."
|
echo "No errors found."
|
||||||
echo "SCRIPT_OUTPUT=" >> $GITHUB_ENV
|
echo "ERROR_OUTPUT=" >> $GITHUB_ENV
|
||||||
echo "FAIL_JOB=false" >> $GITHUB_ENV
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Post comment on PR
|
- name: Post comment on PR
|
||||||
if: env.SCRIPT_OUTPUT != ''
|
if: env.ERROR_OUTPUT != ''
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const { GITHUB_REPOSITORY, SCRIPT_OUTPUT } = process.env;
|
const { GITHUB_REPOSITORY, ERROR_OUTPUT } = process.env;
|
||||||
const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/');
|
const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/');
|
||||||
const prNumber = context.issue.number;
|
const prNumber = context.issue.number;
|
||||||
|
|
||||||
@@ -134,7 +120,7 @@ jobs:
|
|||||||
owner: repoOwner,
|
owner: repoOwner,
|
||||||
repo: repoName,
|
repo: repoName,
|
||||||
comment_id: comment.id,
|
comment_id: comment.id,
|
||||||
body: `## 🚀 Translation Verification Summary\n\n\n${SCRIPT_OUTPUT}\n`
|
body: `## 🚀 Translation Verification Summary\n\n\n${ERROR_OUTPUT}\n`
|
||||||
});
|
});
|
||||||
console.log("Updated existing comment.");
|
console.log("Updated existing comment.");
|
||||||
} else if (!comment) {
|
} else if (!comment) {
|
||||||
@@ -143,24 +129,33 @@ jobs:
|
|||||||
owner: repoOwner,
|
owner: repoOwner,
|
||||||
repo: repoName,
|
repo: repoName,
|
||||||
issue_number: prNumber,
|
issue_number: prNumber,
|
||||||
body: `## 🚀 Translation Verification Summary\n\n\n${SCRIPT_OUTPUT}\n`
|
body: `## 🚀 Translation Verification Summary\n\n\n${ERROR_OUTPUT}\n`
|
||||||
});
|
});
|
||||||
console.log("Created new comment.");
|
console.log("Created new comment.");
|
||||||
} else {
|
} else {
|
||||||
console.log("Comment update attempt denied. Actor does not match.");
|
console.log("Comment update attempt denied. Actor does not match.");
|
||||||
}
|
}
|
||||||
|
|
||||||
- name: Fail job if errors found
|
# - name: Set up git config
|
||||||
if: env.FAIL_JOB == 'true'
|
# run: |
|
||||||
run: |
|
# git config --global user.name "github-actions[bot]"
|
||||||
echo "Failing the job because errors were detected."
|
# git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
exit 1
|
|
||||||
|
# - name: Add translation keys
|
||||||
|
# run: |
|
||||||
|
# cd ${{ env.BRANCH_PATH }}
|
||||||
|
# git add src/main/resources/messages_*.properties
|
||||||
|
# git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
|
||||||
|
# git commit -m "Update translation files" || echo "No changes to commit"
|
||||||
|
# - name: Push
|
||||||
|
# if: env.CHANGES_DETECTED == 'true'
|
||||||
|
# run: |
|
||||||
|
# cd pr-branch
|
||||||
|
# git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.event.pull_request.head.repo.full_name }}.git
|
||||||
|
# git push origin ${{ github.head_ref }} || echo "Push failed: possibly no changes to push"
|
||||||
|
|
||||||
update-translations-main:
|
update-translations-main:
|
||||||
if: github.event_name == 'push'
|
if: github.event_name == 'push'
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
@@ -174,10 +169,7 @@ jobs:
|
|||||||
- name: Run Python script to check files
|
- name: Run Python script to check files
|
||||||
id: run-check
|
id: run-check
|
||||||
run: |
|
run: |
|
||||||
echo "Running Python script to check files..."
|
python .github/scripts/check_language_properties.py --reference-file src/main/resources/messages_en_GB.properties --branch main
|
||||||
python .github/scripts/check_language_properties.py \
|
|
||||||
--reference-file src/main/resources/messages_en_GB.properties \
|
|
||||||
--branch main
|
|
||||||
|
|
||||||
- name: Set up git config
|
- name: Set up git config
|
||||||
run: |
|
run: |
|
||||||
@@ -192,7 +184,7 @@ jobs:
|
|||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
id: cpr
|
id: cpr
|
||||||
if: env.CHANGES_DETECTED == 'true'
|
if: env.CHANGES_DETECTED == 'true'
|
||||||
uses: peter-evans/create-pull-request@v7
|
uses: peter-evans/create-pull-request@v6
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
commit-message: "Update translation files"
|
commit-message: "Update translation files"
|
||||||
@@ -201,8 +193,6 @@ jobs:
|
|||||||
signoff: true
|
signoff: true
|
||||||
branch: update_translation_files
|
branch: update_translation_files
|
||||||
title: "Update translation files"
|
title: "Update translation files"
|
||||||
add-paths: |
|
|
||||||
src/main/resources/messages_*.properties
|
|
||||||
body: |
|
body: |
|
||||||
Auto-generated by [create-pull-request][1]
|
Auto-generated by [create-pull-request][1]
|
||||||
|
|
||||||
@@ -210,4 +200,3 @@ jobs:
|
|||||||
labels: Translation
|
labels: Translation
|
||||||
draft: false
|
draft: false
|
||||||
delete-branch: true
|
delete-branch: true
|
||||||
sign-commits: true
|
|
||||||
|
|||||||
3
.github/workflows/push-docker.yml
vendored
3
.github/workflows/push-docker.yml
vendored
@@ -67,7 +67,6 @@ jobs:
|
|||||||
images: |
|
images: |
|
||||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
|
||||||
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }},enable=${{ github.ref == 'refs/heads/master' }}
|
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }},enable=${{ github.ref == 'refs/heads/master' }}
|
||||||
@@ -96,7 +95,6 @@ jobs:
|
|||||||
images: |
|
images: |
|
||||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
|
||||||
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
||||||
@@ -124,7 +122,6 @@ jobs:
|
|||||||
images: |
|
images: |
|
||||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
|
||||||
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-fat,enable=${{ github.ref == 'refs/heads/master' }}
|
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-fat,enable=${{ github.ref == 'refs/heads/master' }}
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ These files provide pre-configured setups for different scenarios. For example,
|
|||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Security
|
container_name: Stirling-PDF-Security
|
||||||
image: stirlingtools/stirling-pdf:latest
|
image: frooodle/s-pdf:latest
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
@@ -173,20 +173,20 @@ Stirling-PDF uses different Docker images for various configurations. The build
|
|||||||
For the latest version:
|
For the latest version:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest -f ./Dockerfile .
|
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest -f ./Dockerfile .
|
||||||
```
|
```
|
||||||
|
|
||||||
For the ultra-lite version:
|
For the ultra-lite version:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
|
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
|
||||||
```
|
```
|
||||||
|
|
||||||
For the fat version (with security enabled):
|
For the fat version (with security enabled):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export DOCKER_ENABLE_SECURITY=true
|
export DOCKER_ENABLE_SECURITY=true
|
||||||
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest-fat -f ./Dockerfile-fat .
|
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-fat -f ./Dockerfile-fat .
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: The `--no-cache` and `--pull` flags ensure that the build process uses the latest base images and doesn't use cached layers, which is useful for testing and ensuring reproducible builds. however to improve build times these can often be removed depending on your usecase
|
Note: The `--no-cache` and `--pull` flags ensure that the build process uses the latest base images and doesn't use cached layers, which is useful for testing and ensuring reproducible builds. however to improve build times these can often be removed depending on your usecase
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Build the application
|
# Build the application
|
||||||
FROM gradle:8.11-jdk17 AS build
|
FROM gradle:8.7-jdk17 AS build
|
||||||
|
|
||||||
# Set the working directory
|
# Set the working directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|||||||
45
Jenkinsfile
vendored
Normal file
45
Jenkinsfile
vendored
Normal file
@@ -0,0 +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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
81
README.md
81
README.md
@@ -120,13 +120,13 @@ Please view the [LocalRunGuide](https://github.com/Stirling-Tools/Stirling-PDF/b
|
|||||||
### Docker / Podman
|
### Docker / Podman
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> <https://hub.docker.com/r/stirlingtools/stirling-pdf>
|
> <https://hub.docker.com/r/frooodle/s-pdf>
|
||||||
|
|
||||||
Stirling-PDF has three different versions: a full version, an ultra-lite version, and a 'fat' version. Depending on the types of features you use, you may want a smaller image to save on space. To see what the different versions offer, please look at our [version mapping](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/Version-groups.md). For people that don't mind space optimization, just use the latest tag.
|
Stirling-PDF has three different versions: a full version, an ultra-lite version, and a 'fat' version. Depending on the types of features you use, you may want a smaller image to save on space. To see what the different versions offer, please look at our [version mapping](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/Version-groups.md). For people that don't mind space optimization, just use the latest tag.
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
Please note in the examples below, you may need to change the volume paths as needed, e.g., `./extraConfigs:/configs` to `/opt/stirlingpdf/extraConfigs:/configs`.
|
Please note in the examples below, you may need to change the volume paths as needed, e.g., `./extraConfigs:/configs` to `/opt/stirlingpdf/extraConfigs:/configs`.
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@ docker run -d \
|
|||||||
-e INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false \
|
-e INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false \
|
||||||
-e LANGS=en_GB \
|
-e LANGS=en_GB \
|
||||||
--name stirling-pdf \
|
--name stirling-pdf \
|
||||||
stirlingtools/stirling-pdf:latest
|
frooodle/s-pdf:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
### Docker Compose
|
### Docker Compose
|
||||||
@@ -153,7 +153,7 @@ docker run -d \
|
|||||||
version: '3.3'
|
version: '3.3'
|
||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
image: stirlingtools/stirling-pdf:latest
|
image: frooodle/s-pdf:latest
|
||||||
ports:
|
ports:
|
||||||
- '8080:8080'
|
- '8080:8080'
|
||||||
volumes:
|
volumes:
|
||||||
@@ -186,47 +186,46 @@ Certain functionality like `Sign` supports pre-saved files stored at `/customFil
|
|||||||
|
|
||||||
## Supported Languages
|
## Supported Languages
|
||||||
|
|
||||||
Stirling-PDF currently supports 37 languages!
|
Stirling-PDF currently supports 36 languages!
|
||||||
|
|
||||||
| Language | Progress |
|
| Language | Progress |
|
||||||
| -------------------------------------------- | -------------------------------------- |
|
| -------------------------------------------- | -------------------------------------- |
|
||||||
| Arabic (العربية) (ar_AR) |  |
|
| Arabic (العربية) (ar_AR) |  |
|
||||||
| Azerbaijani (Azərbaycan Dili) (az_AZ) |  |
|
| Basque (Euskara) (eu_ES) |  |
|
||||||
| Basque (Euskara) (eu_ES) |  |
|
| Bulgarian (Български) (bg_BG) |  |
|
||||||
| Bulgarian (Български) (bg_BG) |  |
|
| Catalan (Català) (ca_CA) |  |
|
||||||
| Catalan (Català) (ca_CA) |  |
|
| Croatian (Hrvatski) (hr_HR) |  |
|
||||||
| Croatian (Hrvatski) (hr_HR) |  |
|
| Czech (Česky) (cs_CZ) |  |
|
||||||
| Czech (Česky) (cs_CZ) |  |
|
| Danish (Dansk) (da_DK) |  |
|
||||||
| Danish (Dansk) (da_DK) |  |
|
| Dutch (Nederlands) (nl_NL) |  |
|
||||||
| Dutch (Nederlands) (nl_NL) |  |
|
|
||||||
| English (English) (en_GB) |  |
|
| English (English) (en_GB) |  |
|
||||||
| English (US) (en_US) |  |
|
| English (US) (en_US) |  |
|
||||||
| French (Français) (fr_FR) |  |
|
| French (Français) (fr_FR) |  |
|
||||||
| German (Deutsch) (de_DE) |  |
|
| German (Deutsch) (de_DE) |  |
|
||||||
| Greek (Ελληνικά) (el_GR) |  |
|
| Greek (Ελληνικά) (el_GR) |  |
|
||||||
| Hindi (हिंदी) (hi_IN) |  |
|
| Hindi (हिंदी) (hi_IN) |  |
|
||||||
| Hungarian (Magyar) (hu_HU) |  |
|
| Hungarian (Magyar) (hu_HU) |  |
|
||||||
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
||||||
| Irish (Gaeilge) (ga_IE) |  |
|
| Irish (Gaeilge) (ga_IE) |  |
|
||||||
| Italian (Italiano) (it_IT) |  |
|
| Italian (Italiano) (it_IT) |  |
|
||||||
| Japanese (日本語) (ja_JP) |  |
|
| Japanese (日本語) (ja_JP) |  |
|
||||||
| Korean (한국어) (ko_KR) |  |
|
| Korean (한국어) (ko_KR) |  |
|
||||||
| Norwegian (Norsk) (no_NB) |  |
|
| Norwegian (Norsk) (no_NB) |  |
|
||||||
| Polish (Polski) (pl_PL) |  |
|
| Polish (Polski) (pl_PL) |  |
|
||||||
| Portuguese (Português) (pt_PT) |  |
|
| Portuguese (Português) (pt_PT) |  |
|
||||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||||
| Romanian (Română) (ro_RO) |  |
|
| Romanian (Română) (ro_RO) |  |
|
||||||
| Russian (Русский) (ru_RU) |  |
|
| Russian (Русский) (ru_RU) |  |
|
||||||
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||||
| Slovakian (Slovensky) (sk_SK) |  |
|
| Slovakian (Slovensky) (sk_SK) |  |
|
||||||
| Spanish (Español) (es_ES) |  |
|
| Spanish (Español) (es_ES) |  |
|
||||||
| Swedish (Svenska) (sv_SE) |  |
|
| Swedish (Svenska) (sv_SE) |  |
|
||||||
| Thai (ไทย) (th_TH) |  |
|
| Thai (ไทย) (th_TH) |  |
|
||||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||||
| Turkish (Türkçe) (tr_TR) |  |
|
| Turkish (Türkçe) (tr_TR) |  |
|
||||||
| Ukrainian (Українська) (uk_UA) |  |
|
| Ukrainian (Українська) (uk_UA) |  |
|
||||||
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
||||||
|
|
||||||
## Contributing (Creating Issues, Translations, Fixing Bugs, etc.)
|
## Contributing (Creating Issues, Translations, Fixing Bugs, etc.)
|
||||||
|
|
||||||
|
|||||||
30
build.gradle
30
build.gradle
@@ -1,6 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "java"
|
id "java"
|
||||||
id "org.springframework.boot" version "3.4.0"
|
id "org.springframework.boot" version "3.3.5"
|
||||||
id "io.spring.dependency-management" version "1.1.6"
|
id "io.spring.dependency-management" version "1.1.6"
|
||||||
id "org.springdoc.openapi-gradle-plugin" version "1.8.0"
|
id "org.springdoc.openapi-gradle-plugin" version "1.8.0"
|
||||||
id "io.swagger.swaggerhub" version "1.3.2"
|
id "io.swagger.swaggerhub" version "1.3.2"
|
||||||
@@ -10,21 +10,19 @@ plugins {
|
|||||||
//id "nebula.lint" version "19.0.3"
|
//id "nebula.lint" version "19.0.3"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import com.github.jk1.license.render.*
|
import com.github.jk1.license.render.*
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
springBootVersion = "3.4.0"
|
springBootVersion = "3.3.5"
|
||||||
pdfboxVersion = "3.0.3"
|
pdfboxVersion = "3.0.3"
|
||||||
logbackVersion = "1.5.7"
|
logbackVersion = "1.5.7"
|
||||||
imageioVersion = "3.12.0"
|
imageioVersion = "3.12.0"
|
||||||
lombokVersion = "1.18.36"
|
lombokVersion = "1.18.34"
|
||||||
bouncycastleVersion = "1.79"
|
bouncycastleVersion = "1.78.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "stirling.software"
|
group = "stirling.software"
|
||||||
version = "0.34.0"
|
version = "0.32.0"
|
||||||
|
|
||||||
java {
|
java {
|
||||||
// 17 is lowest but we support and recommend 21
|
// 17 is lowest but we support and recommend 21
|
||||||
@@ -121,7 +119,7 @@ configurations.all {
|
|||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
//security updates
|
//security updates
|
||||||
implementation "org.springframework:spring-webmvc:6.2.0"
|
implementation "org.springframework:spring-webmvc:6.1.14"
|
||||||
|
|
||||||
implementation("io.github.pixee:java-security-toolkit:1.2.0")
|
implementation("io.github.pixee:java-security-toolkit:1.2.0")
|
||||||
|
|
||||||
@@ -143,10 +141,11 @@ dependencies {
|
|||||||
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
|
||||||
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
|
||||||
|
|
||||||
implementation 'org.springframework.security:spring-security-saml2-service-provider:6.4.1'
|
implementation 'org.springframework.security:spring-security-saml2-service-provider:6.3.4'
|
||||||
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
|
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
|
||||||
// Don't upgrade h2database
|
//2.2.x requires rebuild of DB file.. need migration path
|
||||||
runtimeOnly "com.h2database:h2:2.3.232"
|
runtimeOnly "com.h2database:h2:2.1.214"
|
||||||
|
// implementation "com.h2database:h2:2.2.224"
|
||||||
constraints {
|
constraints {
|
||||||
implementation "org.opensaml:opensaml-core"
|
implementation "org.opensaml:opensaml-core"
|
||||||
implementation "org.opensaml:opensaml-saml-api"
|
implementation "org.opensaml:opensaml-saml-api"
|
||||||
@@ -202,19 +201,12 @@ dependencies {
|
|||||||
exclude group: "commons-logging", module: "commons-logging"
|
exclude group: "commons-logging", module: "commons-logging"
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/technology.tabula/tabula
|
|
||||||
implementation ('technology.tabula:tabula:1.0.5') {
|
|
||||||
exclude group: "org.slf4j", module: "slf4j-simple"
|
|
||||||
exclude group: "org.bouncycastle", module: "bcprov-jdk15on"
|
|
||||||
exclude group: "com.google.code.gson", module: "gson"
|
|
||||||
}
|
|
||||||
|
|
||||||
implementation 'org.apache.pdfbox:jbig2-imageio:3.0.4'
|
implementation 'org.apache.pdfbox:jbig2-imageio:3.0.4'
|
||||||
|
|
||||||
implementation "org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion"
|
implementation "org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion"
|
||||||
implementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion"
|
implementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion"
|
||||||
implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion"
|
||||||
implementation "io.micrometer:micrometer-core:1.14.1"
|
implementation "io.micrometer:micrometer-core:1.13.6"
|
||||||
implementation group: "com.google.zxing", name: "core", version: "3.5.3"
|
implementation group: "com.google.zxing", name: "core", version: "3.5.3"
|
||||||
// https://mvnrepository.com/artifact/org.commonmark/commonmark
|
// https://mvnrepository.com/artifact/org.commonmark/commonmark
|
||||||
implementation "org.commonmark:commonmark:0.24.0"
|
implementation "org.commonmark:commonmark:0.24.0"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Security-Fat
|
container_name: Stirling-PDF-Security-Fat
|
||||||
image: stirlingtools/stirling-pdf:latest-fat
|
image: frooodle/s-pdf:latest-fat
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Security
|
container_name: Stirling-PDF-Security
|
||||||
image: stirlingtools/stirling-pdf:latest
|
image: frooodle/s-pdf:latest
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Security
|
container_name: Stirling-PDF-Security
|
||||||
image: stirlingtools/stirling-pdf:latest
|
image: frooodle/s-pdf:latest
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Ultra-Lite-Security
|
container_name: Stirling-PDF-Ultra-Lite-Security
|
||||||
image: stirlingtools/stirling-pdf:latest-ultra-lite
|
image: frooodle/s-pdf:latest-ultra-lite
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Ultra-Lite
|
container_name: Stirling-PDF-Ultra-Lite
|
||||||
image: stirlingtools/stirling-pdf:latest-ultra-lite
|
image: frooodle/s-pdf:latest-ultra-lite
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF
|
container_name: Stirling-PDF
|
||||||
image: stirlingtools/stirling-pdf:latest
|
image: frooodle/s-pdf:latest
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|||||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@@ -3,11 +3,6 @@ ignore = [
|
|||||||
'language.direction',
|
'language.direction',
|
||||||
]
|
]
|
||||||
|
|
||||||
[az_AZ]
|
|
||||||
ignore = [
|
|
||||||
'language.direction',
|
|
||||||
]
|
|
||||||
|
|
||||||
[bg_BG]
|
[bg_BG]
|
||||||
ignore = [
|
ignore = [
|
||||||
'language.direction',
|
'language.direction',
|
||||||
@@ -37,12 +32,12 @@ ignore = [
|
|||||||
ignore = [
|
ignore = [
|
||||||
'AddStampRequest.alphabet',
|
'AddStampRequest.alphabet',
|
||||||
'AddStampRequest.position',
|
'AddStampRequest.position',
|
||||||
|
'home.pipeline.title'
|
||||||
'PDFToBook.selectText.1',
|
'PDFToBook.selectText.1',
|
||||||
'PDFToText.tags',
|
'PDFToText.tags',
|
||||||
'addPageNumbers.selectText.3',
|
'addPageNumbers.selectText.3',
|
||||||
'alphabet',
|
'alphabet',
|
||||||
'certSign.name',
|
'certSign.name',
|
||||||
'home.pipeline.title',
|
|
||||||
'language.direction',
|
'language.direction',
|
||||||
'licenses.version',
|
'licenses.version',
|
||||||
'pipeline.title',
|
'pipeline.title',
|
||||||
@@ -51,6 +46,7 @@ ignore = [
|
|||||||
'sponsor',
|
'sponsor',
|
||||||
'text',
|
'text',
|
||||||
'watermark.type.1',
|
'watermark.type.1',
|
||||||
|
'certSign.name',
|
||||||
]
|
]
|
||||||
|
|
||||||
[el_GR]
|
[el_GR]
|
||||||
|
|||||||
@@ -452,7 +452,7 @@ public class SecurityConfiguration {
|
|||||||
RelyingPartyRegistration rp =
|
RelyingPartyRegistration rp =
|
||||||
RelyingPartyRegistration.withRegistrationId(samlConf.getRegistrationId())
|
RelyingPartyRegistration.withRegistrationId(samlConf.getRegistrationId())
|
||||||
.signingX509Credentials((c) -> c.add(signingCredential))
|
.signingX509Credentials((c) -> c.add(signingCredential))
|
||||||
.assertingPartyMetadata(
|
.assertingPartyDetails(
|
||||||
(details) ->
|
(details) ->
|
||||||
details.entityId(samlConf.getIdpIssuer())
|
details.entityId(samlConf.getIdpIssuer())
|
||||||
.singleSignOnServiceLocation(
|
.singleSignOnServiceLocation(
|
||||||
|
|||||||
@@ -34,12 +34,6 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
|
|||||||
@Value("${spring.datasource.url}")
|
@Value("${spring.datasource.url}")
|
||||||
private String url;
|
private String url;
|
||||||
|
|
||||||
@Value("${spring.datasource.username}")
|
|
||||||
private String databaseUsername;
|
|
||||||
|
|
||||||
@Value("${spring.datasource.password}")
|
|
||||||
private String databasePassword;
|
|
||||||
|
|
||||||
private Path backupPath = Paths.get("configs/db/backup/");
|
private Path backupPath = Paths.get("configs/db/backup/");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -140,8 +134,7 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
|
|||||||
this.getBackupFilePath("backup_" + dateNow.format(myFormatObj) + ".sql");
|
this.getBackupFilePath("backup_" + dateNow.format(myFormatObj) + ".sql");
|
||||||
String query = "SCRIPT SIMPLE COLUMNS DROP to ?;";
|
String query = "SCRIPT SIMPLE COLUMNS DROP to ?;";
|
||||||
|
|
||||||
try (Connection conn =
|
try (Connection conn = DriverManager.getConnection(url, "sa", "");
|
||||||
DriverManager.getConnection(url, databaseUsername, databasePassword);
|
|
||||||
PreparedStatement stmt = conn.prepareStatement(query)) {
|
PreparedStatement stmt = conn.prepareStatement(query)) {
|
||||||
stmt.setString(1, insertOutputFilePath.toString());
|
stmt.setString(1, insertOutputFilePath.toString());
|
||||||
stmt.execute();
|
stmt.execute();
|
||||||
@@ -154,8 +147,7 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
|
|||||||
// Retrieves the H2 database version.
|
// Retrieves the H2 database version.
|
||||||
public String getH2Version() {
|
public String getH2Version() {
|
||||||
String version = "Unknown";
|
String version = "Unknown";
|
||||||
try (Connection conn =
|
try (Connection conn = DriverManager.getConnection(url, "sa", "")) {
|
||||||
DriverManager.getConnection(url, databaseUsername, databasePassword)) {
|
|
||||||
try (Statement stmt = conn.createStatement();
|
try (Statement stmt = conn.createStatement();
|
||||||
ResultSet rs = stmt.executeQuery("SELECT H2VERSION() AS version")) {
|
ResultSet rs = stmt.executeQuery("SELECT H2VERSION() AS version")) {
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
@@ -197,8 +189,7 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
|
|||||||
private boolean executeDatabaseScript(Path scriptPath) {
|
private boolean executeDatabaseScript(Path scriptPath) {
|
||||||
String query = "RUNSCRIPT from ?;";
|
String query = "RUNSCRIPT from ?;";
|
||||||
|
|
||||||
try (Connection conn =
|
try (Connection conn = DriverManager.getConnection(url, "sa", "");
|
||||||
DriverManager.getConnection(url, databaseUsername, databasePassword);
|
|
||||||
PreparedStatement stmt = conn.prepareStatement(query)) {
|
PreparedStatement stmt = conn.prepareStatement(query)) {
|
||||||
stmt.setString(1, scriptPath.toString());
|
stmt.setString(1, scriptPath.toString());
|
||||||
stmt.execute();
|
stmt.execute();
|
||||||
|
|||||||
@@ -1,18 +1,25 @@
|
|||||||
package stirling.software.SPDF.config.security.saml2;
|
package stirling.software.SPDF.config.security.saml2;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.URL;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.KeyFactory;
|
import java.security.KeyFactory;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.security.interfaces.RSAPrivateKey;
|
import java.security.interfaces.RSAPrivateKey;
|
||||||
import java.security.spec.PKCS8EncodedKeySpec;
|
import java.security.spec.PKCS8EncodedKeySpec;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
import org.bouncycastle.util.io.pem.PemObject;
|
import org.bouncycastle.util.io.pem.PemObject;
|
||||||
import org.bouncycastle.util.io.pem.PemReader;
|
import org.bouncycastle.util.io.pem.PemReader;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.UrlResource;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
public class CertificateUtils {
|
public class CertificateUtils {
|
||||||
|
|
||||||
public static X509Certificate readCertificate(Resource certificateResource) throws Exception {
|
public static X509Certificate readCertificate(Resource certificateResource) throws Exception {
|
||||||
@@ -39,4 +46,84 @@ public class CertificateUtils {
|
|||||||
.generatePrivate(new PKCS8EncodedKeySpec(decodedKey));
|
.generatePrivate(new PKCS8EncodedKeySpec(decodedKey));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static X509Certificate getIdPCertificate(Resource certificateResource) throws Exception {
|
||||||
|
|
||||||
|
if (certificateResource instanceof UrlResource) {
|
||||||
|
return extractCertificateFromMetadata(certificateResource);
|
||||||
|
} else {
|
||||||
|
// Treat as file resource
|
||||||
|
return readCertificate(certificateResource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static X509Certificate extractCertificateFromMetadata(Resource metadataResource) throws Exception {
|
||||||
|
log.info("Attempting to extract certificate from metadata resource: {}", metadataResource.getDescription());
|
||||||
|
|
||||||
|
try (InputStream is = metadataResource.getInputStream()) {
|
||||||
|
String content = new String(is.readAllBytes(), StandardCharsets.UTF_8);
|
||||||
|
log.info("Retrieved metadata content, length: {}", content.length());
|
||||||
|
|
||||||
|
// Find the certificate data
|
||||||
|
int startIndex = content.indexOf("<ds:X509Certificate>");
|
||||||
|
int endIndex = content.indexOf("</ds:X509Certificate>");
|
||||||
|
|
||||||
|
if (startIndex == -1 || endIndex == -1) {
|
||||||
|
log.error("Certificate tags not found in metadata");
|
||||||
|
throw new Exception("Certificate tags not found in metadata");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract certificate data
|
||||||
|
String certData = content.substring(
|
||||||
|
startIndex + "<ds:X509Certificate>".length(),
|
||||||
|
endIndex
|
||||||
|
).trim();
|
||||||
|
|
||||||
|
log.info("Found certificate data, length: {}", certData.length());
|
||||||
|
|
||||||
|
// Remove any whitespace and newlines from cert data
|
||||||
|
certData = certData.replaceAll("\\s+", "");
|
||||||
|
|
||||||
|
// Reconstruct PEM format with proper line breaks
|
||||||
|
StringBuilder pemBuilder = new StringBuilder();
|
||||||
|
pemBuilder.append("-----BEGIN CERTIFICATE-----\n");
|
||||||
|
|
||||||
|
// Insert line breaks every 64 characters
|
||||||
|
int lineLength = 64;
|
||||||
|
for (int i = 0; i < certData.length(); i += lineLength) {
|
||||||
|
int end = Math.min(i + lineLength, certData.length());
|
||||||
|
pemBuilder.append(certData, i, end).append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
pemBuilder.append("-----END CERTIFICATE-----");
|
||||||
|
String pemCert = pemBuilder.toString();
|
||||||
|
|
||||||
|
log.debug("Reconstructed PEM certificate:\n{}", pemCert);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ByteArrayInputStream pemStream = new ByteArrayInputStream(pemCert.getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||||
|
X509Certificate cert = (X509Certificate) cf.generateCertificate(pemStream);
|
||||||
|
|
||||||
|
log.info("Successfully parsed certificate. Subject: {}", cert.getSubjectX500Principal());
|
||||||
|
|
||||||
|
// Optional: check validity dates
|
||||||
|
cert.checkValidity(); // Throws CertificateExpiredException if expired
|
||||||
|
log.info("Certificate is valid (not expired)");
|
||||||
|
|
||||||
|
return cert;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to parse certificate", e);
|
||||||
|
throw new Exception("Failed to parse X509 certificate from metadata", e);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error processing metadata resource", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,23 +16,35 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class CustomSaml2AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
|
public class CustomSaml2AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAuthenticationFailure(
|
public void onAuthenticationFailure(
|
||||||
HttpServletRequest request,
|
HttpServletRequest request,
|
||||||
HttpServletResponse response,
|
HttpServletResponse response,
|
||||||
AuthenticationException exception)
|
AuthenticationException exception)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
if (exception instanceof Saml2AuthenticationException) {
|
|
||||||
Saml2Error error = ((Saml2AuthenticationException) exception).getSaml2Error();
|
if (exception instanceof Saml2AuthenticationException saml2Exception) {
|
||||||
getRedirectStrategy()
|
Saml2Error error = saml2Exception.getSaml2Error();
|
||||||
.sendRedirect(request, response, "/login?erroroauth=" + error.getErrorCode());
|
|
||||||
} else if (exception instanceof ProviderNotFoundException) {
|
// Log detailed information about the SAML error
|
||||||
getRedirectStrategy()
|
log.error("SAML Authentication failed with error code: {}", error.getErrorCode());
|
||||||
.sendRedirect(
|
log.error("Error description: {}", error.getDescription());
|
||||||
request,
|
|
||||||
response,
|
// Redirect to login with specific error code
|
||||||
"/login?erroroauth=not_authentication_provider_found");
|
getRedirectStrategy()
|
||||||
}
|
.sendRedirect(request, response, "/login?erroroauth=" + error.getErrorCode());
|
||||||
log.error("AuthenticationException: " + exception);
|
} else if (exception instanceof ProviderNotFoundException) {
|
||||||
}
|
log.error("Authentication failed: No authentication provider found");
|
||||||
|
|
||||||
|
getRedirectStrategy()
|
||||||
|
.sendRedirect(
|
||||||
|
request,
|
||||||
|
response,
|
||||||
|
"/login?erroroauth=not_authentication_provider_found");
|
||||||
|
} else {
|
||||||
|
log.error("Unknown AuthenticationException: {}", exception.getMessage());
|
||||||
|
getRedirectStrategy().sendRedirect(request, response, "/login?erroroauth=unknown_error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package stirling.software.SPDF.config.security.saml2;
|
||||||
|
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider;
|
||||||
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
|
||||||
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider;
|
||||||
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
|
||||||
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken;
|
||||||
|
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
|
||||||
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.saml2.core.Saml2ErrorCodes;
|
||||||
|
|
||||||
|
public class LoggingSamlAuthenticationProvider implements AuthenticationProvider {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(LoggingSamlAuthenticationProvider.class);
|
||||||
|
private final OpenSaml4AuthenticationProvider delegate;
|
||||||
|
|
||||||
|
public LoggingSamlAuthenticationProvider(OpenSaml4AuthenticationProvider delegate) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
|
if (authentication instanceof Saml2AuthenticationToken token) {
|
||||||
|
String samlResponse = token.getSaml2Response();
|
||||||
|
|
||||||
|
// Log the raw SAML response
|
||||||
|
log.info("Raw SAML Response (Base64): {}", samlResponse);
|
||||||
|
|
||||||
|
// Decode and log the SAML response XML
|
||||||
|
try {
|
||||||
|
String decodedResponse = new String(Base64.getDecoder().decode(samlResponse), StandardCharsets.UTF_8);
|
||||||
|
log.info("Decoded SAML Response XML:\n{}", decodedResponse);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// If decoding fails, it’s likely already plain XML
|
||||||
|
log.warn("SAML Response appears to be different format, not Base64-encoded.");
|
||||||
|
log.debug("SAML Response XML:\n{}", samlResponse);
|
||||||
|
}
|
||||||
|
// Delegate the actual authentication to the wrapped OpenSaml4AuthenticationProvider
|
||||||
|
try {
|
||||||
|
return delegate.authenticate(authentication);
|
||||||
|
} catch (Saml2AuthenticationException e) {
|
||||||
|
log.error("SAML authentication failed: {}");
|
||||||
|
log.error("Detailed error message: {}", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(Class<?> authentication) {
|
||||||
|
// Only support Saml2AuthenticationToken
|
||||||
|
return Saml2AuthenticationToken.class.isAssignableFrom(authentication);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
package stirling.software.SPDF.controller.api.converters;
|
package stirling.software.SPDF.controller.api.converters;
|
||||||
|
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.csv.CSVFormat;
|
|
||||||
import org.apache.commons.csv.QuoteMode;
|
|
||||||
import org.apache.pdfbox.Loader;
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.ContentDisposition;
|
import org.springframework.http.ContentDisposition;
|
||||||
@@ -18,36 +18,79 @@ import org.springframework.web.bind.annotation.PostMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import com.opencsv.CSVWriter;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import stirling.software.SPDF.controller.api.CropController;
|
import stirling.software.SPDF.controller.api.CropController;
|
||||||
|
import stirling.software.SPDF.controller.api.strippers.PDFTableStripper;
|
||||||
import stirling.software.SPDF.model.api.extract.PDFFilePage;
|
import stirling.software.SPDF.model.api.extract.PDFFilePage;
|
||||||
import stirling.software.SPDF.pdf.FlexibleCSVWriter;
|
|
||||||
import technology.tabula.ObjectExtractor;
|
|
||||||
import technology.tabula.Page;
|
|
||||||
import technology.tabula.Table;
|
|
||||||
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;
|
|
||||||
import technology.tabula.writers.Writer;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/convert")
|
@RequestMapping("/api/v1/convert")
|
||||||
@Tag(name = "Convert", description = "Convert APIs")
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
public class ExtractCSVController {
|
public class ExtractCSVController {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(ExtractCSVController.class);
|
private static final Logger logger = LoggerFactory.getLogger(CropController.class);
|
||||||
|
|
||||||
@PostMapping(value = "/pdf/csv", consumes = "multipart/form-data")
|
@PostMapping(value = "/pdf/csv", consumes = "multipart/form-data")
|
||||||
@Operation(summary = "Extracts a CSV document from a PDF", description = "This operation takes an input PDF file and returns CSV file of whole page. Input:PDF Output:CSV Type:SISO")
|
@Operation(
|
||||||
|
summary = "Extracts a CSV document from a PDF",
|
||||||
|
description =
|
||||||
|
"This operation takes an input PDF file and returns CSV file of whole page. Input:PDF Output:CSV Type:SISO")
|
||||||
public ResponseEntity<String> PdfToCsv(@ModelAttribute PDFFilePage form) throws Exception {
|
public ResponseEntity<String> PdfToCsv(@ModelAttribute PDFFilePage form) throws Exception {
|
||||||
StringWriter writer = new StringWriter();
|
|
||||||
|
ArrayList<String> tableData = new ArrayList<>();
|
||||||
|
int columnsCount = 0;
|
||||||
|
|
||||||
try (PDDocument document = Loader.loadPDF(form.getFileInput().getBytes())) {
|
try (PDDocument document = Loader.loadPDF(form.getFileInput().getBytes())) {
|
||||||
CSVFormat format = CSVFormat.EXCEL.builder().setEscape('"').setQuoteMode(QuoteMode.ALL).build();
|
final double res = 72; // PDF units are at 72 DPI
|
||||||
Writer csvWriter = new FlexibleCSVWriter(format);
|
PDFTableStripper stripper = new PDFTableStripper();
|
||||||
SpreadsheetExtractionAlgorithm sea = new SpreadsheetExtractionAlgorithm();
|
PDPage pdPage = document.getPage(form.getPageId() - 1);
|
||||||
try (ObjectExtractor extractor = new ObjectExtractor(document)) {
|
stripper.extractTable(pdPage);
|
||||||
Page page = extractor.extract(form.getPageId());
|
columnsCount = stripper.getColumns();
|
||||||
List<Table> tables = sea.extract(page);
|
for (int c = 0; c < columnsCount; ++c) {
|
||||||
csvWriter.write(writer, tables);
|
for (int r = 0; r < stripper.getRows(); ++r) {
|
||||||
|
tableData.add(stripper.getText(r, c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<String> notEmptyColumns = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String item : tableData) {
|
||||||
|
if (!item.trim().isEmpty()) {
|
||||||
|
notEmptyColumns.add(item);
|
||||||
|
} else {
|
||||||
|
columnsCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> fullTable =
|
||||||
|
notEmptyColumns.stream()
|
||||||
|
.map(
|
||||||
|
(entity) ->
|
||||||
|
entity.replace('\n', ' ')
|
||||||
|
.replace('\r', ' ')
|
||||||
|
.trim()
|
||||||
|
.replaceAll("\\s{2,}", "|"))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
int rowsCount = fullTable.get(0).split("\\|").length;
|
||||||
|
|
||||||
|
ArrayList<String> headersList = getTableHeaders(columnsCount, fullTable);
|
||||||
|
ArrayList<String> recordList = getRecordsList(rowsCount, fullTable);
|
||||||
|
|
||||||
|
if (headersList.size() == 0 && recordList.size() == 0) {
|
||||||
|
throw new Exception("No table detected, no headers or records found");
|
||||||
|
}
|
||||||
|
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
try (CSVWriter csvWriter = new CSVWriter(writer)) {
|
||||||
|
csvWriter.writeNext(headersList.toArray(new String[0]));
|
||||||
|
for (String record : recordList) {
|
||||||
|
csvWriter.writeNext(record.split("\\|"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,12 +99,41 @@ public class ExtractCSVController {
|
|||||||
ContentDisposition.builder("attachment")
|
ContentDisposition.builder("attachment")
|
||||||
.filename(
|
.filename(
|
||||||
form.getFileInput()
|
form.getFileInput()
|
||||||
.getOriginalFilename()
|
.getOriginalFilename()
|
||||||
.replaceFirst("[.][^.]+$", "")
|
.replaceFirst("[.][^.]+$", "")
|
||||||
+ "_extracted.csv")
|
+ "_extracted.csv")
|
||||||
.build());
|
.build());
|
||||||
headers.setContentType(MediaType.parseMediaType("text/csv"));
|
headers.setContentType(MediaType.parseMediaType("text/csv"));
|
||||||
|
|
||||||
return ResponseEntity.ok().headers(headers).body(writer.toString());
|
return ResponseEntity.ok().headers(headers).body(writer.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ArrayList<String> getRecordsList(int rowsCounts, List<String> items) {
|
||||||
|
ArrayList<String> recordsList = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int b = 1; b < rowsCounts; b++) {
|
||||||
|
StringBuilder strbldr = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = 0; i < items.size(); i++) {
|
||||||
|
String[] parts = items.get(i).split("\\|");
|
||||||
|
strbldr.append(parts[b]);
|
||||||
|
if (i != items.size() - 1) {
|
||||||
|
strbldr.append("|");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
recordsList.add(strbldr.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return recordsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<String> getTableHeaders(int columnsCount, List<String> items) {
|
||||||
|
ArrayList<String> resultList = new ArrayList<>();
|
||||||
|
for (int i = 0; i < columnsCount; i++) {
|
||||||
|
String[] parts = items.get(i).split("\\|");
|
||||||
|
resultList.add(parts[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,10 +98,10 @@ public class CertSignController {
|
|||||||
|
|
||||||
public CreateSignature(KeyStore keystore, char[] pin)
|
public CreateSignature(KeyStore keystore, char[] pin)
|
||||||
throws KeyStoreException,
|
throws KeyStoreException,
|
||||||
UnrecoverableKeyException,
|
UnrecoverableKeyException,
|
||||||
NoSuchAlgorithmException,
|
NoSuchAlgorithmException,
|
||||||
IOException,
|
IOException,
|
||||||
CertificateException {
|
CertificateException {
|
||||||
super(keystore, pin);
|
super(keystore, pin);
|
||||||
ClassPathResource resource = new ClassPathResource("static/images/signature.png");
|
ClassPathResource resource = new ClassPathResource("static/images/signature.png");
|
||||||
try (InputStream is = resource.getInputStream()) {
|
try (InputStream is = resource.getInputStream()) {
|
||||||
@@ -160,7 +160,8 @@ public class CertSignController {
|
|||||||
extState.setNonStrokingAlphaConstant(0.5f);
|
extState.setNonStrokingAlphaConstant(0.5f);
|
||||||
cs.setGraphicsStateParameters(extState);
|
cs.setGraphicsStateParameters(extState);
|
||||||
cs.transform(Matrix.getScaleInstance(0.08f, 0.08f));
|
cs.transform(Matrix.getScaleInstance(0.08f, 0.08f));
|
||||||
PDImageXObject img = PDImageXObject.createFromFileByExtension(logoFile, doc);
|
PDImageXObject img =
|
||||||
|
PDImageXObject.createFromFileByExtension(logoFile, doc);
|
||||||
cs.drawImage(img, 100, 0);
|
cs.drawImage(img, 100, 0);
|
||||||
cs.restoreGraphicsState();
|
cs.restoreGraphicsState();
|
||||||
}
|
}
|
||||||
@@ -208,7 +209,10 @@ public class CertSignController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/cert-sign")
|
@PostMapping(consumes = "multipart/form-data", value = "/cert-sign")
|
||||||
@Operation(summary = "Sign PDF with a Digital Certificate", description = "This endpoint accepts a PDF file, a digital certificate and related information to sign the PDF. It then returns the digitally signed PDF file. Input:PDF Output:PDF Type:SISO")
|
@Operation(
|
||||||
|
summary = "Sign PDF with a Digital Certificate",
|
||||||
|
description =
|
||||||
|
"This endpoint accepts a PDF file, a digital certificate and related information to sign the PDF. It then returns the digitally signed PDF file. Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> signPDFWithCert(@ModelAttribute SignPDFWithCertRequest request)
|
public ResponseEntity<byte[]> signPDFWithCert(@ModelAttribute SignPDFWithCertRequest request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
MultipartFile pdf = request.getFileInput();
|
MultipartFile pdf = request.getFileInput();
|
||||||
@@ -238,7 +242,7 @@ public class CertSignController {
|
|||||||
PrivateKey privateKey = getPrivateKeyFromPEM(privateKeyFile.getBytes(), password);
|
PrivateKey privateKey = getPrivateKeyFromPEM(privateKeyFile.getBytes(), password);
|
||||||
Certificate cert = (Certificate) getCertificateFromPEM(certFile.getBytes());
|
Certificate cert = (Certificate) getCertificateFromPEM(certFile.getBytes());
|
||||||
ks.setKeyEntry(
|
ks.setKeyEntry(
|
||||||
"alias", privateKey, password.toCharArray(), new Certificate[] { cert });
|
"alias", privateKey, password.toCharArray(), new Certificate[] {cert});
|
||||||
break;
|
break;
|
||||||
case "PKCS12":
|
case "PKCS12":
|
||||||
ks = KeyStore.getInstance("PKCS12");
|
ks = KeyStore.getInstance("PKCS12");
|
||||||
@@ -310,19 +314,22 @@ public class CertSignController {
|
|||||||
|
|
||||||
private PrivateKey getPrivateKeyFromPEM(byte[] pemBytes, String password)
|
private PrivateKey getPrivateKeyFromPEM(byte[] pemBytes, String password)
|
||||||
throws IOException, OperatorCreationException, PKCSException {
|
throws IOException, OperatorCreationException, PKCSException {
|
||||||
try (PEMParser pemParser = new PEMParser(new InputStreamReader(new ByteArrayInputStream(pemBytes)))) {
|
try (PEMParser pemParser =
|
||||||
|
new PEMParser(new InputStreamReader(new ByteArrayInputStream(pemBytes)))) {
|
||||||
Object pemObject = pemParser.readObject();
|
Object pemObject = pemParser.readObject();
|
||||||
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
|
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
|
||||||
PrivateKeyInfo pkInfo;
|
PrivateKeyInfo pkInfo;
|
||||||
if (pemObject instanceof PKCS8EncryptedPrivateKeyInfo) {
|
if (pemObject instanceof PKCS8EncryptedPrivateKeyInfo) {
|
||||||
InputDecryptorProvider decProv = new JceOpenSSLPKCS8DecryptorProviderBuilder()
|
InputDecryptorProvider decProv =
|
||||||
.build(password.toCharArray());
|
new JceOpenSSLPKCS8DecryptorProviderBuilder().build(password.toCharArray());
|
||||||
pkInfo = ((PKCS8EncryptedPrivateKeyInfo) pemObject).decryptPrivateKeyInfo(decProv);
|
pkInfo = ((PKCS8EncryptedPrivateKeyInfo) pemObject).decryptPrivateKeyInfo(decProv);
|
||||||
} else if (pemObject instanceof PEMEncryptedKeyPair) {
|
} else if (pemObject instanceof PEMEncryptedKeyPair) {
|
||||||
PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password.toCharArray());
|
PEMDecryptorProvider decProv =
|
||||||
pkInfo = ((PEMEncryptedKeyPair) pemObject)
|
new JcePEMDecryptorProviderBuilder().build(password.toCharArray());
|
||||||
.decryptKeyPair(decProv)
|
pkInfo =
|
||||||
.getPrivateKeyInfo();
|
((PEMEncryptedKeyPair) pemObject)
|
||||||
|
.decryptKeyPair(decProv)
|
||||||
|
.getPrivateKeyInfo();
|
||||||
} else {
|
} else {
|
||||||
pkInfo = ((PEMKeyPair) pemObject).getPrivateKeyInfo();
|
pkInfo = ((PEMKeyPair) pemObject).getPrivateKeyInfo();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,327 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.strippers;
|
||||||
|
|
||||||
|
import java.awt.Shape;
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.fontbox.util.BoundingBox;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
|
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||||
|
import org.apache.pdfbox.pdmodel.font.PDType3Font;
|
||||||
|
import org.apache.pdfbox.text.PDFTextStripper;
|
||||||
|
import org.apache.pdfbox.text.PDFTextStripperByArea;
|
||||||
|
import org.apache.pdfbox.text.TextPosition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to extract tabular data from a PDF. Works by making a first pass of the page to group all
|
||||||
|
* nearby text items together, and then inferring a 2D grid from these regions. Each table cell is
|
||||||
|
* then extracted using a PDFTextStripperByArea object.
|
||||||
|
*
|
||||||
|
* <p>Works best when headers are included in the detected region, to ensure representative text in
|
||||||
|
* every column.
|
||||||
|
*
|
||||||
|
* <p>Based upon DrawPrintTextLocations PDFBox example
|
||||||
|
* (https://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/DrawPrintTextLocations.java)
|
||||||
|
*
|
||||||
|
* @author Beldaz
|
||||||
|
*/
|
||||||
|
public class PDFTableStripper extends PDFTextStripper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will print the documents data, for each table cell.
|
||||||
|
*
|
||||||
|
* @param args The command line arguments.
|
||||||
|
* @throws IOException If there is an error parsing the document.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Used in methods derived from DrawPrintTextLocations
|
||||||
|
*/
|
||||||
|
private AffineTransform flipAT;
|
||||||
|
|
||||||
|
private AffineTransform rotateAT;
|
||||||
|
|
||||||
|
/** Regions updated by calls to writeString */
|
||||||
|
private Set<Rectangle2D> boxes;
|
||||||
|
|
||||||
|
// Border to allow when finding intersections
|
||||||
|
private double dx = 1.0; // This value works for me, feel free to tweak (or add setter)
|
||||||
|
private double dy = 0.000; // Rows of text tend to overlap, so need to extend
|
||||||
|
|
||||||
|
/** Region in which to find table (otherwise whole page) */
|
||||||
|
private Rectangle2D regionArea;
|
||||||
|
|
||||||
|
/** Number of rows in inferred table */
|
||||||
|
private int nRows = 0;
|
||||||
|
|
||||||
|
/** Number of columns in inferred table */
|
||||||
|
private int nCols = 0;
|
||||||
|
|
||||||
|
/** This is the object that does the text extraction */
|
||||||
|
private PDFTextStripperByArea regionStripper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1D intervals - used for calculateTableRegions()
|
||||||
|
*
|
||||||
|
* @author Beldaz
|
||||||
|
*/
|
||||||
|
public static class Interval {
|
||||||
|
double start;
|
||||||
|
double end;
|
||||||
|
|
||||||
|
public Interval(double start, double end) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(Interval col) {
|
||||||
|
if (col.start < start) start = col.start;
|
||||||
|
if (col.end > end) end = col.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addTo(Interval x, LinkedList<Interval> columns) {
|
||||||
|
int p = 0;
|
||||||
|
Iterator<Interval> it = columns.iterator();
|
||||||
|
// Find where x should go
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Interval col = it.next();
|
||||||
|
if (x.end >= col.start) {
|
||||||
|
if (x.start <= col.end) { // overlaps
|
||||||
|
x.add(col);
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Interval col = it.next();
|
||||||
|
if (x.start > col.end) break;
|
||||||
|
x.add(col);
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
columns.add(p, x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate a new PDFTableStripper object.
|
||||||
|
*
|
||||||
|
* @throws IOException If there is an error loading the properties.
|
||||||
|
*/
|
||||||
|
public PDFTableStripper() throws IOException {
|
||||||
|
super.setShouldSeparateByBeads(false);
|
||||||
|
regionStripper = new PDFTextStripperByArea();
|
||||||
|
regionStripper.setSortByPosition(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the region to group text by.
|
||||||
|
*
|
||||||
|
* @param rect The rectangle area to retrieve the text from.
|
||||||
|
*/
|
||||||
|
public void setRegion(Rectangle2D rect) {
|
||||||
|
regionArea = rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRows() {
|
||||||
|
return nRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColumns() {
|
||||||
|
return nCols;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the text for the region, this should be called after extractTable().
|
||||||
|
*
|
||||||
|
* @return The text that was identified in that region.
|
||||||
|
*/
|
||||||
|
public String getText(int row, int col) {
|
||||||
|
return regionStripper.getTextForRegion("el" + col + "x" + row);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void extractTable(PDPage pdPage) throws IOException {
|
||||||
|
setStartPage(getCurrentPageNo());
|
||||||
|
setEndPage(getCurrentPageNo());
|
||||||
|
|
||||||
|
boxes = new HashSet<Rectangle2D>();
|
||||||
|
// flip y-axis
|
||||||
|
flipAT = new AffineTransform();
|
||||||
|
flipAT.translate(0, pdPage.getBBox().getHeight());
|
||||||
|
flipAT.scale(1, -1);
|
||||||
|
|
||||||
|
// page may be rotated
|
||||||
|
rotateAT = new AffineTransform();
|
||||||
|
int rotation = pdPage.getRotation();
|
||||||
|
if (rotation != 0) {
|
||||||
|
PDRectangle mediaBox = pdPage.getMediaBox();
|
||||||
|
switch (rotation) {
|
||||||
|
case 90:
|
||||||
|
rotateAT.translate(mediaBox.getHeight(), 0);
|
||||||
|
break;
|
||||||
|
case 270:
|
||||||
|
rotateAT.translate(0, mediaBox.getWidth());
|
||||||
|
break;
|
||||||
|
case 180:
|
||||||
|
rotateAT.translate(mediaBox.getWidth(), mediaBox.getHeight());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rotateAT.rotate(Math.toRadians(rotation));
|
||||||
|
}
|
||||||
|
// Trigger processing of the document so that writeString is called.
|
||||||
|
try (Writer dummy = new OutputStreamWriter(new ByteArrayOutputStream())) {
|
||||||
|
super.output = dummy;
|
||||||
|
super.processPage(pdPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle2D[][] regions = calculateTableRegions();
|
||||||
|
|
||||||
|
// System.err.println("Drawing " + nCols + "x" + nRows + "="+ nRows*nCols + "
|
||||||
|
// regions");
|
||||||
|
for (int i = 0; i < nCols; ++i) {
|
||||||
|
for (int j = 0; j < nRows; ++j) {
|
||||||
|
final Rectangle2D region = regions[i][j];
|
||||||
|
regionStripper.addRegion("el" + i + "x" + j, region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
regionStripper.extractRegions(pdPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Infer a rectangular grid of regions from the boxes field.
|
||||||
|
*
|
||||||
|
* @return 2D array of table regions (as Rectangle2D objects). Note that some of these regions
|
||||||
|
* may have no content.
|
||||||
|
*/
|
||||||
|
private Rectangle2D[][] calculateTableRegions() {
|
||||||
|
|
||||||
|
// Build up a list of all table regions, based upon the populated
|
||||||
|
// regions of boxes field. Treats the horizontal and vertical extents
|
||||||
|
// of each box as distinct
|
||||||
|
LinkedList<Interval> columns = new LinkedList<Interval>();
|
||||||
|
LinkedList<Interval> rows = new LinkedList<Interval>();
|
||||||
|
|
||||||
|
for (Rectangle2D box : boxes) {
|
||||||
|
Interval x = new Interval(box.getMinX(), box.getMaxX());
|
||||||
|
Interval y = new Interval(box.getMinY(), box.getMaxY());
|
||||||
|
|
||||||
|
Interval.addTo(x, columns);
|
||||||
|
Interval.addTo(y, rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
nRows = rows.size();
|
||||||
|
nCols = columns.size();
|
||||||
|
Rectangle2D[][] regions = new Rectangle2D[nCols][nRows];
|
||||||
|
int i = 0;
|
||||||
|
// Label regions from top left, rather than the transformed orientation
|
||||||
|
for (Interval column : columns) {
|
||||||
|
int j = 0;
|
||||||
|
for (Interval row : rows) {
|
||||||
|
regions[nCols - i - 1][nRows - j - 1] =
|
||||||
|
new Rectangle2D.Double(
|
||||||
|
column.start,
|
||||||
|
row.start,
|
||||||
|
column.end - column.start,
|
||||||
|
row.end - row.start);
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return regions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register each character's bounding box, updating boxes field to maintain a list of all
|
||||||
|
* distinct groups of characters.
|
||||||
|
*
|
||||||
|
* <p>Overrides the default functionality of PDFTextStripper. Most of this is taken from
|
||||||
|
* DrawPrintTextLocations.java, with extra steps at end of main loop
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void writeString(String string, List<TextPosition> textPositions) throws IOException {
|
||||||
|
for (TextPosition text : textPositions) {
|
||||||
|
// glyph space -> user space
|
||||||
|
// note: text.getTextMatrix() is *not* the Text Matrix, it's the Text Rendering Matrix
|
||||||
|
AffineTransform at = text.getTextMatrix().createAffineTransform();
|
||||||
|
PDFont font = text.getFont();
|
||||||
|
BoundingBox bbox = font.getBoundingBox();
|
||||||
|
|
||||||
|
// advance width, bbox height (glyph space)
|
||||||
|
float xadvance =
|
||||||
|
font.getWidth(text.getCharacterCodes()[0]); // todo: should iterate all chars
|
||||||
|
Rectangle2D.Float rect =
|
||||||
|
new Rectangle2D.Float(0, bbox.getLowerLeftY(), xadvance, bbox.getHeight());
|
||||||
|
|
||||||
|
if (font instanceof PDType3Font) {
|
||||||
|
// bbox and font matrix are unscaled
|
||||||
|
at.concatenate(font.getFontMatrix().createAffineTransform());
|
||||||
|
} else {
|
||||||
|
// bbox and font matrix are already scaled to 1000
|
||||||
|
at.scale(1 / 1000f, 1 / 1000f);
|
||||||
|
}
|
||||||
|
Shape s = at.createTransformedShape(rect);
|
||||||
|
s = flipAT.createTransformedShape(s);
|
||||||
|
s = rotateAT.createTransformedShape(s);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Merge character's bounding box with boxes field
|
||||||
|
//
|
||||||
|
Rectangle2D bounds = s.getBounds2D();
|
||||||
|
// Pad sides to detect almost touching boxes
|
||||||
|
Rectangle2D hitbox = bounds.getBounds2D();
|
||||||
|
hitbox.add(bounds.getMinX() - dx, bounds.getMinY() - dy);
|
||||||
|
hitbox.add(bounds.getMaxX() + dx, bounds.getMaxY() + dy);
|
||||||
|
|
||||||
|
// Find all overlapping boxes
|
||||||
|
List<Rectangle2D> intersectList = new ArrayList<Rectangle2D>();
|
||||||
|
for (Rectangle2D box : boxes) {
|
||||||
|
if (box.intersects(hitbox)) {
|
||||||
|
intersectList.add(box);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine all touching boxes and update
|
||||||
|
// (NOTE: Potentially this could leave some overlapping boxes un-merged,
|
||||||
|
// but it's sufficient for now and get's fixed up in calculateTableRegions)
|
||||||
|
for (Rectangle2D box : intersectList) {
|
||||||
|
bounds.add(box);
|
||||||
|
boxes.remove(box);
|
||||||
|
}
|
||||||
|
boxes.add(bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method does nothing in this derived class, because beads and regions are incompatible.
|
||||||
|
* Beads are ignored when stripping by area.
|
||||||
|
*
|
||||||
|
* @param aShouldSeparateByBeads The new grouping of beads.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final void setShouldSeparateByBeads(boolean aShouldSeparateByBeads) {}
|
||||||
|
|
||||||
|
/** Adapted from PDFTextStripperByArea {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
protected void processTextPosition(TextPosition text) {
|
||||||
|
if (regionArea != null && !regionArea.contains(text.getX(), text.getY())) {
|
||||||
|
// skip character
|
||||||
|
} else {
|
||||||
|
super.processTextPosition(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,9 +34,7 @@ public class DatabaseWebController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<FileInfo> backupList = databaseBackupHelper.getBackupList();
|
List<FileInfo> backupList = databaseBackupHelper.getBackupList();
|
||||||
model.addAttribute("backupFiles", backupList);
|
model.addAttribute("systemUpdate", backupList);
|
||||||
|
|
||||||
model.addAttribute("databaseVersion", databaseBackupHelper.getH2Version());
|
|
||||||
|
|
||||||
return "database";
|
return "database";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import org.springframework.core.annotation.Order;
|
|||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.core.io.FileSystemResource;
|
import org.springframework.core.io.FileSystemResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.UrlResource;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -30,6 +31,7 @@ import stirling.software.SPDF.model.provider.GithubProvider;
|
|||||||
import stirling.software.SPDF.model.provider.GoogleProvider;
|
import stirling.software.SPDF.model.provider.GoogleProvider;
|
||||||
import stirling.software.SPDF.model.provider.KeycloakProvider;
|
import stirling.software.SPDF.model.provider.KeycloakProvider;
|
||||||
import stirling.software.SPDF.model.provider.UnsupportedProviderException;
|
import stirling.software.SPDF.model.provider.UnsupportedProviderException;
|
||||||
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConfigurationProperties(prefix = "")
|
@ConfigurationProperties(prefix = "")
|
||||||
@@ -134,44 +136,20 @@ public class ApplicationProperties {
|
|||||||
private String privateKey;
|
private String privateKey;
|
||||||
private String spCert;
|
private String spCert;
|
||||||
|
|
||||||
public InputStream getIdpMetadataUri() throws IOException {
|
public Resource getIdpMetadataUri() throws IOException {
|
||||||
if (idpMetadataUri.startsWith("classpath:")) {
|
return GeneralUtils.filePathToResource(idpMetadataUri);
|
||||||
return new ClassPathResource(idpMetadataUri.substring("classpath".length()))
|
|
||||||
.getInputStream();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
URI uri = new URI(idpMetadataUri);
|
|
||||||
URL url = uri.toURL();
|
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
|
||||||
connection.setRequestMethod("GET");
|
|
||||||
return connection.getInputStream();
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
throw new IOException("Invalid URI format: " + idpMetadataUri, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Resource getSpCert() {
|
public Resource getSpCert() {
|
||||||
if (spCert.startsWith("classpath:")) {
|
return GeneralUtils.filePathToResource(spCert);
|
||||||
return new ClassPathResource(spCert.substring("classpath:".length()));
|
|
||||||
} else {
|
|
||||||
return new FileSystemResource(spCert);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Resource getidpCert() {
|
public Resource getidpCert() {
|
||||||
if (idpCert.startsWith("classpath:")) {
|
return GeneralUtils.filePathToResource(idpCert);
|
||||||
return new ClassPathResource(idpCert.substring("classpath:".length()));
|
|
||||||
} else {
|
|
||||||
return new FileSystemResource(idpCert);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Resource getPrivateKey() {
|
public Resource getPrivateKey() {
|
||||||
if (privateKey.startsWith("classpath:")) {
|
return GeneralUtils.filePathToResource(privateKey);
|
||||||
return new ClassPathResource(privateKey.substring("classpath:".length()));
|
|
||||||
} else {
|
|
||||||
return new FileSystemResource(privateKey);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
package stirling.software.SPDF.pdf;
|
|
||||||
|
|
||||||
import org.apache.commons.csv.CSVFormat;
|
|
||||||
|
|
||||||
import technology.tabula.writers.CSVWriter;
|
|
||||||
|
|
||||||
public class FlexibleCSVWriter extends CSVWriter {
|
|
||||||
|
|
||||||
public FlexibleCSVWriter() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public FlexibleCSVWriter(CSVFormat csvFormat) {
|
|
||||||
super(csvFormat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -24,7 +24,7 @@ public class MetricsAggregatorService {
|
|||||||
this.postHogService = postHogService;
|
this.postHogService = postHogService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(fixedRate = 1800000) // Run every 30 minutes
|
@Scheduled(fixedRate = 900000) // Run every 15 minutes
|
||||||
public void aggregateAndSendMetrics() {
|
public void aggregateAndSendMetrics() {
|
||||||
Map<String, Object> metrics = new HashMap<>();
|
Map<String, Object> metrics = new HashMap<>();
|
||||||
Search.in(meterRegistry)
|
Search.in(meterRegistry)
|
||||||
@@ -32,19 +32,11 @@ public class MetricsAggregatorService {
|
|||||||
.counters()
|
.counters()
|
||||||
.forEach(
|
.forEach(
|
||||||
counter -> {
|
counter -> {
|
||||||
String method = counter.getId().getTag("method");
|
String key =
|
||||||
String uri = counter.getId().getTag("uri");
|
String.format(
|
||||||
|
"http_requests_%s_%s",
|
||||||
// Skip if either method or uri is null
|
counter.getId().getTag("method"),
|
||||||
if (method == null || uri == null) {
|
counter.getId().getTag("uri").replace("/", "_"));
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String key = String.format(
|
|
||||||
"http_requests_%s_%s",
|
|
||||||
method,
|
|
||||||
uri.replace("/", "_")
|
|
||||||
);
|
|
||||||
|
|
||||||
double currentCount = counter.count();
|
double currentCount = counter.count();
|
||||||
double lastCount = lastSentMetrics.getOrDefault(key, 0.0);
|
double lastCount = lastSentMetrics.getOrDefault(key, 0.0);
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import java.util.TimeZone;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.posthog.java.PostHog;
|
import com.posthog.java.PostHog;
|
||||||
@@ -27,25 +26,19 @@ import stirling.software.SPDF.model.ApplicationProperties;
|
|||||||
public class PostHogService {
|
public class PostHogService {
|
||||||
private final PostHog postHog;
|
private final PostHog postHog;
|
||||||
private final String uniqueId;
|
private final String uniqueId;
|
||||||
private final String appVersion;
|
|
||||||
private final ApplicationProperties applicationProperties;
|
private final ApplicationProperties applicationProperties;
|
||||||
private final UserServiceInterface userService;
|
private final UserServiceInterface userService;
|
||||||
private final Environment env;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public PostHogService(
|
public PostHogService(
|
||||||
PostHog postHog,
|
PostHog postHog,
|
||||||
@Qualifier("UUID") String uuid,
|
@Qualifier("UUID") String uuid,
|
||||||
@Qualifier("appVersion") String appVersion,
|
|
||||||
ApplicationProperties applicationProperties,
|
ApplicationProperties applicationProperties,
|
||||||
@Autowired(required = false) UserServiceInterface userService,
|
@Autowired(required = false) UserServiceInterface userService) {
|
||||||
Environment env) {
|
|
||||||
this.postHog = postHog;
|
this.postHog = postHog;
|
||||||
this.uniqueId = uuid;
|
this.uniqueId = uuid;
|
||||||
this.appVersion = appVersion;
|
|
||||||
this.applicationProperties = applicationProperties;
|
this.applicationProperties = applicationProperties;
|
||||||
this.userService = userService;
|
this.userService = userService;
|
||||||
this.env = env;
|
|
||||||
captureSystemInfo();
|
captureSystemInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,16 +64,6 @@ public class PostHogService {
|
|||||||
Map<String, Object> metrics = new HashMap<>();
|
Map<String, Object> metrics = new HashMap<>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//Application version
|
|
||||||
metrics.put("app_version", appVersion);
|
|
||||||
String deploymentType = "JAR"; // default
|
|
||||||
if ("true".equalsIgnoreCase(env.getProperty("BROWSER_OPEN"))) {
|
|
||||||
deploymentType = "EXE";
|
|
||||||
} else if (isRunningInDocker()) {
|
|
||||||
deploymentType = "DOCKER";
|
|
||||||
}
|
|
||||||
metrics.put("deployment_type", deploymentType);
|
|
||||||
|
|
||||||
// System info
|
// System info
|
||||||
metrics.put("os_name", System.getProperty("os.name"));
|
metrics.put("os_name", System.getProperty("os.name"));
|
||||||
metrics.put("os_version", System.getProperty("os.version"));
|
metrics.put("os_version", System.getProperty("os.version"));
|
||||||
@@ -149,6 +132,7 @@ public class PostHogService {
|
|||||||
|
|
||||||
// Docker detection and stats
|
// Docker detection and stats
|
||||||
boolean isDocker = isRunningInDocker();
|
boolean isDocker = isRunningInDocker();
|
||||||
|
metrics.put("is_docker", isDocker);
|
||||||
if (isDocker) {
|
if (isDocker) {
|
||||||
metrics.put("docker_metrics", getDockerMetrics());
|
metrics.put("docker_metrics", getDockerMetrics());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ import org.simpleyaml.configuration.implementation.SimpleYamlImplementation;
|
|||||||
import org.simpleyaml.configuration.implementation.snakeyaml.lib.DumperOptions;
|
import org.simpleyaml.configuration.implementation.snakeyaml.lib.DumperOptions;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.core.io.FileSystemResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.UrlResource;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import com.fathzer.soft.javaluator.DoubleEvaluator;
|
import com.fathzer.soft.javaluator.DoubleEvaluator;
|
||||||
@@ -349,4 +353,23 @@ public class GeneralUtils {
|
|||||||
return "GenericID";
|
return "GenericID";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Resource filePathToResource(String resourceFile) {
|
||||||
|
if (resourceFile == null) {
|
||||||
|
throw new IllegalStateException("file is not configured");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resourceFile.startsWith("classpath:")) {
|
||||||
|
return new ClassPathResource(resourceFile.substring("classpath:".length()));
|
||||||
|
} else if (resourceFile.startsWith("http://") || resourceFile.startsWith("https://")) {
|
||||||
|
try {
|
||||||
|
return new UrlResource(resourceFile);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to create URL resource: " + resourceFile, e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new FileSystemResource(resourceFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ spring.mvc.async.request-timeout=${SYSTEM_CONNECTIONTIMEOUTMILLISECONDS:1200000}
|
|||||||
#spring.thymeleaf.prefix=file:/customFiles/templates/,classpath:/templates/
|
#spring.thymeleaf.prefix=file:/customFiles/templates/,classpath:/templates/
|
||||||
#spring.thymeleaf.cache=false
|
#spring.thymeleaf.cache=false
|
||||||
|
|
||||||
spring.datasource.url=jdbc:h2:file:./configs/stirling-pdf-DB-2.3.232;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
|
spring.datasource.url=jdbc:h2:file:./configs/stirling-pdf-DB;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
|
||||||
spring.datasource.driver-class-name=org.h2.Driver
|
spring.datasource.driver-class-name=org.h2.Driver
|
||||||
spring.datasource.username=sa
|
spring.datasource.username=sa
|
||||||
spring.datasource.password=
|
spring.datasource.password=
|
||||||
|
|||||||
@@ -81,11 +81,10 @@ page=صفحة
|
|||||||
pages=صفحات
|
pages=صفحات
|
||||||
loading=جارٍ التحميل...
|
loading=جارٍ التحميل...
|
||||||
addToDoc=إضافة إلى المستند
|
addToDoc=إضافة إلى المستند
|
||||||
reset=إعداة ضبط
|
|
||||||
|
|
||||||
legal.privacy=سياسة الخصوصية
|
legal.privacy=سياسة الخصوصية
|
||||||
legal.terms=شروط الاستخدام
|
legal.terms=شروط الاستخدام
|
||||||
legal.accessibility=إمكانية الوصول
|
legal.accessibility=Accessibility
|
||||||
legal.cookie=سياسة ملفات تعريف الارتباط
|
legal.cookie=سياسة ملفات تعريف الارتباط
|
||||||
legal.impressum=بيان الهوية
|
legal.impressum=بيان الهوية
|
||||||
|
|
||||||
@@ -119,8 +118,8 @@ pipelineOptions.validateButton=تحقق
|
|||||||
########################
|
########################
|
||||||
enterpriseEdition.button=ترقية إلى محترف
|
enterpriseEdition.button=ترقية إلى محترف
|
||||||
enterpriseEdition.warning=هذه الخاصية متوفرة فقط للمستخدمين المحترفين.
|
enterpriseEdition.warning=هذه الخاصية متوفرة فقط للمستخدمين المحترفين.
|
||||||
enterpriseEdition.yamlAdvert=يدعم Stirling PDF Pro ملفات الإعدادات YAML وميزات SSO أخرى
|
enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features.
|
||||||
enterpriseEdition.ssoAdvert=هل تبحث عن المزيد من ميزات إدارة المستخدمين؟ اطلع على Stirling PDF Pro
|
enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro
|
||||||
|
|
||||||
|
|
||||||
#################
|
#################
|
||||||
@@ -142,7 +141,7 @@ navbar.language=اللغات
|
|||||||
navbar.settings=إعدادات
|
navbar.settings=إعدادات
|
||||||
navbar.allTools=أدوات
|
navbar.allTools=أدوات
|
||||||
navbar.multiTool=أدوات متعددة
|
navbar.multiTool=أدوات متعددة
|
||||||
navbar.search=البحث
|
navbar.search=Search
|
||||||
navbar.sections.organize=تنظيم
|
navbar.sections.organize=تنظيم
|
||||||
navbar.sections.convertTo=تحويل الى PDF
|
navbar.sections.convertTo=تحويل الى PDF
|
||||||
navbar.sections.convertFrom=تحويل من PDF
|
navbar.sections.convertFrom=تحويل من PDF
|
||||||
@@ -247,8 +246,8 @@ database.fileNotFound=لم يتم العثور على الملف
|
|||||||
database.fileNullOrEmpty=يجب ألا يكون الملف فارغًا أو خاليًا
|
database.fileNullOrEmpty=يجب ألا يكون الملف فارغًا أو خاليًا
|
||||||
database.failedImportFile=فشل استيراد الملف
|
database.failedImportFile=فشل استيراد الملف
|
||||||
|
|
||||||
session.expired=لقد انتهت جلستك. يرجى تحديث الصفحة والمحاولة مرة أخرى
|
session.expired=Your session has expired. Please refresh the page and try again.
|
||||||
session.refreshPage=تحديث الصفحة
|
session.refreshPage=Refresh Page
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# HOME-PAGE #
|
# HOME-PAGE #
|
||||||
@@ -513,15 +512,15 @@ home.splitPdfByChapters.desc=قسم مستند PDF إلى ملفات متعدد
|
|||||||
splitPdfByChapters.tags=تجزئة، فصول، علامات تبويب، تنظيم
|
splitPdfByChapters.tags=تجزئة، فصول، علامات تبويب، تنظيم
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=إستبدال-عكس اللون
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=استبدال-عكس لون PDF
|
replace-color.header=استبدال-إلغاء مirro لون PDF
|
||||||
home.replaceColorPdf.title=إستبدال و عكس الألوان
|
home.replaceColorPdf.title=Replace and Invert Color
|
||||||
home.replaceColorPdf.desc=استبدال الألوان للنصوص والخلفيات في المستندات PDF وإلغاء تعكير اللون الكامل للمستند لتقليل حجم الملف
|
home.replaceColorPdf.desc=استبدال الألوان للنصوص والخلفيات في المستندات PDF وإلغاء تعكير اللون الكامل للمستند لتقليل حجم الملف
|
||||||
replaceColorPdf.tags=استبدال اللون، عمليات الصفحة، الخلفية، جانب الخادم
|
replaceColorPdf.tags=استبدال اللون، عمليات الصفحة، الخلفية، جانب الخادم
|
||||||
replace-color.selectText.1=خيارات استبدال أو عكس الألوان
|
replace-color.selectText.1=خيارات استبدال-إلغاء مirro لون
|
||||||
replace-color.selectText.2=افتراضي(ألوان التباين العالي الافتراضية)
|
replace-color.selectText.2=Default(Default high contrast colors)
|
||||||
replace-color.selectText.3=خصيصة (ألوان شخصية)
|
replace-color.selectText.3=خصيصة (ألوان شخصية)
|
||||||
replace-color.selectText.4=عكس كامل(عكس جميع الألوان)
|
replace-color.selectText.4=Full-Invert(Invert all colors)
|
||||||
replace-color.selectText.5=خيارات ألوان التباين العالي
|
replace-color.selectText.5=خيارات ألوان التباين العالي
|
||||||
replace-color.selectText.6=نص أبيض على خلفية سوداء
|
replace-color.selectText.6=نص أبيض على خلفية سوداء
|
||||||
replace-color.selectText.7=نص أسود على خلفية بيضاء
|
replace-color.selectText.7=نص أسود على خلفية بيضاء
|
||||||
@@ -818,12 +817,7 @@ sign.save=حفظ توقيع
|
|||||||
sign.personalSigs=توقيعات شخصية
|
sign.personalSigs=توقيعات شخصية
|
||||||
sign.sharedSigs=توقيعات مشتركة
|
sign.sharedSigs=توقيعات مشتركة
|
||||||
sign.noSavedSigs=لم يتم العثور على توقيعات محفوظة
|
sign.noSavedSigs=لم يتم العثور على توقيعات محفوظة
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=إصلاح
|
repair.title=إصلاح
|
||||||
@@ -940,27 +934,17 @@ pdfOrganiser.placeholder=(مثال: 1,3,2 أو 4-8,2,10-12 أو 2n-1)
|
|||||||
multiTool.title=أداة متعددة PDF
|
multiTool.title=أداة متعددة PDF
|
||||||
multiTool.header=أداة متعددة PDF
|
multiTool.header=أداة متعددة PDF
|
||||||
multiTool.uploadPrompts=اسم الملف
|
multiTool.uploadPrompts=اسم الملف
|
||||||
multiTool.selectAll=تحديد الكل
|
multiTool.selectAll=Select All
|
||||||
multiTool.deselectAll=إلغاء تحديد الكل
|
multiTool.deselectAll=Deselect All
|
||||||
multiTool.selectPages=تحديد الصفحة
|
multiTool.selectPages=Page Select
|
||||||
multiTool.selectedPages=الصفحات المحددة
|
multiTool.selectedPages=Selected Pages
|
||||||
multiTool.page=صفحة
|
multiTool.page=Page
|
||||||
multiTool.deleteSelected=حذف المحدد
|
multiTool.deleteSelected=Delete Selected
|
||||||
multiTool.downloadAll=تصدير
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=تصدير المحدد
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=إدراج فاصل صفحات
|
|
||||||
multiTool.addFile=إضافة ملف
|
|
||||||
multiTool.rotateLeft=تدوير إلى اليسار
|
|
||||||
multiTool.rotateRight=تدوير إلى اليمين
|
|
||||||
multiTool.split=تقسيم
|
|
||||||
multiTool.moveLeft=تحريك إلى اليسار
|
|
||||||
multiTool.moveRight=تحريك إلى اليمين
|
|
||||||
multiTool.delete=حذف
|
|
||||||
multiTool.dragDropMessage=الصفحات المحددة
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=هذه الميزة متوفرة في <a href="{0}">صفحة الأدوات المتعددة</a> لدينا. اطلع عليها للحصول على واجهة مستخدم محسّنة لكل صفحة وميزات إضافية!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
#view pdf
|
#view pdf
|
||||||
viewPdf.title=عرض PDF
|
viewPdf.title=عرض PDF
|
||||||
@@ -1254,9 +1238,9 @@ splitByChapters.title=تجزئة المستند حسب الفصول
|
|||||||
splitByChapters.header=تجزئة المستند حسب الفصول
|
splitByChapters.header=تجزئة المستند حسب الفصول
|
||||||
splitByChapters.bookmarkLevel=مستوى العلامات التذكارية
|
splitByChapters.bookmarkLevel=مستوى العلامات التذكارية
|
||||||
splitByChapters.includeMetadata=شامل البيانات المرفقة
|
splitByChapters.includeMetadata=شامل البيانات المرفقة
|
||||||
splitByChapters.allowDuplicates=السماح بالتكرار
|
splitByChapters.allowDuplicates=Allow Duplicates
|
||||||
splitByChapters.desc.1=هذه الأداة تقوم بتقسيم ملف PDF إلى عدة ملفات PDF استناداً إلى بنية فصوله
|
splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure.
|
||||||
splitByChapters.desc.2=مستوى الإشارة المرجعية: اختر مستوى الإشارات المرجعية التي تريد استخدامها للتقسيم (0 للمستوى الأعلى، 1 للمستوى الثاني، وما إلى ذلك)
|
splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.).
|
||||||
splitByChapters.desc.3=تمثيل البيانات الأصلية: إذا تم اختيارها، سترمز البيانات المرجعية الأصلية إلى كل PDF مجزأ.
|
splitByChapters.desc.3=تمثيل البيانات الأصلية: إذا تم اختيارها، سترمز البيانات المرجعية الأصلية إلى كل PDF مجزأ.
|
||||||
splitByChapters.desc.4=سماح بالتكرار: إذا تم اختياره، يسمح بوجود معاينات متعددة في الصفحة نفسها لخلق ملفات PDF منفصلة.
|
splitByChapters.desc.4=سماح بالتكرار: إذا تم اختياره، يسمح بوجود معاينات متعددة في الصفحة نفسها لخلق ملفات PDF منفصلة.
|
||||||
splitByChapters.submit=تقطيع ملف PDF
|
splitByChapters.submit=تقطيع ملف PDF
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -81,7 +81,6 @@ page=Страница
|
|||||||
pages=Страници
|
pages=Страници
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Политика за поверителност
|
legal.privacy=Политика за поверителност
|
||||||
legal.terms=Правила и условия
|
legal.terms=Правила и условия
|
||||||
@@ -818,12 +817,7 @@ sign.save=Save Signature
|
|||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=Personal Signatures
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=Shared Signatures
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=No saved signatures found
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Поправи
|
repair.title=Поправи
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Pàgina
|
|||||||
pages=Pàgines
|
pages=Pàgines
|
||||||
loading=Carregant...
|
loading=Carregant...
|
||||||
addToDoc=Afegeix al document
|
addToDoc=Afegeix al document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Política de Privacitat
|
legal.privacy=Política de Privacitat
|
||||||
legal.terms=Termes i condicions
|
legal.terms=Termes i condicions
|
||||||
@@ -818,12 +817,7 @@ sign.save=Desa Signatura
|
|||||||
sign.personalSigs=Signatures Personals
|
sign.personalSigs=Signatures Personals
|
||||||
sign.sharedSigs=Signatures Compartides
|
sign.sharedSigs=Signatures Compartides
|
||||||
sign.noSavedSigs=No s'han trobat signatures desades
|
sign.noSavedSigs=No s'han trobat signatures desades
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparar
|
repair.title=Reparar
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Strana
|
|||||||
pages=Strany
|
pages=Strany
|
||||||
loading=Načítání...
|
loading=Načítání...
|
||||||
addToDoc=Přidat do dokumentu
|
addToDoc=Přidat do dokumentu
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Politika soukromí
|
legal.privacy=Politika soukromí
|
||||||
legal.terms=Podmínky použití
|
legal.terms=Podmínky použití
|
||||||
@@ -818,12 +817,7 @@ sign.save=Uložit podpis
|
|||||||
sign.personalSigs=Osobní podpisy
|
sign.personalSigs=Osobní podpisy
|
||||||
sign.sharedSigs=Sdílené podpisy
|
sign.sharedSigs=Sdílené podpisy
|
||||||
sign.noSavedSigs=Nenašly se žádné uložené podpisy
|
sign.noSavedSigs=Nenašly se žádné uložené podpisy
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Opravit
|
repair.title=Opravit
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Sidenummer
|
|||||||
pages=Sideantal
|
pages=Sideantal
|
||||||
loading=Laster...
|
loading=Laster...
|
||||||
addToDoc=Tilføj til Dokument
|
addToDoc=Tilføj til Dokument
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Vilkår og betingelser
|
legal.terms=Vilkår og betingelser
|
||||||
@@ -818,12 +817,7 @@ sign.save=Gem Signatur
|
|||||||
sign.personalSigs=Personlige Signaturer
|
sign.personalSigs=Personlige Signaturer
|
||||||
sign.sharedSigs=Delte Signaturer
|
sign.sharedSigs=Delte Signaturer
|
||||||
sign.noSavedSigs=Ingen Gemte Signaturer Fundet
|
sign.noSavedSigs=Ingen Gemte Signaturer Fundet
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparér
|
repair.title=Reparér
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Seite
|
|||||||
pages=Seiten
|
pages=Seiten
|
||||||
loading=Laden...
|
loading=Laden...
|
||||||
addToDoc=In Dokument hinzufügen
|
addToDoc=In Dokument hinzufügen
|
||||||
reset=Zurücksetzen
|
|
||||||
|
|
||||||
legal.privacy=Datenschutz
|
legal.privacy=Datenschutz
|
||||||
legal.terms=AGB
|
legal.terms=AGB
|
||||||
@@ -818,12 +817,7 @@ sign.save=Signature speichern
|
|||||||
sign.personalSigs=Persönliche Signaturen
|
sign.personalSigs=Persönliche Signaturen
|
||||||
sign.sharedSigs=Geteilte Signaturen
|
sign.sharedSigs=Geteilte Signaturen
|
||||||
sign.noSavedSigs=Es wurden keine gespeicherten Signaturen gefunden
|
sign.noSavedSigs=Es wurden keine gespeicherten Signaturen gefunden
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparieren
|
repair.title=Reparieren
|
||||||
@@ -949,18 +943,8 @@ multiTool.deleteSelected=Auswahl löschen
|
|||||||
multiTool.downloadAll=Downloaden
|
multiTool.downloadAll=Downloaden
|
||||||
multiTool.downloadSelected=Auswahl downloaden
|
multiTool.downloadSelected=Auswahl downloaden
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=Diese Funktion ist auch auf unserer <a href="{0}">PDF-Multitool-Seite</a> verfügbar. Probieren Sie sie aus, denn sie bietet eine verbesserte Benutzeroberfläche und zusätzliche Funktionen!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
#view pdf
|
#view pdf
|
||||||
viewPdf.title=PDF anzeigen
|
viewPdf.title=PDF anzeigen
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Σελίδα
|
|||||||
pages=Σελίδες
|
pages=Σελίδες
|
||||||
loading=Φόρτωση...
|
loading=Φόρτωση...
|
||||||
addToDoc=Πρόσθεση στο Εκπομπώματο
|
addToDoc=Πρόσθεση στο Εκπομπώματο
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Πολιτική Προνομίους
|
legal.privacy=Πολιτική Προνομίους
|
||||||
legal.terms=Φράσεις Υποχρεωτικότητας
|
legal.terms=Φράσεις Υποχρεωτικότητας
|
||||||
@@ -818,12 +817,7 @@ sign.save=Αποθήκευση Αλιάσης
|
|||||||
sign.personalSigs=Προσωπικές Αλιάσεις
|
sign.personalSigs=Προσωπικές Αλιάσεις
|
||||||
sign.sharedSigs=Μεταδότες Αλιάσεις
|
sign.sharedSigs=Μεταδότες Αλιάσεις
|
||||||
sign.noSavedSigs=Δεν βρέθηκαν αποθηκευμένες αλιάσεις
|
sign.noSavedSigs=Δεν βρέθηκαν αποθηκευμένες αλιάσεις
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Επιδιόρθωση
|
repair.title=Επιδιόρθωση
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -818,12 +818,7 @@ sign.save=Save Signature
|
|||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=Personal Signatures
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=Shared Signatures
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=No saved signatures found
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Repair
|
repair.title=Repair
|
||||||
@@ -949,16 +944,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
@@ -818,12 +817,7 @@ sign.save=Save Signature
|
|||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=Personal Signatures
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=Shared Signatures
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=No saved signatures found
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Repair
|
repair.title=Repair
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Página
|
|||||||
pages=Páginas
|
pages=Páginas
|
||||||
loading=Cargando...
|
loading=Cargando...
|
||||||
addToDoc=Agregar al Documento
|
addToDoc=Agregar al Documento
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Política de Privacidad
|
legal.privacy=Política de Privacidad
|
||||||
legal.terms=Términos y Condiciones
|
legal.terms=Términos y Condiciones
|
||||||
@@ -818,12 +817,7 @@ sign.save=Guardar Firma
|
|||||||
sign.personalSigs=Firmas Personales
|
sign.personalSigs=Firmas Personales
|
||||||
sign.sharedSigs=Firmas compartidas
|
sign.sharedSigs=Firmas compartidas
|
||||||
sign.noSavedSigs=No se encontraron firmas guardadas
|
sign.noSavedSigs=No se encontraron firmas guardadas
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparar
|
repair.title=Reparar
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
@@ -818,12 +817,7 @@ sign.save=Save Signature
|
|||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=Personal Signatures
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=Shared Signatures
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=No saved signatures found
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Konpondu
|
repair.title=Konpondu
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ userNotFoundMessage=Utilisateur non trouvé.
|
|||||||
incorrectPasswordMessage=Le mot de passe actuel est incorrect.
|
incorrectPasswordMessage=Le mot de passe actuel est incorrect.
|
||||||
usernameExistsMessage=Le nouveau nom d'utilisateur existe déjà.
|
usernameExistsMessage=Le nouveau nom d'utilisateur existe déjà.
|
||||||
invalidUsernameMessage=Nom d'utilisateur invalide, le nom d'utilisateur ne peut contenir que des lettres, des chiffres et les caractères spéciaux suivants @._+- ou doit être une adresse e-mail valide.
|
invalidUsernameMessage=Nom d'utilisateur invalide, le nom d'utilisateur ne peut contenir que des lettres, des chiffres et les caractères spéciaux suivants @._+- ou doit être une adresse e-mail valide.
|
||||||
invalidPasswordMessage=Le mot de passe ne peut pas être vide et ne doit pas contenir d'espaces au début ou à la fin.
|
invalidPasswordMessage=Le mot de passe ne peut pas être vide et ne doit pas contenir d'espaces au début ou en fin.
|
||||||
confirmPasswordErrorMessage=Le nouveau mot de passe et sa confirmation doivent être identiques.
|
confirmPasswordErrorMessage=Nouveau Mot de passe et Confirmer le Nouveau Mot de passe doivent correspondre.
|
||||||
deleteCurrentUserMessage=Impossible de supprimer l'utilisateur actuellement connecté.
|
deleteCurrentUserMessage=Impossible de supprimer l'utilisateur actuellement connecté.
|
||||||
deleteUsernameExistsMessage=Le nom d'utilisateur n'existe pas et ne peut pas être supprimé.
|
deleteUsernameExistsMessage=Le nom d'utilisateur n'existe pas et ne peut pas être supprimé.
|
||||||
downgradeCurrentUserMessage=Impossible de rétrograder le rôle de l'utilisateur actuel.
|
downgradeCurrentUserMessage=Impossible de rétrograder le rôle de l'utilisateur actuel.
|
||||||
@@ -81,7 +81,6 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Chargement...
|
loading=Chargement...
|
||||||
addToDoc=Ajouter au Document
|
addToDoc=Ajouter au Document
|
||||||
reset=Réinitialiser
|
|
||||||
|
|
||||||
legal.privacy=Politique de Confidentialité
|
legal.privacy=Politique de Confidentialité
|
||||||
legal.terms=Conditions Générales
|
legal.terms=Conditions Générales
|
||||||
@@ -142,7 +141,7 @@ navbar.language=Langues
|
|||||||
navbar.settings=Paramètres
|
navbar.settings=Paramètres
|
||||||
navbar.allTools=Outils
|
navbar.allTools=Outils
|
||||||
navbar.multiTool=Outils Multiples
|
navbar.multiTool=Outils Multiples
|
||||||
navbar.search=Rechercher
|
navbar.search=Search
|
||||||
navbar.sections.organize=Organisation
|
navbar.sections.organize=Organisation
|
||||||
navbar.sections.convertTo=Convertir en PDF
|
navbar.sections.convertTo=Convertir en PDF
|
||||||
navbar.sections.convertFrom=Convertir depuis PDF
|
navbar.sections.convertFrom=Convertir depuis PDF
|
||||||
@@ -813,17 +812,12 @@ sign.draw=Dessiner une signature
|
|||||||
sign.text=Saisir de texte
|
sign.text=Saisir de texte
|
||||||
sign.clear=Effacer
|
sign.clear=Effacer
|
||||||
sign.add=Ajouter
|
sign.add=Ajouter
|
||||||
sign.saved=Sceaux enregistrées
|
sign.saved=Saved Signatures
|
||||||
sign.save=Enregistrer le sceau
|
sign.save=Enregistrer le sceau
|
||||||
sign.personalSigs=Sceaux personnels
|
sign.personalSigs=Sceaux personnels
|
||||||
sign.sharedSigs=Sceaux partagés
|
sign.sharedSigs=Sceaux partagés
|
||||||
sign.noSavedSigs=Aucun sceau enregistré trouvé
|
sign.noSavedSigs=Aucun sceau enregistré trouvé
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Réparer
|
repair.title=Réparer
|
||||||
@@ -940,27 +934,17 @@ pdfOrganiser.placeholder=(par exemple 1,3,2 ou 4-8,2,10-12 ou 2n-1)
|
|||||||
multiTool.title=Outil multifonction PDF
|
multiTool.title=Outil multifonction PDF
|
||||||
multiTool.header=Outil multifonction PDF
|
multiTool.header=Outil multifonction PDF
|
||||||
multiTool.uploadPrompts=Nom du fichier
|
multiTool.uploadPrompts=Nom du fichier
|
||||||
multiTool.selectAll=Tout sélectionner
|
multiTool.selectAll=Select All
|
||||||
multiTool.deselectAll=Tout déselectionner
|
multiTool.deselectAll=Deselect All
|
||||||
multiTool.selectPages=Sélection des pages
|
multiTool.selectPages=Page Select
|
||||||
multiTool.selectedPages=Pages sélectionnées
|
multiTool.selectedPages=Selected Pages
|
||||||
multiTool.page=Page
|
multiTool.page=Page
|
||||||
multiTool.deleteSelected=Supprimer la sélection
|
multiTool.deleteSelected=Delete Selected
|
||||||
multiTool.downloadAll=Exporter
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Exporter la sélection
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insérer un saut de page
|
|
||||||
multiTool.addFile=Ajouter un fichier
|
|
||||||
multiTool.rotateLeft=Rotation vers la gauche
|
|
||||||
multiTool.rotateRight=Rotation vers la droite
|
|
||||||
multiTool.split=Diviser
|
|
||||||
multiTool.moveLeft=Déplacer vers la gauche
|
|
||||||
multiTool.moveRight=Déplacer vers la droite
|
|
||||||
multiTool.delete=Supprimer
|
|
||||||
multiTool.dragDropMessage=Page(s) sélectionnées
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=Cette fonctionnalité est aussi disponible dans la <a href="{0}">page de l'outil multifonction</a>. Allez-y pour une interface page par page améliorée et des fonctionnalités additionnelles !
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
#view pdf
|
#view pdf
|
||||||
viewPdf.title=Visualiser un PDF
|
viewPdf.title=Visualiser un PDF
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
@@ -818,12 +817,7 @@ sign.save=Save Signature
|
|||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=Personal Signatures
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=Shared Signatures
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=No saved signatures found
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Deisiúchán
|
repair.title=Deisiúchán
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=पृष्ठ
|
|||||||
pages=पृष्ठों
|
pages=पृष्ठों
|
||||||
loading=डालिंग...
|
loading=डालिंग...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=गुप्तता सूचना
|
legal.privacy=गुप्तता सूचना
|
||||||
legal.terms=शर्तें और प्रवाह
|
legal.terms=शर्तें और प्रवाह
|
||||||
@@ -818,12 +817,7 @@ sign.save=प्रदर्शन बचाएं
|
|||||||
sign.personalSigs=मौजूदा प्रदर्शन
|
sign.personalSigs=मौजूदा प्रदर्शन
|
||||||
sign.sharedSigs=साझेदार प्रदर्शन
|
sign.sharedSigs=साझेदार प्रदर्शन
|
||||||
sign.noSavedSigs=कोई भी संवर्तित प्रदर्शन नहीं मौजूद है
|
sign.noSavedSigs=कोई भी संवर्तित प्रदर्शन नहीं मौजूद है
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=मरम्मत
|
repair.title=मरम्मत
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Stranica
|
|||||||
pages=Stranice
|
pages=Stranice
|
||||||
loading=Učitavanje...
|
loading=Učitavanje...
|
||||||
addToDoc=Dodaj u dokument
|
addToDoc=Dodaj u dokument
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Politika privatnosti
|
legal.privacy=Politika privatnosti
|
||||||
legal.terms=Uspe sodržine
|
legal.terms=Uspe sodržine
|
||||||
@@ -818,12 +817,7 @@ sign.save=Sačuvaj potpisnu oznaku
|
|||||||
sign.personalSigs=Osobni potpisi
|
sign.personalSigs=Osobni potpisi
|
||||||
sign.sharedSigs=Dijeljeni potpisi
|
sign.sharedSigs=Dijeljeni potpisi
|
||||||
sign.noSavedSigs=Nema sacuvanih potpisa pronađenih
|
sign.noSavedSigs=Nema sacuvanih potpisa pronađenih
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Popravi
|
repair.title=Popravi
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Oldal
|
|||||||
pages=Oldalak
|
pages=Oldalak
|
||||||
loading=Betöltés...
|
loading=Betöltés...
|
||||||
addToDoc=Hozzáadás dokumentumba
|
addToDoc=Hozzáadás dokumentumba
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Adatvédelmi nyilatkozat
|
legal.privacy=Adatvédelmi nyilatkozat
|
||||||
legal.terms=Feltételek és feltételek
|
legal.terms=Feltételek és feltételek
|
||||||
@@ -818,12 +817,7 @@ sign.save=Aláíráshoz mentés
|
|||||||
sign.personalSigs=Személyi aláíráshoz
|
sign.personalSigs=Személyi aláíráshoz
|
||||||
sign.sharedSigs=Megosztott aláíráshoz
|
sign.sharedSigs=Megosztott aláíráshoz
|
||||||
sign.noSavedSigs=Nincsenek mentett aláírások találat
|
sign.noSavedSigs=Nincsenek mentett aláírások találat
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Javítás
|
repair.title=Javítás
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Halaman
|
|||||||
pages=Halaman-halaman
|
pages=Halaman-halaman
|
||||||
loading=Mengambil data...
|
loading=Mengambil data...
|
||||||
addToDoc=Tambahkan ke Dokumen
|
addToDoc=Tambahkan ke Dokumen
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Kebijakan Privasi
|
legal.privacy=Kebijakan Privasi
|
||||||
legal.terms=Syarat dan Ketentuan
|
legal.terms=Syarat dan Ketentuan
|
||||||
@@ -818,12 +817,7 @@ sign.save=Simpan Tanda Tangan
|
|||||||
sign.personalSigs=Tanda Tangan Pribadi
|
sign.personalSigs=Tanda Tangan Pribadi
|
||||||
sign.sharedSigs=Tanda Tangan Berbagi
|
sign.sharedSigs=Tanda Tangan Berbagi
|
||||||
sign.noSavedSigs=Tidak ditemukan tanda tangan yang disimpan
|
sign.noSavedSigs=Tidak ditemukan tanda tangan yang disimpan
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Perbaiki
|
repair.title=Perbaiki
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Pagina
|
|||||||
pages=Pagine
|
pages=Pagine
|
||||||
loading=Caricamento...
|
loading=Caricamento...
|
||||||
addToDoc=Aggiungi al documento
|
addToDoc=Aggiungi al documento
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Informativa sulla privacy
|
legal.privacy=Informativa sulla privacy
|
||||||
legal.terms=Termini e Condizioni
|
legal.terms=Termini e Condizioni
|
||||||
@@ -142,7 +141,7 @@ navbar.language=Lingue
|
|||||||
navbar.settings=Impostazioni
|
navbar.settings=Impostazioni
|
||||||
navbar.allTools=Strumenti
|
navbar.allTools=Strumenti
|
||||||
navbar.multiTool=Strumenti multipli
|
navbar.multiTool=Strumenti multipli
|
||||||
navbar.search=Cerca
|
navbar.search=Search
|
||||||
navbar.sections.organize=Organizza
|
navbar.sections.organize=Organizza
|
||||||
navbar.sections.convertTo=Converti in PDF
|
navbar.sections.convertTo=Converti in PDF
|
||||||
navbar.sections.convertFrom=Converti da PDF
|
navbar.sections.convertFrom=Converti da PDF
|
||||||
@@ -818,12 +817,7 @@ sign.save=Firma salvata
|
|||||||
sign.personalSigs=Firme personali
|
sign.personalSigs=Firme personali
|
||||||
sign.sharedSigs=Firme condivise
|
sign.sharedSigs=Firme condivise
|
||||||
sign.noSavedSigs=Nessuna firma salvata trovata
|
sign.noSavedSigs=Nessuna firma salvata trovata
|
||||||
sign.addToAll=Aggiungi a tutte le pagine
|
|
||||||
sign.delete=Elimina
|
|
||||||
sign.first=Prima pagina
|
|
||||||
sign.last=Ultima pagina
|
|
||||||
sign.next=Prossima pagina
|
|
||||||
sign.previous=Pagina precedente
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Ripara
|
repair.title=Ripara
|
||||||
@@ -949,18 +943,8 @@ multiTool.deleteSelected=Elimina selezionata
|
|||||||
multiTool.downloadAll=Esporta
|
multiTool.downloadAll=Esporta
|
||||||
multiTool.downloadSelected=Esporta selezionata
|
multiTool.downloadSelected=Esporta selezionata
|
||||||
|
|
||||||
multiTool.insertPageBreak=Inserisci interruzione di pagina
|
|
||||||
multiTool.addFile=Aggiungi file
|
|
||||||
multiTool.rotateLeft=Ruota a sinistra
|
|
||||||
multiTool.rotateRight=Ruota a destra
|
|
||||||
multiTool.split=Dividi
|
|
||||||
multiTool.moveLeft=Sposta a sinistra
|
|
||||||
multiTool.moveRight=Sposta a destra
|
|
||||||
multiTool.delete=Elimina
|
|
||||||
multiTool.dragDropMessage=Pagina(e) selezionata(e)
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=Questa funzione è disponibile anche nella nostra <a href="{0}">pagina multi-strumento</a>. Scoprila per un'interfaccia utente pagina per pagina migliorata e funzionalità aggiuntive!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
#view pdf
|
#view pdf
|
||||||
viewPdf.title=Visualizza PDF
|
viewPdf.title=Visualizza PDF
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=プライバシーポリシー
|
legal.privacy=プライバシーポリシー
|
||||||
legal.terms=利用規約
|
legal.terms=利用規約
|
||||||
@@ -818,12 +817,7 @@ sign.save=Save Signature
|
|||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=Personal Signatures
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=Shared Signatures
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=No saved signatures found
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=修復
|
repair.title=修復
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=페이지
|
|||||||
pages=페이지
|
pages=페이지
|
||||||
loading=로딩 중...
|
loading=로딩 중...
|
||||||
addToDoc=문서에 추가
|
addToDoc=문서에 추가
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=개인 정보 정책
|
legal.privacy=개인 정보 정책
|
||||||
legal.terms=이용 약관
|
legal.terms=이용 약관
|
||||||
@@ -818,12 +817,7 @@ sign.save=서명 저장
|
|||||||
sign.personalSigs=개인용 서명
|
sign.personalSigs=개인용 서명
|
||||||
sign.sharedSigs=공유용 서명
|
sign.sharedSigs=공유용 서명
|
||||||
sign.noSavedSigs=저장된 서명이 없습니다
|
sign.noSavedSigs=저장된 서명이 없습니다
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=복구
|
repair.title=복구
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Pagina
|
|||||||
pages=Pagen
|
pages=Pagen
|
||||||
loading=Laden...
|
loading=Laden...
|
||||||
addToDoc=Toevoegen aan document
|
addToDoc=Toevoegen aan document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Privacybeleid
|
legal.privacy=Privacybeleid
|
||||||
legal.terms=Voorwaarden van gebruik
|
legal.terms=Voorwaarden van gebruik
|
||||||
@@ -818,12 +817,7 @@ sign.save=Opslaan Signatuur
|
|||||||
sign.personalSigs=Persoonlijke Signatuuren
|
sign.personalSigs=Persoonlijke Signatuuren
|
||||||
sign.sharedSigs=Gedeelde Signatuuren
|
sign.sharedSigs=Gedeelde Signatuuren
|
||||||
sign.noSavedSigs=Geen opgeslagen signatuuren gevonden
|
sign.noSavedSigs=Geen opgeslagen signatuuren gevonden
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Repareren
|
repair.title=Repareren
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
@@ -818,12 +817,7 @@ sign.save=Save Signature
|
|||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=Personal Signatures
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=Shared Signatures
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=No saved signatures found
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparer
|
repair.title=Reparer
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Strona
|
|||||||
pages=Strony
|
pages=Strony
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Polityka Prywatności
|
legal.privacy=Polityka Prywatności
|
||||||
legal.terms=Zasady i Postanowienia
|
legal.terms=Zasady i Postanowienia
|
||||||
@@ -818,12 +817,7 @@ sign.save=Save Signature
|
|||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=Personal Signatures
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=Shared Signatures
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=No saved signatures found
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Napraw
|
repair.title=Napraw
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Página
|
|||||||
pages=Páginas
|
pages=Páginas
|
||||||
loading=Carregando...
|
loading=Carregando...
|
||||||
addToDoc=Adicionar ao Documento
|
addToDoc=Adicionar ao Documento
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Política de Privacidade
|
legal.privacy=Política de Privacidade
|
||||||
legal.terms=Termos e Condições
|
legal.terms=Termos e Condições
|
||||||
@@ -818,12 +817,7 @@ sign.save=Salvar Assinatura
|
|||||||
sign.personalSigs=Assinaturas Pessoais
|
sign.personalSigs=Assinaturas Pessoais
|
||||||
sign.sharedSigs=Assinaturas Compartilhadas
|
sign.sharedSigs=Assinaturas Compartilhadas
|
||||||
sign.noSavedSigs=Nenhuma assinatura salva encontrada
|
sign.noSavedSigs=Nenhuma assinatura salva encontrada
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparar
|
repair.title=Reparar
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Página
|
|||||||
pages=Páginas
|
pages=Páginas
|
||||||
loading=A carregar...
|
loading=A carregar...
|
||||||
addToDoc=Adicionar ao Documento
|
addToDoc=Adicionar ao Documento
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Política de Privacidade
|
legal.privacy=Política de Privacidade
|
||||||
legal.terms=Termos e Condições
|
legal.terms=Termos e Condições
|
||||||
@@ -818,12 +817,7 @@ sign.save=Guardar Assinatura
|
|||||||
sign.personalSigs=Assinaturas Pessoais
|
sign.personalSigs=Assinaturas Pessoais
|
||||||
sign.sharedSigs=Assinaturas Compartilhadas
|
sign.sharedSigs=Assinaturas Compartilhadas
|
||||||
sign.noSavedSigs=Nenhuma assinatura guardada encontrada
|
sign.noSavedSigs=Nenhuma assinatura guardada encontrada
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparar
|
repair.title=Reparar
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
@@ -818,12 +817,7 @@ sign.save=Save Signature
|
|||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=Personal Signatures
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=Shared Signatures
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=No saved signatures found
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Repară
|
repair.title=Repară
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Страница
|
|||||||
pages=Страницы
|
pages=Страницы
|
||||||
loading=Загрузка...
|
loading=Загрузка...
|
||||||
addToDoc=Добавить в документ
|
addToDoc=Добавить в документ
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Политика конфиденциальности
|
legal.privacy=Политика конфиденциальности
|
||||||
legal.terms=Условия использования
|
legal.terms=Условия использования
|
||||||
@@ -818,12 +817,7 @@ sign.save=Сохранить подпись
|
|||||||
sign.personalSigs=Личные подписи
|
sign.personalSigs=Личные подписи
|
||||||
sign.sharedSigs=Общие подписи
|
sign.sharedSigs=Общие подписи
|
||||||
sign.noSavedSigs=Найдено ни одной сохраненной подписи
|
sign.noSavedSigs=Найдено ни одной сохраненной подписи
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Ремонт
|
repair.title=Ремонт
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
@@ -818,12 +817,7 @@ sign.save=Save Signature
|
|||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=Personal Signatures
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=Shared Signatures
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=No saved signatures found
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Opraviť
|
repair.title=Opraviť
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
@@ -818,12 +817,7 @@ sign.save=Save Signature
|
|||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=Personal Signatures
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=Shared Signatures
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=No saved signatures found
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Popravi
|
repair.title=Popravi
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Sidan
|
|||||||
pages=Sidor
|
pages=Sidor
|
||||||
loading=Laddar...
|
loading=Laddar...
|
||||||
addToDoc=Lägg till i dokument
|
addToDoc=Lägg till i dokument
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Dataprotektionspolicy
|
legal.privacy=Dataprotektionspolicy
|
||||||
legal.terms=Villkor och betingelser
|
legal.terms=Villkor och betingelser
|
||||||
@@ -818,12 +817,7 @@ sign.save=Spara signatur
|
|||||||
sign.personalSigs=Personliga signaturer
|
sign.personalSigs=Personliga signaturer
|
||||||
sign.sharedSigs=Delade signaturer
|
sign.sharedSigs=Delade signaturer
|
||||||
sign.noSavedSigs=Inga sparade signaturer hittades
|
sign.noSavedSigs=Inga sparade signaturer hittades
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparera
|
repair.title=Reparera
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=หน้า
|
|||||||
pages=หน้า
|
pages=หน้า
|
||||||
loading=กำลังโหลด...
|
loading=กำลังโหลด...
|
||||||
addToDoc=เพิ่มเข้าสู่เอกสาร
|
addToDoc=เพิ่มเข้าสู่เอกสาร
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=นโยบายความเป็นส่วนตัว
|
legal.privacy=นโยบายความเป็นส่วนตัว
|
||||||
legal.terms=ข้อกำหนดการใช้งาน
|
legal.terms=ข้อกำหนดการใช้งาน
|
||||||
@@ -818,12 +817,7 @@ sign.save=บันทึกลายเซ็น
|
|||||||
sign.personalSigs=ลายเซ็นส่วนตัว
|
sign.personalSigs=ลายเซ็นส่วนตัว
|
||||||
sign.sharedSigs=ลายเซ็นร่วม
|
sign.sharedSigs=ลายเซ็นร่วม
|
||||||
sign.noSavedSigs=ไม่พบลายเซ็นที่บันทึกไว้
|
sign.noSavedSigs=ไม่พบลายเซ็นที่บันทึกไว้
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=ซ่อมแซม
|
repair.title=ซ่อมแซม
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Gizlilik Politikası
|
legal.privacy=Gizlilik Politikası
|
||||||
legal.terms=Şartlar ve koşullar
|
legal.terms=Şartlar ve koşullar
|
||||||
@@ -818,12 +817,7 @@ sign.save=Save Signature
|
|||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=Personal Signatures
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=Shared Signatures
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=No saved signatures found
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Onar
|
repair.title=Onar
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
@@ -818,12 +817,7 @@ sign.save=Save Signature
|
|||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=Personal Signatures
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=Shared Signatures
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=No saved signatures found
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Ремонт
|
repair.title=Ремонт
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
@@ -818,12 +817,7 @@ sign.save=Save Signature
|
|||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=Personal Signatures
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=Shared Signatures
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=No saved signatures found
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Sửa chữa
|
repair.title=Sửa chữa
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
@@ -818,12 +817,7 @@ sign.save=Save Signature
|
|||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=Personal Signatures
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=Shared Signatures
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=No saved signatures found
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=修复
|
repair.title=修复
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ page=頁面
|
|||||||
pages=頁面
|
pages=頁面
|
||||||
loading=載入中...
|
loading=載入中...
|
||||||
addToDoc=新增至文件
|
addToDoc=新增至文件
|
||||||
reset=Reset
|
|
||||||
|
|
||||||
legal.privacy=隱私權政策
|
legal.privacy=隱私權政策
|
||||||
legal.terms=使用條款
|
legal.terms=使用條款
|
||||||
@@ -818,12 +817,7 @@ sign.save=儲存簽章
|
|||||||
sign.personalSigs=個人簽章
|
sign.personalSigs=個人簽章
|
||||||
sign.sharedSigs=共用簽章
|
sign.sharedSigs=共用簽章
|
||||||
sign.noSavedSigs=尚未儲存任何簽章
|
sign.noSavedSigs=尚未儲存任何簽章
|
||||||
sign.addToAll=Add to all pages
|
|
||||||
sign.delete=Delete
|
|
||||||
sign.first=First page
|
|
||||||
sign.last=Last page
|
|
||||||
sign.next=Next page
|
|
||||||
sign.previous=Previous page
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=修復
|
repair.title=修復
|
||||||
@@ -949,16 +943,6 @@ multiTool.deleteSelected=Delete Selected
|
|||||||
multiTool.downloadAll=Export
|
multiTool.downloadAll=Export
|
||||||
multiTool.downloadSelected=Export Selected
|
multiTool.downloadSelected=Export Selected
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
|
||||||
multiTool.addFile=Add File
|
|
||||||
multiTool.rotateLeft=Rotate Left
|
|
||||||
multiTool.rotateRight=Rotate Right
|
|
||||||
multiTool.split=Split
|
|
||||||
multiTool.moveLeft=Move Left
|
|
||||||
multiTool.moveRight=Move Right
|
|
||||||
multiTool.delete=Delete
|
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,14 @@
|
|||||||
{
|
{
|
||||||
"moduleName": "ch.qos.logback:logback-classic",
|
"moduleName": "ch.qos.logback:logback-classic",
|
||||||
"moduleUrl": "http://www.qos.ch",
|
"moduleUrl": "http://www.qos.ch",
|
||||||
"moduleVersion": "1.5.12",
|
"moduleVersion": "1.5.11",
|
||||||
"moduleLicense": "GNU Lesser General Public License",
|
"moduleLicense": "GNU Lesser General Public License",
|
||||||
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "ch.qos.logback:logback-core",
|
"moduleName": "ch.qos.logback:logback-core",
|
||||||
"moduleUrl": "http://www.qos.ch",
|
"moduleUrl": "http://www.qos.ch",
|
||||||
"moduleVersion": "1.5.12",
|
"moduleVersion": "1.5.11",
|
||||||
"moduleLicense": "GNU Lesser General Public License",
|
"moduleLicense": "GNU Lesser General Public License",
|
||||||
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
||||||
},
|
},
|
||||||
@@ -45,77 +45,77 @@
|
|||||||
{
|
{
|
||||||
"moduleName": "com.fasterxml.jackson.core:jackson-annotations",
|
"moduleName": "com.fasterxml.jackson.core:jackson-annotations",
|
||||||
"moduleUrl": "https://github.com/FasterXML/jackson",
|
"moduleUrl": "https://github.com/FasterXML/jackson",
|
||||||
"moduleVersion": "2.18.1",
|
"moduleVersion": "2.17.2",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.fasterxml.jackson.core:jackson-core",
|
"moduleName": "com.fasterxml.jackson.core:jackson-core",
|
||||||
"moduleUrl": "https://github.com/FasterXML/jackson-core",
|
"moduleUrl": "https://github.com/FasterXML/jackson-core",
|
||||||
"moduleVersion": "2.18.1",
|
"moduleVersion": "2.17.2",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.fasterxml.jackson.core:jackson-databind",
|
"moduleName": "com.fasterxml.jackson.core:jackson-databind",
|
||||||
"moduleUrl": "https://github.com/FasterXML/jackson",
|
"moduleUrl": "https://github.com/FasterXML/jackson",
|
||||||
"moduleVersion": "2.18.1",
|
"moduleVersion": "2.17.2",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml",
|
"moduleName": "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml",
|
||||||
"moduleUrl": "https://github.com/FasterXML/jackson-dataformats-text",
|
"moduleUrl": "https://github.com/FasterXML/jackson-dataformats-text",
|
||||||
"moduleVersion": "2.18.1",
|
"moduleVersion": "2.17.2",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.fasterxml.jackson.datatype:jackson-datatype-jdk8",
|
"moduleName": "com.fasterxml.jackson.datatype:jackson-datatype-jdk8",
|
||||||
"moduleUrl": "https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8",
|
"moduleUrl": "https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8",
|
||||||
"moduleVersion": "2.18.1",
|
"moduleVersion": "2.17.2",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.fasterxml.jackson.datatype:jackson-datatype-jsr310",
|
"moduleName": "com.fasterxml.jackson.datatype:jackson-datatype-jsr310",
|
||||||
"moduleUrl": "https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310",
|
"moduleUrl": "https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310",
|
||||||
"moduleVersion": "2.18.1",
|
"moduleVersion": "2.17.2",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.fasterxml.jackson.jaxrs:jackson-jaxrs-base",
|
"moduleName": "com.fasterxml.jackson.jaxrs:jackson-jaxrs-base",
|
||||||
"moduleUrl": "https://github.com/FasterXML/jackson-jaxrs-providers/jackson-jaxrs-base",
|
"moduleUrl": "https://github.com/FasterXML/jackson-jaxrs-providers/jackson-jaxrs-base",
|
||||||
"moduleVersion": "2.18.1",
|
"moduleVersion": "2.17.2",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider",
|
"moduleName": "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider",
|
||||||
"moduleUrl": "https://github.com/FasterXML/jackson-jaxrs-providers/jackson-jaxrs-json-provider",
|
"moduleUrl": "https://github.com/FasterXML/jackson-jaxrs-providers/jackson-jaxrs-json-provider",
|
||||||
"moduleVersion": "2.18.1",
|
"moduleVersion": "2.17.2",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.fasterxml.jackson.module:jackson-module-jaxb-annotations",
|
"moduleName": "com.fasterxml.jackson.module:jackson-module-jaxb-annotations",
|
||||||
"moduleUrl": "https://github.com/FasterXML/jackson-modules-base",
|
"moduleUrl": "https://github.com/FasterXML/jackson-modules-base",
|
||||||
"moduleVersion": "2.18.1",
|
"moduleVersion": "2.17.2",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.fasterxml.jackson.module:jackson-module-parameter-names",
|
"moduleName": "com.fasterxml.jackson.module:jackson-module-parameter-names",
|
||||||
"moduleUrl": "https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names",
|
"moduleUrl": "https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names",
|
||||||
"moduleVersion": "2.18.1",
|
"moduleVersion": "2.17.2",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.fasterxml.jackson:jackson-bom",
|
"moduleName": "com.fasterxml.jackson:jackson-bom",
|
||||||
"moduleUrl": "https://github.com/FasterXML/jackson-bom",
|
"moduleUrl": "https://github.com/FasterXML/jackson-bom",
|
||||||
"moduleVersion": "2.18.1",
|
"moduleVersion": "2.17.2",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
@@ -146,18 +146,6 @@
|
|||||||
"moduleLicense": "GNU General Public License v3.0",
|
"moduleLicense": "GNU General Public License v3.0",
|
||||||
"moduleLicenseUrl": "https://api.github.com/licenses/gpl-3.0"
|
"moduleLicenseUrl": "https://api.github.com/licenses/gpl-3.0"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"moduleName": "com.github.jai-imageio:jai-imageio-core",
|
|
||||||
"moduleUrl": "https://github.com/jai-imageio/jai-imageio-core",
|
|
||||||
"moduleVersion": "1.4.0",
|
|
||||||
"moduleLicense": "LICENSE.txt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": "com.github.jai-imageio:jai-imageio-jpeg2000",
|
|
||||||
"moduleUrl": "https://github.com/jai-imageio/jai-imageio-jpeg2000",
|
|
||||||
"moduleVersion": "1.4.0",
|
|
||||||
"moduleLicense": "LICENSE-JJ2000.txt, LICENSE-Sun.txt"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"moduleName": "com.github.stephenc.jcip:jcip-annotations",
|
"moduleName": "com.github.stephenc.jcip:jcip-annotations",
|
||||||
"moduleUrl": "http://stephenc.github.com/jcip-annotations",
|
"moduleUrl": "http://stephenc.github.com/jcip-annotations",
|
||||||
@@ -174,22 +162,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.google.errorprone:error_prone_annotations",
|
"moduleName": "com.google.errorprone:error_prone_annotations",
|
||||||
"moduleUrl": "https://errorprone.info/error_prone_annotations",
|
"moduleVersion": "2.11.0",
|
||||||
"moduleVersion": "2.28.0",
|
|
||||||
"moduleLicense": "Apache 2.0",
|
"moduleLicense": "Apache 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.google.guava:failureaccess",
|
"moduleName": "com.google.guava:failureaccess",
|
||||||
"moduleUrl": "https://github.com/google/guava/",
|
"moduleUrl": "https://github.com/google/guava/",
|
||||||
"moduleVersion": "1.0.2",
|
"moduleVersion": "1.0.1",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "com.google.guava:guava",
|
"moduleName": "com.google.guava:guava",
|
||||||
"moduleUrl": "https://github.com/google/guava/",
|
"moduleUrl": "https://github.com/google/guava/",
|
||||||
"moduleVersion": "33.3.1-jre",
|
"moduleVersion": "31.1-jre",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
@@ -202,8 +189,8 @@
|
|||||||
{
|
{
|
||||||
"moduleName": "com.google.j2objc:j2objc-annotations",
|
"moduleName": "com.google.j2objc:j2objc-annotations",
|
||||||
"moduleUrl": "https://github.com/google/j2objc/",
|
"moduleUrl": "https://github.com/google/j2objc/",
|
||||||
"moduleVersion": "3.0.0",
|
"moduleVersion": "1.3",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -235,7 +222,7 @@
|
|||||||
{
|
{
|
||||||
"moduleName": "com.h2database:h2",
|
"moduleName": "com.h2database:h2",
|
||||||
"moduleUrl": "https://h2database.com",
|
"moduleUrl": "https://h2database.com",
|
||||||
"moduleVersion": "2.3.232",
|
"moduleVersion": "2.1.214",
|
||||||
"moduleLicense": "MPL 2.0",
|
"moduleLicense": "MPL 2.0",
|
||||||
"moduleLicenseUrl": "https://www.mozilla.org/en-US/MPL/2.0/"
|
"moduleLicenseUrl": "https://www.mozilla.org/en-US/MPL/2.0/"
|
||||||
},
|
},
|
||||||
@@ -383,17 +370,10 @@
|
|||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"moduleName": "commons-cli:commons-cli",
|
|
||||||
"moduleUrl": "http://commons.apache.org/proper/commons-cli/",
|
|
||||||
"moduleVersion": "1.4",
|
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"moduleName": "commons-codec:commons-codec",
|
"moduleName": "commons-codec:commons-codec",
|
||||||
"moduleUrl": "https://commons.apache.org/proper/commons-codec/",
|
"moduleUrl": "https://commons.apache.org/proper/commons-codec/",
|
||||||
"moduleVersion": "1.17.1",
|
"moduleVersion": "1.16.1",
|
||||||
"moduleLicense": "Apache-2.0",
|
"moduleLicense": "Apache-2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
@@ -413,10 +393,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "commons-logging:commons-logging",
|
"moduleName": "commons-logging:commons-logging",
|
||||||
"moduleUrl": "https://commons.apache.org/proper/commons-logging/",
|
"moduleUrl": "http://jakarta.apache.org/commons/logging/",
|
||||||
"moduleVersion": "1.3.3",
|
"moduleVersion": "1.0.4",
|
||||||
"moduleLicense": "Apache-2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "/LICENSE.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "io.dropwizard.metrics:metrics-core",
|
"moduleName": "io.dropwizard.metrics:metrics-core",
|
||||||
@@ -434,34 +414,34 @@
|
|||||||
{
|
{
|
||||||
"moduleName": "io.micrometer:micrometer-commons",
|
"moduleName": "io.micrometer:micrometer-commons",
|
||||||
"moduleUrl": "https://github.com/micrometer-metrics/micrometer",
|
"moduleUrl": "https://github.com/micrometer-metrics/micrometer",
|
||||||
"moduleVersion": "1.14.1",
|
"moduleVersion": "1.13.6",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "io.micrometer:micrometer-core",
|
"moduleName": "io.micrometer:micrometer-core",
|
||||||
"moduleUrl": "https://github.com/micrometer-metrics/micrometer",
|
"moduleUrl": "https://github.com/micrometer-metrics/micrometer",
|
||||||
"moduleVersion": "1.14.1",
|
"moduleVersion": "1.13.6",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "io.micrometer:micrometer-jakarta9",
|
"moduleName": "io.micrometer:micrometer-jakarta9",
|
||||||
"moduleUrl": "https://github.com/micrometer-metrics/micrometer",
|
"moduleUrl": "https://github.com/micrometer-metrics/micrometer",
|
||||||
"moduleVersion": "1.14.1",
|
"moduleVersion": "1.13.6",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "io.micrometer:micrometer-observation",
|
"moduleName": "io.micrometer:micrometer-observation",
|
||||||
"moduleUrl": "https://github.com/micrometer-metrics/micrometer",
|
"moduleUrl": "https://github.com/micrometer-metrics/micrometer",
|
||||||
"moduleVersion": "1.14.1",
|
"moduleVersion": "1.13.6",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "io.smallrye:jandex",
|
"moduleName": "io.smallrye:jandex",
|
||||||
"moduleVersion": "3.2.0",
|
"moduleVersion": "3.1.2",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
@@ -593,7 +573,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "net.bytebuddy:byte-buddy",
|
"moduleName": "net.bytebuddy:byte-buddy",
|
||||||
"moduleVersion": "1.15.10",
|
"moduleVersion": "1.14.19",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
@@ -631,17 +611,10 @@
|
|||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"moduleName": "org.apache.commons:commons-csv",
|
|
||||||
"moduleUrl": "https://commons.apache.org/proper/commons-csv/",
|
|
||||||
"moduleVersion": "1.9.0",
|
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"moduleName": "org.apache.commons:commons-lang3",
|
"moduleName": "org.apache.commons:commons-lang3",
|
||||||
"moduleUrl": "https://commons.apache.org/proper/commons-lang/",
|
"moduleUrl": "https://commons.apache.org/proper/commons-lang/",
|
||||||
"moduleVersion": "3.17.0",
|
"moduleVersion": "3.14.0",
|
||||||
"moduleLicense": "Apache-2.0",
|
"moduleLicense": "Apache-2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
@@ -668,13 +641,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.apache.logging.log4j:log4j-api",
|
"moduleName": "org.apache.logging.log4j:log4j-api",
|
||||||
"moduleVersion": "2.24.1",
|
"moduleVersion": "2.23.1",
|
||||||
"moduleLicense": "Apache-2.0",
|
"moduleLicense": "Apache-2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.apache.logging.log4j:log4j-to-slf4j",
|
"moduleName": "org.apache.logging.log4j:log4j-to-slf4j",
|
||||||
"moduleVersion": "2.24.1",
|
"moduleVersion": "2.23.1",
|
||||||
"moduleLicense": "Apache-2.0",
|
"moduleLicense": "Apache-2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
@@ -722,7 +695,7 @@
|
|||||||
{
|
{
|
||||||
"moduleName": "org.apache.tomcat.embed:tomcat-embed-el",
|
"moduleName": "org.apache.tomcat.embed:tomcat-embed-el",
|
||||||
"moduleUrl": "https://tomcat.apache.org/",
|
"moduleUrl": "https://tomcat.apache.org/",
|
||||||
"moduleVersion": "10.1.33",
|
"moduleVersion": "10.1.31",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
@@ -760,52 +733,31 @@
|
|||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"moduleName": "org.bouncycastle:bcmail-jdk15on",
|
|
||||||
"moduleUrl": "https://www.bouncycastle.org/java.html",
|
|
||||||
"moduleVersion": "1.69",
|
|
||||||
"moduleLicense": "Bouncy Castle Licence",
|
|
||||||
"moduleLicenseUrl": "https://www.bouncycastle.org/licence.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": "org.bouncycastle:bcpkix-jdk15on",
|
|
||||||
"moduleUrl": "https://www.bouncycastle.org/java.html",
|
|
||||||
"moduleVersion": "1.69",
|
|
||||||
"moduleLicense": "Bouncy Castle Licence",
|
|
||||||
"moduleLicenseUrl": "https://www.bouncycastle.org/licence.html"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"moduleName": "org.bouncycastle:bcpkix-jdk18on",
|
"moduleName": "org.bouncycastle:bcpkix-jdk18on",
|
||||||
"moduleUrl": "https://www.bouncycastle.org/java.html",
|
"moduleUrl": "https://www.bouncycastle.org/java.html",
|
||||||
"moduleVersion": "1.79",
|
"moduleVersion": "1.78.1",
|
||||||
"moduleLicense": "Bouncy Castle Licence",
|
"moduleLicense": "Bouncy Castle Licence",
|
||||||
"moduleLicenseUrl": "https://www.bouncycastle.org/licence.html"
|
"moduleLicenseUrl": "https://www.bouncycastle.org/licence.html"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.bouncycastle:bcprov-jdk18on",
|
"moduleName": "org.bouncycastle:bcprov-jdk18on",
|
||||||
"moduleUrl": "https://www.bouncycastle.org/java.html",
|
"moduleUrl": "https://www.bouncycastle.org/java.html",
|
||||||
"moduleVersion": "1.79",
|
"moduleVersion": "1.78.1",
|
||||||
"moduleLicense": "Bouncy Castle Licence",
|
|
||||||
"moduleLicenseUrl": "https://www.bouncycastle.org/licence.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": "org.bouncycastle:bcutil-jdk15on",
|
|
||||||
"moduleUrl": "https://www.bouncycastle.org/java.html",
|
|
||||||
"moduleVersion": "1.69",
|
|
||||||
"moduleLicense": "Bouncy Castle Licence",
|
"moduleLicense": "Bouncy Castle Licence",
|
||||||
"moduleLicenseUrl": "https://www.bouncycastle.org/licence.html"
|
"moduleLicenseUrl": "https://www.bouncycastle.org/licence.html"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.bouncycastle:bcutil-jdk18on",
|
"moduleName": "org.bouncycastle:bcutil-jdk18on",
|
||||||
"moduleUrl": "https://www.bouncycastle.org/java.html",
|
"moduleUrl": "https://www.bouncycastle.org/java.html",
|
||||||
"moduleVersion": "1.79",
|
"moduleVersion": "1.78.1",
|
||||||
"moduleLicense": "Bouncy Castle Licence",
|
"moduleLicense": "Bouncy Castle Licence",
|
||||||
"moduleLicenseUrl": "https://www.bouncycastle.org/licence.html"
|
"moduleLicenseUrl": "https://www.bouncycastle.org/licence.html"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.checkerframework:checker-qual",
|
"moduleName": "org.checkerframework:checker-qual",
|
||||||
"moduleUrl": "https://checkerframework.org/",
|
"moduleUrl": "https://checkerframework.org",
|
||||||
"moduleVersion": "3.43.0",
|
"moduleVersion": "3.12.0",
|
||||||
"moduleLicense": "The MIT License",
|
"moduleLicense": "The MIT License",
|
||||||
"moduleLicenseUrl": "http://opensource.org/licenses/MIT"
|
"moduleLicenseUrl": "http://opensource.org/licenses/MIT"
|
||||||
},
|
},
|
||||||
@@ -838,182 +790,182 @@
|
|||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-client",
|
"moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-client",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-common",
|
"moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-common",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-server",
|
"moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-server",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jetty-server",
|
"moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jetty-server",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-servlet",
|
"moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-servlet",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty.ee10:jetty-ee10-annotations",
|
"moduleName": "org.eclipse.jetty.ee10:jetty-ee10-annotations",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty.ee10:jetty-ee10-plus",
|
"moduleName": "org.eclipse.jetty.ee10:jetty-ee10-plus",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty.ee10:jetty-ee10-servlet",
|
"moduleName": "org.eclipse.jetty.ee10:jetty-ee10-servlet",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty.ee10:jetty-ee10-servlets",
|
"moduleName": "org.eclipse.jetty.ee10:jetty-ee10-servlets",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty.ee10:jetty-ee10-webapp",
|
"moduleName": "org.eclipse.jetty.ee10:jetty-ee10-webapp",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty.websocket:jetty-websocket-core-client",
|
"moduleName": "org.eclipse.jetty.websocket:jetty-websocket-core-client",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty.websocket:jetty-websocket-core-common",
|
"moduleName": "org.eclipse.jetty.websocket:jetty-websocket-core-common",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty.websocket:jetty-websocket-core-server",
|
"moduleName": "org.eclipse.jetty.websocket:jetty-websocket-core-server",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty.websocket:jetty-websocket-jetty-api",
|
"moduleName": "org.eclipse.jetty.websocket:jetty-websocket-jetty-api",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty.websocket:jetty-websocket-jetty-common",
|
"moduleName": "org.eclipse.jetty.websocket:jetty-websocket-jetty-common",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty:jetty-alpn-client",
|
"moduleName": "org.eclipse.jetty:jetty-alpn-client",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty:jetty-client",
|
"moduleName": "org.eclipse.jetty:jetty-client",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty:jetty-ee",
|
"moduleName": "org.eclipse.jetty:jetty-ee",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty:jetty-http",
|
"moduleName": "org.eclipse.jetty:jetty-http",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty:jetty-io",
|
"moduleName": "org.eclipse.jetty:jetty-io",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty:jetty-plus",
|
"moduleName": "org.eclipse.jetty:jetty-plus",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty:jetty-security",
|
"moduleName": "org.eclipse.jetty:jetty-security",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty:jetty-server",
|
"moduleName": "org.eclipse.jetty:jetty-server",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty:jetty-session",
|
"moduleName": "org.eclipse.jetty:jetty-session",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty:jetty-util",
|
"moduleName": "org.eclipse.jetty:jetty-util",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.eclipse.jetty:jetty-xml",
|
"moduleName": "org.eclipse.jetty:jetty-xml",
|
||||||
"moduleUrl": "https://jetty.org/",
|
"moduleUrl": "https://jetty.org/",
|
||||||
"moduleVersion": "12.0.15",
|
"moduleVersion": "12.0.14",
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0",
|
"moduleLicense": "Eclipse Public License - Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
"moduleLicenseUrl": "https://www.eclipse.org/legal/epl-2.0/"
|
||||||
},
|
},
|
||||||
@@ -1048,23 +1000,23 @@
|
|||||||
{
|
{
|
||||||
"moduleName": "org.hibernate.common:hibernate-commons-annotations",
|
"moduleName": "org.hibernate.common:hibernate-commons-annotations",
|
||||||
"moduleUrl": "http://hibernate.org",
|
"moduleUrl": "http://hibernate.org",
|
||||||
"moduleVersion": "7.0.3.Final",
|
"moduleVersion": "6.0.6.Final",
|
||||||
"moduleLicense": "Apache License Version 2.0",
|
"moduleLicense": "GNU Library General Public License v2.1 or later",
|
||||||
"moduleLicenseUrl": "https://opensource.org/licenses/Apache-2.0"
|
"moduleLicenseUrl": "http://www.opensource.org/licenses/LGPL-2.1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.hibernate.orm:hibernate-core",
|
"moduleName": "org.hibernate.orm:hibernate-core",
|
||||||
"moduleUrl": "https://www.hibernate.org/orm/6.6",
|
"moduleUrl": "https://www.hibernate.org/orm/6.5",
|
||||||
"moduleVersion": "6.6.2.Final",
|
"moduleVersion": "6.5.3.Final",
|
||||||
"moduleLicense": "GNU Library General Public License v2.1 or later",
|
"moduleLicense": "GNU Library General Public License v2.1 or later",
|
||||||
"moduleLicenseUrl": "https://www.opensource.org/licenses/LGPL-2.1"
|
"moduleLicenseUrl": "https://www.opensource.org/licenses/LGPL-2.1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.jboss.logging:jboss-logging",
|
"moduleName": "org.jboss.logging:jboss-logging",
|
||||||
"moduleUrl": "http://www.jboss.org",
|
"moduleUrl": "http://www.jboss.org",
|
||||||
"moduleVersion": "3.6.1.Final",
|
"moduleVersion": "3.5.3.Final",
|
||||||
"moduleLicense": "Apache License 2.0",
|
"moduleLicense": "Public Domain",
|
||||||
"moduleLicenseUrl": "https://repository.jboss.org/licenses/apache-2.0.txt"
|
"moduleLicenseUrl": "http://repository.jboss.org/licenses/cc0-1.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.latencyutils:LatencyUtils",
|
"moduleName": "org.latencyutils:LatencyUtils",
|
||||||
@@ -1073,12 +1025,6 @@
|
|||||||
"moduleLicense": "Public Domain, per Creative Commons CC0",
|
"moduleLicense": "Public Domain, per Creative Commons CC0",
|
||||||
"moduleLicenseUrl": "http://creativecommons.org/publicdomain/zero/1.0/"
|
"moduleLicenseUrl": "http://creativecommons.org/publicdomain/zero/1.0/"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"moduleName": "org.locationtech.jts:jts-core",
|
|
||||||
"moduleVersion": "1.18.1",
|
|
||||||
"moduleLicense": "Eclipse Public License, Version 2.0",
|
|
||||||
"moduleLicenseUrl": "https://github.com/locationtech/jts/blob/master/LICENSE_EPLv2.txt"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"moduleName": "org.opensaml:opensaml-core",
|
"moduleName": "org.opensaml:opensaml-core",
|
||||||
"moduleVersion": "4.3.2",
|
"moduleVersion": "4.3.2",
|
||||||
@@ -1154,21 +1100,21 @@
|
|||||||
{
|
{
|
||||||
"moduleName": "org.ow2.asm:asm",
|
"moduleName": "org.ow2.asm:asm",
|
||||||
"moduleUrl": "http://asm.ow2.org",
|
"moduleUrl": "http://asm.ow2.org",
|
||||||
"moduleVersion": "9.7.1",
|
"moduleVersion": "9.7",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.ow2.asm:asm-commons",
|
"moduleName": "org.ow2.asm:asm-commons",
|
||||||
"moduleUrl": "http://asm.ow2.org",
|
"moduleUrl": "http://asm.ow2.org",
|
||||||
"moduleVersion": "9.7.1",
|
"moduleVersion": "9.7",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.ow2.asm:asm-tree",
|
"moduleName": "org.ow2.asm:asm-tree",
|
||||||
"moduleUrl": "http://asm.ow2.org",
|
"moduleUrl": "http://asm.ow2.org",
|
||||||
"moduleVersion": "9.7.1",
|
"moduleVersion": "9.7",
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
@@ -1207,266 +1153,273 @@
|
|||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot",
|
"moduleName": "org.springframework.boot:spring-boot",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-actuator",
|
"moduleName": "org.springframework.boot:spring-boot-actuator",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-actuator-autoconfigure",
|
"moduleName": "org.springframework.boot:spring-boot-actuator-autoconfigure",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-autoconfigure",
|
"moduleName": "org.springframework.boot:spring-boot-autoconfigure",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-devtools",
|
"moduleName": "org.springframework.boot:spring-boot-devtools",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-starter",
|
"moduleName": "org.springframework.boot:spring-boot-starter",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-starter-actuator",
|
"moduleName": "org.springframework.boot:spring-boot-starter-actuator",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleName": "org.springframework.boot:spring-boot-starter-aop",
|
||||||
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-starter-data-jpa",
|
"moduleName": "org.springframework.boot:spring-boot-starter-data-jpa",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-starter-jdbc",
|
"moduleName": "org.springframework.boot:spring-boot-starter-jdbc",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-starter-jetty",
|
"moduleName": "org.springframework.boot:spring-boot-starter-jetty",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-starter-json",
|
"moduleName": "org.springframework.boot:spring-boot-starter-json",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-starter-logging",
|
"moduleName": "org.springframework.boot:spring-boot-starter-logging",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-starter-oauth2-client",
|
"moduleName": "org.springframework.boot:spring-boot-starter-oauth2-client",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-starter-security",
|
"moduleName": "org.springframework.boot:spring-boot-starter-security",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-starter-thymeleaf",
|
"moduleName": "org.springframework.boot:spring-boot-starter-thymeleaf",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.boot:spring-boot-starter-web",
|
"moduleName": "org.springframework.boot:spring-boot-starter-web",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-boot",
|
"moduleUrl": "https://spring.io/projects/spring-boot",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.data:spring-data-commons",
|
"moduleName": "org.springframework.data:spring-data-commons",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-data",
|
"moduleUrl": "https://spring.io/projects/spring-data",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.data:spring-data-jpa",
|
"moduleName": "org.springframework.data:spring-data-jpa",
|
||||||
"moduleUrl": "https://projects.spring.io/spring-data-jpa",
|
"moduleUrl": "https://projects.spring.io/spring-data-jpa",
|
||||||
"moduleVersion": "3.4.0",
|
"moduleVersion": "3.3.5",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.security:spring-security-config",
|
"moduleName": "org.springframework.security:spring-security-config",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-security",
|
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||||
"moduleVersion": "6.4.1",
|
"moduleVersion": "6.3.4",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.security:spring-security-core",
|
"moduleName": "org.springframework.security:spring-security-core",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-security",
|
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||||
"moduleVersion": "6.4.1",
|
"moduleVersion": "6.3.4",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.security:spring-security-crypto",
|
"moduleName": "org.springframework.security:spring-security-crypto",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-security",
|
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||||
"moduleVersion": "6.4.1",
|
"moduleVersion": "6.3.4",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.security:spring-security-oauth2-client",
|
"moduleName": "org.springframework.security:spring-security-oauth2-client",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-security",
|
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||||
"moduleVersion": "6.4.1",
|
"moduleVersion": "6.3.4",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.security:spring-security-oauth2-core",
|
"moduleName": "org.springframework.security:spring-security-oauth2-core",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-security",
|
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||||
"moduleVersion": "6.4.1",
|
"moduleVersion": "6.3.4",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.security:spring-security-oauth2-jose",
|
"moduleName": "org.springframework.security:spring-security-oauth2-jose",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-security",
|
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||||
"moduleVersion": "6.4.1",
|
"moduleVersion": "6.3.4",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.security:spring-security-saml2-service-provider",
|
"moduleName": "org.springframework.security:spring-security-saml2-service-provider",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-security",
|
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||||
"moduleVersion": "6.4.1",
|
"moduleVersion": "6.3.4",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework.security:spring-security-web",
|
"moduleName": "org.springframework.security:spring-security-web",
|
||||||
"moduleUrl": "https://spring.io/projects/spring-security",
|
"moduleUrl": "https://spring.io/projects/spring-security",
|
||||||
"moduleVersion": "6.4.1",
|
"moduleVersion": "6.3.4",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework:spring-aop",
|
"moduleName": "org.springframework:spring-aop",
|
||||||
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
||||||
"moduleVersion": "6.2.0",
|
"moduleVersion": "6.1.14",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework:spring-aspects",
|
"moduleName": "org.springframework:spring-aspects",
|
||||||
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
||||||
"moduleVersion": "6.2.0",
|
"moduleVersion": "6.1.14",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework:spring-beans",
|
"moduleName": "org.springframework:spring-beans",
|
||||||
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
||||||
"moduleVersion": "6.2.0",
|
"moduleVersion": "6.1.14",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework:spring-context",
|
"moduleName": "org.springframework:spring-context",
|
||||||
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
||||||
"moduleVersion": "6.2.0",
|
"moduleVersion": "6.1.14",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework:spring-core",
|
"moduleName": "org.springframework:spring-core",
|
||||||
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
||||||
"moduleVersion": "6.2.0",
|
"moduleVersion": "6.1.14",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework:spring-expression",
|
"moduleName": "org.springframework:spring-expression",
|
||||||
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
||||||
"moduleVersion": "6.2.0",
|
"moduleVersion": "6.1.14",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework:spring-jcl",
|
"moduleName": "org.springframework:spring-jcl",
|
||||||
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
||||||
"moduleVersion": "6.2.0",
|
"moduleVersion": "6.1.14",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework:spring-jdbc",
|
"moduleName": "org.springframework:spring-jdbc",
|
||||||
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
||||||
"moduleVersion": "6.2.0",
|
"moduleVersion": "6.1.14",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework:spring-orm",
|
"moduleName": "org.springframework:spring-orm",
|
||||||
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
||||||
"moduleVersion": "6.2.0",
|
"moduleVersion": "6.1.14",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework:spring-tx",
|
"moduleName": "org.springframework:spring-tx",
|
||||||
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
||||||
"moduleVersion": "6.2.0",
|
"moduleVersion": "6.1.14",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework:spring-web",
|
"moduleName": "org.springframework:spring-web",
|
||||||
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
||||||
"moduleVersion": "6.2.0",
|
"moduleVersion": "6.1.14",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "org.springframework:spring-webmvc",
|
"moduleName": "org.springframework:spring-webmvc",
|
||||||
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
"moduleUrl": "https://github.com/spring-projects/spring-framework",
|
||||||
"moduleVersion": "6.2.0",
|
"moduleVersion": "6.1.14",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
|
||||||
},
|
},
|
||||||
@@ -1511,17 +1464,10 @@
|
|||||||
{
|
{
|
||||||
"moduleName": "org.yaml:snakeyaml",
|
"moduleName": "org.yaml:snakeyaml",
|
||||||
"moduleUrl": "https://bitbucket.org/snakeyaml/snakeyaml",
|
"moduleUrl": "https://bitbucket.org/snakeyaml/snakeyaml",
|
||||||
"moduleVersion": "2.3",
|
"moduleVersion": "2.2",
|
||||||
"moduleLicense": "Apache License, Version 2.0",
|
"moduleLicense": "Apache License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"moduleName": "technology.tabula:tabula",
|
|
||||||
"moduleUrl": "http://github.com/tabulapdf/tabula-java",
|
|
||||||
"moduleVersion": "1.0.5",
|
|
||||||
"moduleLicense": "MIT License",
|
|
||||||
"moduleLicenseUrl": "http://www.opensource.org/licenses/mit-license.php"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"moduleName": "xml-apis:xml-apis",
|
"moduleName": "xml-apis:xml-apis",
|
||||||
"moduleUrl": "http://xml.apache.org/commons/components/external/",
|
"moduleUrl": "http://xml.apache.org/commons/components/external/",
|
||||||
|
|||||||
@@ -19,15 +19,6 @@
|
|||||||
transform-origin: top left;
|
transform-origin: top left;
|
||||||
}
|
}
|
||||||
|
|
||||||
#drag-container .multidrag {
|
|
||||||
position: fixed;
|
|
||||||
max-width: 200px;
|
|
||||||
max-height: 200px;
|
|
||||||
transform-origin: top left;
|
|
||||||
margin-left: 1rem;
|
|
||||||
background-color: rgba(0, 29, 41, 0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.drag-manager_dragging {
|
.drag-manager_dragging {
|
||||||
width: 0px;
|
width: 0px;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
|||||||
@@ -100,30 +100,3 @@ input:-webkit-autofill:focus {
|
|||||||
input[data-autocompleted] {
|
input[data-autocompleted] {
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
}
|
}
|
||||||
.btn-tooltip {
|
|
||||||
position: absolute;
|
|
||||||
display: none;
|
|
||||||
bottom: 3.2rem;
|
|
||||||
white-space: nowrap;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
width: fit-content;
|
|
||||||
padding: 7px;
|
|
||||||
background-color: rgba(0, 29, 41, 0.9);
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: whitesmoke;
|
|
||||||
animation: fadeup 0.15s linear;
|
|
||||||
}
|
|
||||||
@keyframes fadeup {
|
|
||||||
0% {
|
|
||||||
transform: translateY(10px);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateY(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.btn:hover .btn-tooltip {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ label {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#export-button {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.bg-card {
|
.bg-card {
|
||||||
background-color: var(--md-sys-color-surface-5);
|
background-color: var(--md-sys-color-surface-5);
|
||||||
border-radius: 3rem;
|
border-radius: 3rem;
|
||||||
@@ -286,6 +290,3 @@ label {
|
|||||||
.checkbox-label {
|
.checkbox-label {
|
||||||
font-size: medium;
|
font-size: medium;
|
||||||
}
|
}
|
||||||
.btn {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ span.icon-text::after {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* .tooltip-text {
|
.tooltip-text {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
background-color: rgb(71 67 67 / 80%);
|
background-color: rgb(71 67 67 / 80%);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@@ -162,7 +162,7 @@ span.icon-text::after {
|
|||||||
.nav-item:hover .tooltip-text {
|
.nav-item:hover .tooltip-text {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
} */
|
}
|
||||||
|
|
||||||
.dropdown-menu.scrollable-y {
|
.dropdown-menu.scrollable-y {
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
@@ -324,18 +324,6 @@ span.icon-text::after {
|
|||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* .icon-hide {
|
|
||||||
display: none;
|
|
||||||
} */
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width:1199px) {
|
|
||||||
.icon-hide {
|
|
||||||
display: inline-flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width:1200px) {
|
|
||||||
.icon-hide {
|
.icon-hide {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.pdf-actions_button-container {
|
.pdf-actions_button-container {
|
||||||
z-index: 4;
|
z-index: 2;
|
||||||
display: flex;
|
display: flex;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.1s linear;
|
transition: opacity 0.1s linear;
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
width: 80px;
|
width: 80px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
z-index: 3;
|
z-index: 1;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.2s;
|
transition: opacity 0.2s;
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,6 @@ html[dir="rtl"] .pdf-actions_container:last-child>.pdf-actions_insert-file-butto
|
|||||||
translate: 50% -50%;
|
translate: 50% -50%;
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
z-index: 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.pdf-actions_split-file-button {
|
.pdf-actions_split-file-button {
|
||||||
@@ -126,9 +125,9 @@ html[dir="rtl"] .pdf-actions_container:last-child>.pdf-actions_insert-file-butto
|
|||||||
translate: 0 -50%;
|
translate: 0 -50%;
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
z-index: 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.pdf-actions_checkbox {
|
.pdf-actions_checkbox {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 5px;
|
top: 5px;
|
||||||
@@ -138,7 +137,7 @@ html[dir="rtl"] .pdf-actions_container:last-child>.pdf-actions_insert-file-butto
|
|||||||
padding: 6px 8px;
|
padding: 6px 8px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
z-index: 10;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
@@ -151,5 +150,4 @@ html[dir="rtl"] .pdf-actions_container:last-child>.pdf-actions_insert-file-butto
|
|||||||
translate: 0% -50%;
|
translate: 0% -50%;
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
z-index: 5;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,54 +62,53 @@ select#font-select option {
|
|||||||
background-color: rgba(52, 152, 219, 0.2);
|
background-color: rgba(52, 152, 219, 0.2);
|
||||||
/* Darken background on hover */
|
/* Darken background on hover */
|
||||||
}
|
}
|
||||||
|
|
||||||
.signature-grid {
|
.signature-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.signature-list {
|
.signature-list {
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.signature-list-item {
|
.signature-list-item {
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
border: 1px solid #dee2e6;
|
border: 1px solid #dee2e6;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background-color 0.2s;
|
transition: background-color 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.signature-list-item:hover {
|
.signature-list-item:hover {
|
||||||
background-color: #f8f9fa;
|
background-color: #f8f9fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.signature-list-info {
|
.signature-list-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.signature-list-name {
|
.signature-list-name {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.signature-list-details {
|
.signature-list-details {
|
||||||
color: #6c757d;
|
color: #6c757d;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.signature-list-details small:not(:last-child) {
|
.signature-list-details small:not(:last-child) {
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-toggle {
|
.view-toggle {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
}
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-az" viewBox="0 0 640 480">
|
|
||||||
<path fill="#3f9c35" d="M.1 0h640v480H.1z"/>
|
|
||||||
<path fill="#ed2939" d="M.1 0h640v320H.1z"/>
|
|
||||||
<path fill="#00b9e4" d="M.1 0h640v160H.1z"/>
|
|
||||||
<circle cx="304" cy="240" r="72" fill="#fff"/>
|
|
||||||
<circle cx="320" cy="240" r="60" fill="#ed2939"/>
|
|
||||||
<path fill="#fff" d="m384 200 7.7 21.5 20.6-9.8-9.8 20.7L424 240l-21.5 7.7 9.8 20.6-20.6-9.8L384 280l-7.7-21.5-20.6 9.8 9.8-20.6L344 240l21.5-7.7-9.8-20.6 20.6 9.8z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 501 B |
@@ -34,14 +34,6 @@
|
|||||||
const url = this.action;
|
const url = this.action;
|
||||||
const files = $("#fileInput-input")[0].files;
|
const files = $("#fileInput-input")[0].files;
|
||||||
const formData = new FormData(this);
|
const formData = new FormData(this);
|
||||||
const submitButton = document.getElementById("submitBtn");
|
|
||||||
const showGameBtn = document.getElementById("show-game-btn");
|
|
||||||
const originalButtonText = submitButton.textContent;
|
|
||||||
var boredWaiting = localStorage.getItem("boredWaiting") || "disabled";
|
|
||||||
|
|
||||||
if (showGameBtn) {
|
|
||||||
showGameBtn.style.display = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove empty file entries
|
// Remove empty file entries
|
||||||
for (let [key, value] of formData.entries()) {
|
for (let [key, value] of formData.entries()) {
|
||||||
@@ -50,10 +42,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const override = $("#override").val() || "";
|
const override = $("#override").val() || "";
|
||||||
|
const originalButtonText = $("#submitBtn").text();
|
||||||
|
$("#submitBtn").text("Processing...");
|
||||||
console.log(override);
|
console.log(override);
|
||||||
|
|
||||||
// Set a timeout to show the game button if operation takes more than 5 seconds
|
// Set a timeout to show the game button if operation takes more than 5 seconds
|
||||||
const timeoutId = setTimeout(() => {
|
const timeoutId = setTimeout(() => {
|
||||||
|
var boredWaiting = localStorage.getItem("boredWaiting") || "disabled";
|
||||||
|
const showGameBtn = document.getElementById("show-game-btn");
|
||||||
if (boredWaiting === "enabled" && showGameBtn) {
|
if (boredWaiting === "enabled" && showGameBtn) {
|
||||||
showGameBtn.style.display = "block";
|
showGameBtn.style.display = "block";
|
||||||
showGameBtn.parentNode.insertBefore(document.createElement('br'), showGameBtn.nextSibling);
|
showGameBtn.parentNode.insertBefore(document.createElement('br'), showGameBtn.nextSibling);
|
||||||
@@ -61,9 +57,6 @@
|
|||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
submitButton.textContent = "Processing...";
|
|
||||||
submitButton.disabled = true;
|
|
||||||
|
|
||||||
if (remoteCall === true) {
|
if (remoteCall === true) {
|
||||||
if (override === "multi" || (!multipleInputsForSingleRequest && files.length > 1 && override !== "single")) {
|
if (override === "multi" || (!multipleInputsForSingleRequest && files.length > 1 && override !== "single")) {
|
||||||
await submitMultiPdfForm(url, files);
|
await submitMultiPdfForm(url, files);
|
||||||
@@ -72,17 +65,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
clearFileInput();
|
clearFileInput();
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
if (showGameBtn) {
|
$("#submitBtn").text(originalButtonText);
|
||||||
showGameBtn.style.display = "none";
|
|
||||||
showGameBtn.style.marginTop = "";
|
|
||||||
}
|
|
||||||
submitButton.textContent = originalButtonText;
|
|
||||||
submitButton.disabled = false;
|
|
||||||
|
|
||||||
// After process finishes, check for boredWaiting and gameDialog open status
|
// After process finishes, check for boredWaiting and gameDialog open status
|
||||||
|
const boredWaiting = localStorage.getItem("boredWaiting") || "disabled";
|
||||||
const gameDialog = document.getElementById('game-container-wrapper');
|
const gameDialog = document.getElementById('game-container-wrapper');
|
||||||
if (boredWaiting === "enabled" && gameDialog && gameDialog.open) {
|
if (boredWaiting === "enabled" && gameDialog && gameDialog.open) {
|
||||||
// Display a green banner at the bottom of the screen saying "Download complete"
|
// Display a green banner at the bottom of the screen saying "Download complete"
|
||||||
@@ -99,47 +87,80 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
clearFileInput();
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
showGameBtn.style.display = "none";
|
|
||||||
submitButton.textContent = originalButtonText;
|
|
||||||
submitButton.disabled = false;
|
|
||||||
handleDownloadError(error);
|
handleDownloadError(error);
|
||||||
|
$("#submitBtn").text(originalButtonText);
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
async function getPDFPageCount(file) {
|
function getPDFPageCount(file) {
|
||||||
try {
|
try {
|
||||||
const arrayBuffer = await file.arrayBuffer();
|
if (file.type !== 'application/pdf') {
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc = '/pdfjs-legacy/pdf.worker.mjs'
|
return null;
|
||||||
const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
|
}
|
||||||
return pdf.numPages;
|
|
||||||
|
// Create a URL for the file
|
||||||
|
const url = URL.createObjectURL(file);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Ensure the worker is properly set
|
||||||
|
if (!pdfjsLib.GlobalWorkerOptions.workerSrc) {
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the PDF document
|
||||||
|
const loadingTask = pdfjsLib.getDocument(url);
|
||||||
|
const pdf = await loadingTask.promise;
|
||||||
|
|
||||||
|
// Get the page count
|
||||||
|
const pageCount = pdf.numPages;
|
||||||
|
return pageCount;
|
||||||
|
} finally {
|
||||||
|
// Clean up the URL
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error getting PDF page count:', error);
|
console.error('Error counting PDF pages:', error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function trackFileProcessing(file, startTime, success, errorMessage = null) {
|
||||||
|
const endTime = performance.now();
|
||||||
|
const processingTime = endTime - startTime;
|
||||||
|
|
||||||
|
posthog.capture('file_processing', {
|
||||||
|
success: success,
|
||||||
|
file_type: file.type || 'unknown',
|
||||||
|
file_size: file.size,
|
||||||
|
processing_time: processingTime,
|
||||||
|
error_message: errorMessage,
|
||||||
|
pdf_pages: file.type === 'application/pdf' ? getPDFPageCount(file) : null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function handleSingleDownload(url, formData, isMulti = false, isZip = false) {
|
async function handleSingleDownload(url, formData, isMulti = false, isZip = false) {
|
||||||
const startTime = performance.now();
|
const startTime = performance.now();
|
||||||
const file = formData.get('fileInput');
|
const file = formData.get('fileInput');
|
||||||
let success = false;
|
|
||||||
let errorMessage = null;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url, { method: "POST", body: formData });
|
const response = await fetch(url, { method: "POST", body: formData });
|
||||||
const contentType = response.headers.get("content-type");
|
const contentType = response.headers.get("content-type");
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
errorMessage = response.status;
|
|
||||||
if (response.status === 401) {
|
if (response.status === 401) {
|
||||||
showSessionExpiredPrompt();
|
showSessionExpiredPrompt();
|
||||||
|
trackFileProcessing(file, startTime, false, 'unauthorized');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (contentType && contentType.includes("application/json")) {
|
if (contentType && contentType.includes("application/json")) {
|
||||||
console.error("Throwing error banner, response was not okay");
|
console.error("Throwing error banner, response was not okay");
|
||||||
return handleJsonResponse(response);
|
const jsonResponse = await handleJsonResponse(response);
|
||||||
|
trackFileProcessing(file, startTime, false, jsonResponse?.error || 'unknown_error');
|
||||||
|
return jsonResponse;
|
||||||
}
|
}
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
@@ -148,7 +169,7 @@
|
|||||||
let filename = getFilenameFromContentDisposition(contentDisposition);
|
let filename = getFilenameFromContentDisposition(contentDisposition);
|
||||||
|
|
||||||
const blob = await response.blob();
|
const blob = await response.blob();
|
||||||
success = true;
|
trackFileProcessing(file, startTime, true, null);
|
||||||
|
|
||||||
if (contentType.includes("application/pdf") || contentType.includes("image/")) {
|
if (contentType.includes("application/pdf") || contentType.includes("image/")) {
|
||||||
clearFileInput();
|
clearFileInput();
|
||||||
@@ -158,30 +179,16 @@
|
|||||||
return handleResponse(blob, filename, false, isZip);
|
return handleResponse(blob, filename, false, isZip);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
success = false;
|
|
||||||
errorMessage = error.message;
|
|
||||||
console.error("Error in handleSingleDownload:", error);
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
const processingTime = performance.now() - startTime;
|
|
||||||
|
|
||||||
// Capture analytics
|
} catch (error) {
|
||||||
const pageCount = file && file.type === 'application/pdf' ? await getPDFPageCount(file) : null;
|
clearFileInput();
|
||||||
if(analyticsEnabled) {
|
console.error("Error in handleSingleDownload:", error);
|
||||||
posthog.capture('file_processing', {
|
trackFileProcessing(file, startTime, false, error.message);
|
||||||
success: success,
|
throw error;
|
||||||
file_type: file ? file.type || 'unknown' : 'unknown',
|
|
||||||
file_size: file ? file.size : 0,
|
|
||||||
processing_time: processingTime,
|
|
||||||
error_message: errorMessage,
|
|
||||||
pdf_pages: pageCount
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFilenameFromContentDisposition(contentDisposition) {
|
function getFilenameFromContentDisposition(contentDisposition) {
|
||||||
let filename;
|
let filename;
|
||||||
|
|
||||||
if (contentDisposition && contentDisposition.indexOf("attachment") !== -1) {
|
if (contentDisposition && contentDisposition.indexOf("attachment") !== -1) {
|
||||||
@@ -217,8 +224,7 @@
|
|||||||
if (considerViewOptions) {
|
if (considerViewOptions) {
|
||||||
if (downloadOption === "sameWindow") {
|
if (downloadOption === "sameWindow") {
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
window.location.href = url;
|
return { filename, blob, url };
|
||||||
return;
|
|
||||||
} else if (downloadOption === "newWindow") {
|
} else if (downloadOption === "newWindow") {
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
window.open(url, "_blank");
|
window.open(url, "_blank");
|
||||||
@@ -356,14 +362,14 @@
|
|||||||
if(editSectionElement){
|
if(editSectionElement){
|
||||||
editSectionElement.style.display = "none";
|
editSectionElement.style.display = "none";
|
||||||
}
|
}
|
||||||
let cropPdfCanvas = document.querySelector("#cropPdfCanvas");
|
let cropPdfCanvas = document.querySelector("#crop-pdf-canvas");
|
||||||
let overlayCanvas = document.querySelector("#overlayCanvas");
|
let overlayCanvas = document.querySelector("#overlayCanvas");
|
||||||
if(cropPdfCanvas && overlayCanvas){
|
if(cropPdfCanvas && overlayCanvas){
|
||||||
cropPdfCanvas.width = 0;
|
cropPdfCanvas.width = 0;
|
||||||
cropPdfCanvas.height = 0;
|
cropPdfCanvas.heigth = 0;
|
||||||
|
|
||||||
overlayCanvas.width = 0;
|
overlayCanvas.width = 0;
|
||||||
overlayCanvas.height = 0;
|
overlayCanvas.heigth = 0;
|
||||||
}
|
}
|
||||||
} else{
|
} else{
|
||||||
console.log("Disabled for 'Merge'");
|
console.log("Disabled for 'Merge'");
|
||||||
|
|||||||
@@ -4,87 +4,86 @@ const DraggableUtils = {
|
|||||||
nextId: 0,
|
nextId: 0,
|
||||||
pdfDoc: null,
|
pdfDoc: null,
|
||||||
pageIndex: 0,
|
pageIndex: 0,
|
||||||
elementAllPages: [],
|
|
||||||
documentsMap: new Map(),
|
documentsMap: new Map(),
|
||||||
lastInteracted: null,
|
lastInteracted: null,
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
interact(".draggable-canvas")
|
interact(".draggable-canvas")
|
||||||
.draggable({
|
.draggable({
|
||||||
listeners: {
|
listeners: {
|
||||||
move: (event) => {
|
move: (event) => {
|
||||||
const target = event.target;
|
const target = event.target;
|
||||||
const x = (parseFloat(target.getAttribute("data-bs-x")) || 0)
|
const x = (parseFloat(target.getAttribute("data-bs-x")) || 0)
|
||||||
+ event.dx;
|
+ event.dx;
|
||||||
const y = (parseFloat(target.getAttribute("data-bs-y")) || 0)
|
const y = (parseFloat(target.getAttribute("data-bs-y")) || 0)
|
||||||
+ event.dy;
|
+ event.dy;
|
||||||
|
|
||||||
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-x", x);
|
||||||
target.setAttribute("data-bs-y", y);
|
target.setAttribute("data-bs-y", y);
|
||||||
|
|
||||||
this.onInteraction(target);
|
this.onInteraction(target);
|
||||||
//update the last interacted element
|
//update the last interacted element
|
||||||
this.lastInteracted = event.target;
|
this.lastInteracted = event.target;
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
},
|
||||||
.resizable({
|
})
|
||||||
edges: { left: true, right: true, bottom: true, top: true },
|
.resizable({
|
||||||
listeners: {
|
edges: { left: true, right: true, bottom: true, top: true },
|
||||||
move: (event) => {
|
listeners: {
|
||||||
var target = event.target;
|
move: (event) => {
|
||||||
var x = parseFloat(target.getAttribute("data-bs-x")) || 0;
|
var target = event.target;
|
||||||
var y = parseFloat(target.getAttribute("data-bs-y")) || 0;
|
var x = parseFloat(target.getAttribute("data-bs-x")) || 0;
|
||||||
|
var y = parseFloat(target.getAttribute("data-bs-y")) || 0;
|
||||||
|
|
||||||
// check if control key is pressed
|
// check if control key is pressed
|
||||||
if (event.ctrlKey) {
|
if (event.ctrlKey) {
|
||||||
const aspectRatio = target.offsetWidth / target.offsetHeight;
|
const aspectRatio = target.offsetWidth / target.offsetHeight;
|
||||||
// preserve aspect ratio
|
// preserve aspect ratio
|
||||||
let width = event.rect.width;
|
let width = event.rect.width;
|
||||||
let height = event.rect.height;
|
let height = event.rect.height;
|
||||||
|
|
||||||
if (Math.abs(event.deltaRect.width) >= Math.abs(
|
if (Math.abs(event.deltaRect.width) >= Math.abs(
|
||||||
event.deltaRect.height)) {
|
event.deltaRect.height)) {
|
||||||
height = width / aspectRatio;
|
height = width / aspectRatio;
|
||||||
} else {
|
} else {
|
||||||
width = height * aspectRatio;
|
width = height * aspectRatio;
|
||||||
}
|
|
||||||
|
|
||||||
event.rect.width = width;
|
|
||||||
event.rect.height = height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
target.style.width = event.rect.width + "px";
|
event.rect.width = width;
|
||||||
target.style.height = event.rect.height + "px";
|
event.rect.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
// translate when resizing from top or left edges
|
target.style.width = event.rect.width + "px";
|
||||||
x += event.deltaRect.left;
|
target.style.height = event.rect.height + "px";
|
||||||
y += event.deltaRect.top;
|
|
||||||
|
|
||||||
target.style.transform = "translate(" + x + "px," + y + "px)";
|
// translate when resizing from top or left edges
|
||||||
|
x += event.deltaRect.left;
|
||||||
|
y += event.deltaRect.top;
|
||||||
|
|
||||||
target.setAttribute("data-bs-x", x);
|
target.style.transform = "translate(" + x + "px," + y + "px)";
|
||||||
target.setAttribute("data-bs-y", y);
|
|
||||||
target.textContent = Math.round(event.rect.width) + "\u00D7"
|
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);
|
+ Math.round(event.rect.height);
|
||||||
|
|
||||||
this.onInteraction(target);
|
this.onInteraction(target);
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
modifiers: [
|
modifiers: [
|
||||||
interact.modifiers.restrictSize({
|
interact.modifiers.restrictSize({
|
||||||
min: { width: 5, height: 5 },
|
min: {width: 5, height: 5},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
inertia: true,
|
inertia: true,
|
||||||
});
|
});
|
||||||
//Arrow key Support for Add-Image and Sign pages
|
//Arrow key Support for Add-Image and Sign pages
|
||||||
if (window.location.pathname.endsWith('sign') || window.location.pathname.endsWith('add-image')) {
|
if(window.location.pathname.endsWith('sign') || window.location.pathname.endsWith('add-image')) {
|
||||||
window.addEventListener('keydown', (event) => {
|
window.addEventListener('keydown', (event) => {
|
||||||
//Check for last interacted element
|
//Check for last interacted element
|
||||||
if (!this.lastInteracted) {
|
if (!this.lastInteracted){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Get the currently selected element
|
// Get the currently selected element
|
||||||
@@ -198,68 +197,6 @@ const DraggableUtils = {
|
|||||||
deleteAllDraggableCanvases() {
|
deleteAllDraggableCanvases() {
|
||||||
this.boxDragContainer.querySelectorAll(".draggable-canvas").forEach((el) => el.remove());
|
this.boxDragContainer.querySelectorAll(".draggable-canvas").forEach((el) => el.remove());
|
||||||
},
|
},
|
||||||
async addAllPagesDraggableCanvas(element) {
|
|
||||||
if (element) {
|
|
||||||
let currentPage = this.pageIndex
|
|
||||||
if (!this.elementAllPages.includes(element)) {
|
|
||||||
this.elementAllPages.push(element)
|
|
||||||
element.style.filter = 'sepia(1) hue-rotate(90deg) brightness(1.2)';
|
|
||||||
let newElement = {
|
|
||||||
"element": element,
|
|
||||||
"offsetWidth": element.width,
|
|
||||||
"offsetHeight": element.height
|
|
||||||
}
|
|
||||||
|
|
||||||
let pagesMap = this.documentsMap.get(this.pdfDoc);
|
|
||||||
|
|
||||||
if (!pagesMap) {
|
|
||||||
pagesMap = {};
|
|
||||||
this.documentsMap.set(this.pdfDoc, pagesMap);
|
|
||||||
}
|
|
||||||
let page = this.pageIndex
|
|
||||||
|
|
||||||
for (let pageIndex = 0; pageIndex < this.pdfDoc.numPages; pageIndex++) {
|
|
||||||
|
|
||||||
if (pagesMap[`${pageIndex}-offsetWidth`]) {
|
|
||||||
if (!pagesMap[pageIndex].includes(newElement)) {
|
|
||||||
pagesMap[pageIndex].push(newElement);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pagesMap[pageIndex] = []
|
|
||||||
pagesMap[pageIndex].push(newElement)
|
|
||||||
pagesMap[`${pageIndex}-offsetWidth`] = pagesMap[`${page}-offsetWidth`];
|
|
||||||
pagesMap[`${pageIndex}-offsetHeight`] = pagesMap[`${page}-offsetHeight`];
|
|
||||||
}
|
|
||||||
await this.goToPage(pageIndex)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const index = this.elementAllPages.indexOf(element);
|
|
||||||
if (index !== -1) {
|
|
||||||
this.elementAllPages.splice(index, 1);
|
|
||||||
}
|
|
||||||
element.style.filter = '';
|
|
||||||
let pagesMap = this.documentsMap.get(this.pdfDoc);
|
|
||||||
|
|
||||||
if (!pagesMap) {
|
|
||||||
pagesMap = {};
|
|
||||||
this.documentsMap.set(this.pdfDoc, pagesMap);
|
|
||||||
}
|
|
||||||
for (let pageIndex = 0; pageIndex < this.pdfDoc.numPages; pageIndex++) {
|
|
||||||
if (pagesMap[`${pageIndex}-offsetWidth`] && pageIndex != currentPage) {
|
|
||||||
const pageElements = pagesMap[pageIndex];
|
|
||||||
pageElements.forEach(elementPage => {
|
|
||||||
const elementIndex = pageElements.findIndex(elementPage => elementPage['element'].id === element.id);
|
|
||||||
if (elementIndex !== -1) {
|
|
||||||
pageElements.splice(elementIndex, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await this.goToPage(pageIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await this.goToPage(currentPage)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
deleteDraggableCanvas(element) {
|
deleteDraggableCanvas(element) {
|
||||||
if (element) {
|
if (element) {
|
||||||
//Check if deleted element is the last interacted
|
//Check if deleted element is the last interacted
|
||||||
@@ -304,7 +241,7 @@ const DraggableUtils = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const draggablesData = pagesMap[this.pageIndex];
|
const draggablesData = pagesMap[this.pageIndex];
|
||||||
if (draggablesData && Array.isArray(draggablesData)) {
|
if (draggablesData) {
|
||||||
draggablesData.forEach((draggableData) => this.boxDragContainer.appendChild(draggableData.element));
|
draggablesData.forEach((draggableData) => this.boxDragContainer.appendChild(draggableData.element));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,13 +273,6 @@ const DraggableUtils = {
|
|||||||
|
|
||||||
//return pdfCanvas.toDataURL();
|
//return pdfCanvas.toDataURL();
|
||||||
},
|
},
|
||||||
|
|
||||||
async goToPage(pageIndex) {
|
|
||||||
this.storePageContents();
|
|
||||||
await this.renderPage(this.pdfDoc, pageIndex);
|
|
||||||
this.loadPageContents();
|
|
||||||
},
|
|
||||||
|
|
||||||
async incrementPage() {
|
async incrementPage() {
|
||||||
if (this.pageIndex < this.pdfDoc.numPages - 1) {
|
if (this.pageIndex < this.pdfDoc.numPages - 1) {
|
||||||
this.storePageContents();
|
this.storePageContents();
|
||||||
@@ -358,7 +288,7 @@ const DraggableUtils = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
parseTransform(element) { },
|
parseTransform(element) {},
|
||||||
async getOverlayedPdfDocument() {
|
async getOverlayedPdfDocument() {
|
||||||
const pdfBytes = await this.pdfDoc.getData();
|
const pdfBytes = await this.pdfDoc.getData();
|
||||||
const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes, {
|
const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes, {
|
||||||
@@ -367,7 +297,6 @@ const DraggableUtils = {
|
|||||||
this.storePageContents();
|
this.storePageContents();
|
||||||
|
|
||||||
const pagesMap = this.documentsMap.get(this.pdfDoc);
|
const pagesMap = this.documentsMap.get(this.pdfDoc);
|
||||||
|
|
||||||
for (let pageIdx in pagesMap) {
|
for (let pageIdx in pagesMap) {
|
||||||
if (pageIdx.includes("offset")) {
|
if (pageIdx.includes("offset")) {
|
||||||
continue;
|
continue;
|
||||||
@@ -375,12 +304,10 @@ const DraggableUtils = {
|
|||||||
console.log(typeof pageIdx);
|
console.log(typeof pageIdx);
|
||||||
|
|
||||||
const page = pdfDocModified.getPage(parseInt(pageIdx));
|
const page = pdfDocModified.getPage(parseInt(pageIdx));
|
||||||
let draggablesData = pagesMap[pageIdx];
|
const draggablesData = pagesMap[pageIdx];
|
||||||
|
|
||||||
const offsetWidth = pagesMap[pageIdx + "-offsetWidth"];
|
const offsetWidth = pagesMap[pageIdx + "-offsetWidth"];
|
||||||
const offsetHeight = pagesMap[pageIdx + "-offsetHeight"];
|
const offsetHeight = pagesMap[pageIdx + "-offsetHeight"];
|
||||||
|
|
||||||
|
|
||||||
for (const draggableData of draggablesData) {
|
for (const draggableData of draggablesData) {
|
||||||
// embed the draggable canvas
|
// embed the draggable canvas
|
||||||
const draggableElement = draggableData.element;
|
const draggableElement = draggableData.element;
|
||||||
@@ -397,24 +324,6 @@ const DraggableUtils = {
|
|||||||
width: draggableData.offsetWidth,
|
width: draggableData.offsetWidth,
|
||||||
height: draggableData.offsetHeight,
|
height: draggableData.offsetHeight,
|
||||||
};
|
};
|
||||||
|
|
||||||
//Auxiliary variables
|
|
||||||
let widthAdjusted = page.getWidth();
|
|
||||||
let heightAdjusted = page.getHeight();
|
|
||||||
const rotation = page.getRotation();
|
|
||||||
|
|
||||||
//Normalizing angle
|
|
||||||
let normalizedAngle = rotation.angle % 360;
|
|
||||||
if (normalizedAngle < 0) {
|
|
||||||
normalizedAngle += 360;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Changing the page dimension if the angle is 90 or 270
|
|
||||||
if (normalizedAngle === 90 || normalizedAngle === 270) {
|
|
||||||
let widthTemp = widthAdjusted;
|
|
||||||
widthAdjusted = heightAdjusted;
|
|
||||||
heightAdjusted = widthTemp;
|
|
||||||
}
|
|
||||||
const draggablePositionRelative = {
|
const draggablePositionRelative = {
|
||||||
x: draggablePositionPixels.x / offsetWidth,
|
x: draggablePositionPixels.x / offsetWidth,
|
||||||
y: draggablePositionPixels.y / offsetHeight,
|
y: draggablePositionPixels.y / offsetHeight,
|
||||||
@@ -422,39 +331,22 @@ const DraggableUtils = {
|
|||||||
height: draggablePositionPixels.height / offsetHeight,
|
height: draggablePositionPixels.height / offsetHeight,
|
||||||
};
|
};
|
||||||
const draggablePositionPdf = {
|
const draggablePositionPdf = {
|
||||||
x: draggablePositionRelative.x * widthAdjusted,
|
x: draggablePositionRelative.x * page.getWidth(),
|
||||||
y: draggablePositionRelative.y * heightAdjusted,
|
y: draggablePositionRelative.y * page.getHeight(),
|
||||||
width: draggablePositionRelative.width * widthAdjusted,
|
width: draggablePositionRelative.width * page.getWidth(),
|
||||||
height: draggablePositionRelative.height * heightAdjusted,
|
height: draggablePositionRelative.height * page.getHeight(),
|
||||||
};
|
};
|
||||||
|
|
||||||
//Defining the image if the page has a 0-degree angle
|
|
||||||
let x = draggablePositionPdf.x
|
|
||||||
let y = heightAdjusted - draggablePositionPdf.y - draggablePositionPdf.height
|
|
||||||
|
|
||||||
|
|
||||||
//Defining the image position if it is at other angles
|
|
||||||
if (normalizedAngle === 90) {
|
|
||||||
x = draggablePositionPdf.y + draggablePositionPdf.height;
|
|
||||||
y = draggablePositionPdf.x;
|
|
||||||
} else if (normalizedAngle === 180) {
|
|
||||||
x = widthAdjusted - draggablePositionPdf.x;
|
|
||||||
y = draggablePositionPdf.y + draggablePositionPdf.height;
|
|
||||||
} else if (normalizedAngle === 270) {
|
|
||||||
x = heightAdjusted - draggablePositionPdf.y - draggablePositionPdf.height;
|
|
||||||
y = widthAdjusted - draggablePositionPdf.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw the image
|
// draw the image
|
||||||
page.drawImage(pdfImageObject, {
|
page.drawImage(pdfImageObject, {
|
||||||
x: x,
|
x: draggablePositionPdf.x,
|
||||||
y: y,
|
y: page.getHeight() - draggablePositionPdf.y - draggablePositionPdf.height,
|
||||||
width: draggablePositionPdf.width,
|
width: draggablePositionPdf.width,
|
||||||
height: draggablePositionPdf.height,
|
height: draggablePositionPdf.height,
|
||||||
rotate: rotation
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadPageContents();
|
this.loadPageContents();
|
||||||
return pdfDocModified;
|
return pdfDocModified;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ async function checkForUpdate() {
|
|||||||
document.getElementById("update-btn").style.display = "block";
|
document.getElementById("update-btn").style.display = "block";
|
||||||
}
|
}
|
||||||
if (updateLink !== null) {
|
if (updateLink !== null) {
|
||||||
document.getElementById("app-update").innerHTML = updateAvailable.replace("{0}", '<b>' + currentVersion + '</b>').replace("{1}", '<b>' + latestVersion + '</b>');
|
document.getElementById("app-update").innerText = updateAvailable.replace("{0}", '<b>' + currentVersion + '</b>').replace("{1}", '<b>' + latestVersion + '</b>');
|
||||||
if (updateLink.classList.contains("visually-hidden")) {
|
if (updateLink.classList.contains("visually-hidden")) {
|
||||||
updateLink.classList.remove("visually-hidden");
|
updateLink.classList.remove("visually-hidden");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,59 +1,27 @@
|
|||||||
function filterCards() {
|
function filterCards() {
|
||||||
var input = document.getElementById("searchBar");
|
var input = document.getElementById("searchBar");
|
||||||
var filter = input.value.toUpperCase();
|
var filter = input.value.toUpperCase();
|
||||||
|
var cards = document.querySelectorAll(".feature-card");
|
||||||
|
|
||||||
let featureGroups = document.querySelectorAll(".feature-group");
|
for (var i = 0; i < cards.length; i++) {
|
||||||
const collapsedGroups = getCollapsedGroups();
|
var card = cards[i];
|
||||||
|
var title = card.querySelector("h5.card-title").innerText;
|
||||||
|
var text = card.querySelector("p.card-text").innerText;
|
||||||
|
|
||||||
for (const featureGroup of featureGroups) {
|
// Get the navbar tags associated with the card
|
||||||
var cards = featureGroup.querySelectorAll(".feature-card");
|
var navbarItem = document.querySelector(`a.dropdown-item[href="${card.id}"]`);
|
||||||
|
var navbarTags = navbarItem ? navbarItem.getAttribute("data-bs-tags") : "";
|
||||||
|
|
||||||
let groupMatchesFilter = false;
|
var content = title + " " + text + " " + navbarTags;
|
||||||
for (var i = 0; i < cards.length; i++) {
|
|
||||||
var card = cards[i];
|
|
||||||
var title = card.querySelector("h5.card-title").innerText;
|
|
||||||
var text = card.querySelector("p.card-text").innerText;
|
|
||||||
|
|
||||||
// Get the navbar tags associated with the card
|
if (content.toUpperCase().indexOf(filter) > -1) {
|
||||||
var navbarItem = document.querySelector(`a.dropdown-item[href="${card.id}"]`);
|
card.style.display = "";
|
||||||
var navbarTags = navbarItem ? navbarItem.getAttribute("data-bs-tags") : "";
|
|
||||||
|
|
||||||
var content = title + " " + text + " " + navbarTags;
|
|
||||||
|
|
||||||
if (content.toUpperCase().indexOf(filter) > -1) {
|
|
||||||
card.style.display = "";
|
|
||||||
groupMatchesFilter = true;
|
|
||||||
} else {
|
|
||||||
card.style.display = "none";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!groupMatchesFilter) {
|
|
||||||
featureGroup.style.display = "none";
|
|
||||||
} else {
|
} else {
|
||||||
featureGroup.style.display = "";
|
card.style.display = "none";
|
||||||
resetOrTemporarilyExpandGroup(featureGroup, filter, collapsedGroups);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCollapsedGroups() {
|
|
||||||
return localStorage.getItem("collapsedGroups") ? JSON.parse(localStorage.getItem("collapsedGroups")) : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetOrTemporarilyExpandGroup(featureGroup, filterKeywords = "", collapsedGroups = []) {
|
|
||||||
const shouldResetCollapse = filterKeywords.trim() === "";
|
|
||||||
if (shouldResetCollapse) {
|
|
||||||
// Resetting the group's expand/collapse to its original state (as in collapsed groups)
|
|
||||||
const isCollapsed = collapsedGroups.indexOf(featureGroup.id) != -1;
|
|
||||||
expandCollapseToggle(featureGroup, !isCollapsed);
|
|
||||||
} else {
|
|
||||||
// Temporarily expands feature group without affecting the actual/stored collapsed groups
|
|
||||||
featureGroup.classList.remove("collapsed");
|
|
||||||
featureGroup.querySelector(".header-expand-button").classList.remove("collapsed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateFavoritesSection() {
|
function updateFavoritesSection() {
|
||||||
const favoritesContainer = document.getElementById("groupFavorites").querySelector(".feature-group-container");
|
const favoritesContainer = document.getElementById("groupFavorites").querySelector(".feature-group-container");
|
||||||
favoritesContainer.style.maxHeight = "none";
|
favoritesContainer.style.maxHeight = "none";
|
||||||
|
|||||||
@@ -1,21 +1,29 @@
|
|||||||
class DragDropManager {
|
class DragDropManager {
|
||||||
|
dragContainer;
|
||||||
|
wrapper;
|
||||||
|
pageDirection;
|
||||||
|
movePageTo;
|
||||||
|
pageDragging;
|
||||||
|
draggelEl;
|
||||||
|
draggedImageEl;
|
||||||
|
hoveredEl;
|
||||||
|
endInsertionElement;
|
||||||
|
|
||||||
constructor(id, wrapperId) {
|
constructor(id, wrapperId) {
|
||||||
this.dragContainer = document.getElementById(id);
|
this.dragContainer = document.getElementById(id);
|
||||||
this.pageDirection = document.documentElement.getAttribute("dir");
|
this.pageDirection = document.documentElement.getAttribute("dir");
|
||||||
this.wrapper = document.getElementById(wrapperId);
|
this.wrapper = document.getElementById(wrapperId);
|
||||||
this.pageDragging = false;
|
this.pageDragging = false;
|
||||||
this.hoveredEl = undefined;
|
this.hoveredEl = undefined;
|
||||||
|
this.draggelEl = undefined;
|
||||||
this.draggedImageEl = undefined;
|
this.draggedImageEl = undefined;
|
||||||
this.draggedEl = undefined;
|
|
||||||
this.selectedPageElements = []; // Store selected pages for multi-page mode
|
|
||||||
|
|
||||||
// Add CSS dynamically
|
var styleElement = document.createElement("link");
|
||||||
const styleElement = document.createElement("link");
|
|
||||||
styleElement.rel = "stylesheet";
|
styleElement.rel = "stylesheet";
|
||||||
styleElement.href = "css/dragdrop.css";
|
styleElement.href = "css/dragdrop.css";
|
||||||
|
|
||||||
document.head.appendChild(styleElement);
|
document.head.appendChild(styleElement);
|
||||||
|
|
||||||
// Create the endpoint element
|
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("drag-manager_endpoint");
|
div.classList.add("drag-manager_endpoint");
|
||||||
div.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-earmark-arrow-down" viewBox="0 0 16 16">
|
div.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-earmark-arrow-down" viewBox="0 0 16 16">
|
||||||
@@ -24,7 +32,6 @@ class DragDropManager {
|
|||||||
</svg>`;
|
</svg>`;
|
||||||
this.endInsertionElement = div;
|
this.endInsertionElement = div;
|
||||||
|
|
||||||
// Bind methods
|
|
||||||
this.startDraggingPage = this.startDraggingPage.bind(this);
|
this.startDraggingPage = this.startDraggingPage.bind(this);
|
||||||
this.onDragEl = this.onDragEl.bind(this);
|
this.onDragEl = this.onDragEl.bind(this);
|
||||||
this.stopDraggingPage = this.stopDraggingPage.bind(this);
|
this.stopDraggingPage = this.stopDraggingPage.bind(this);
|
||||||
@@ -33,41 +40,20 @@ class DragDropManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
startDraggingPage(div) {
|
startDraggingPage(div) {
|
||||||
if (window.selectPage) {
|
this.pageDragging = true;
|
||||||
// Multi-page drag logic
|
this.draggedEl = div;
|
||||||
this.selectedPageElements = window.selectedPages.map((index) => {
|
const img = div.querySelector("img");
|
||||||
const pageEl = document.getElementById(`page-container-${index}`);
|
div.classList.add("drag-manager_dragging");
|
||||||
if (pageEl) {
|
const imageSrc = img.src;
|
||||||
pageEl.initialTransform = pageEl.style.transform || "translate(0px, 0px)";
|
|
||||||
}
|
|
||||||
return pageEl;
|
|
||||||
}).filter(Boolean);
|
|
||||||
|
|
||||||
if (this.selectedPageElements.length === 0) return;
|
const imgEl = document.createElement("img");
|
||||||
|
imgEl.classList.add("dragged-img");
|
||||||
|
imgEl.src = imageSrc;
|
||||||
|
this.draggedImageEl = imgEl;
|
||||||
|
imgEl.style.visibility = "hidden";
|
||||||
|
imgEl.style.transform = `rotate(${img.style.rotate === "" ? "0deg" : img.style.rotate}) translate(-50%, -50%)`;
|
||||||
|
this.dragContainer.appendChild(imgEl);
|
||||||
|
|
||||||
this.pageDragging = true;
|
|
||||||
this.draggedImageEl = document.createElement("div");
|
|
||||||
this.draggedImageEl.classList.add("multidrag");
|
|
||||||
this.draggedImageEl.textContent = `${this.selectedPageElements.length} ${window.translations.dragDropMessage}`;
|
|
||||||
this.draggedImageEl.style.visibility = "hidden";
|
|
||||||
this.dragContainer.appendChild(this.draggedImageEl);
|
|
||||||
} else {
|
|
||||||
// Single-page drag logic
|
|
||||||
this.pageDragging = true;
|
|
||||||
this.draggedEl = div;
|
|
||||||
const img = div.querySelector("img");
|
|
||||||
div.classList.add("drag-manager_dragging");
|
|
||||||
|
|
||||||
const imgEl = document.createElement("img");
|
|
||||||
imgEl.classList.add("dragged-img");
|
|
||||||
imgEl.src = img.src;
|
|
||||||
imgEl.style.visibility = "hidden";
|
|
||||||
imgEl.style.transform = `rotate(${img.style.rotate === "" ? "0deg" : img.style.rotate}) translate(-50%, -50%)`;
|
|
||||||
this.draggedImageEl = imgEl;
|
|
||||||
this.dragContainer.appendChild(imgEl);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Common setup for both modes
|
|
||||||
window.addEventListener("mouseup", this.stopDraggingPage);
|
window.addEventListener("mouseup", this.stopDraggingPage);
|
||||||
window.addEventListener("mousemove", this.onDragEl);
|
window.addEventListener("mousemove", this.onDragEl);
|
||||||
this.wrapper.classList.add("drag-manager_dragging-container");
|
this.wrapper.classList.add("drag-manager_dragging-container");
|
||||||
@@ -88,43 +74,21 @@ class DragDropManager {
|
|||||||
this.wrapper.classList.remove("drag-manager_dragging-container");
|
this.wrapper.classList.remove("drag-manager_dragging-container");
|
||||||
this.wrapper.removeChild(this.endInsertionElement);
|
this.wrapper.removeChild(this.endInsertionElement);
|
||||||
window.removeEventListener("mouseup", this.stopDraggingPage);
|
window.removeEventListener("mouseup", this.stopDraggingPage);
|
||||||
|
this.draggedImageEl = undefined;
|
||||||
if (this.draggedImageEl) {
|
|
||||||
this.dragContainer.removeChild(this.draggedImageEl);
|
|
||||||
this.draggedImageEl = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window.selectPage) {
|
|
||||||
// Multi-page drop logic
|
|
||||||
if (!this.hoveredEl) {
|
|
||||||
this.selectedPageElements.forEach((pageEl) => {
|
|
||||||
pageEl.style.transform = pageEl.initialTransform || "translate(0px, 0px)";
|
|
||||||
pageEl.classList.remove("drag-manager_dragging");
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.selectedPageElements.forEach((pageEl) => {
|
|
||||||
pageEl.classList.remove("drag-manager_dragging");
|
|
||||||
if (this.hoveredEl === this.endInsertionElement) {
|
|
||||||
this.movePageTo(pageEl);
|
|
||||||
} else {
|
|
||||||
this.movePageTo(pageEl, this.hoveredEl);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.selectedPageElements = [];
|
|
||||||
window.resetPages()
|
|
||||||
} else {
|
|
||||||
// Single-page drop logic
|
|
||||||
if (!this.hoveredEl) return;
|
|
||||||
this.draggedEl.classList.remove("drag-manager_dragging");
|
|
||||||
if (this.hoveredEl === this.endInsertionElement) {
|
|
||||||
this.movePageTo(this.draggedEl);
|
|
||||||
} else {
|
|
||||||
this.movePageTo(this.draggedEl, this.hoveredEl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.pageDragging = false;
|
this.pageDragging = false;
|
||||||
|
this.draggedEl.classList.remove("drag-manager_dragging");
|
||||||
|
this.hoveredEl?.classList.remove("drag-manager_draghover");
|
||||||
|
this.dragContainer.childNodes.forEach((dragChild) => {
|
||||||
|
this.dragContainer.removeChild(dragChild);
|
||||||
|
});
|
||||||
|
if (!this.hoveredEl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.hoveredEl === this.endInsertionElement) {
|
||||||
|
this.movePageTo(this.draggedEl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.movePageTo(this.draggedEl, this.hoveredEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
setActions({ movePageTo }) {
|
setActions({ movePageTo }) {
|
||||||
|
|||||||
@@ -110,32 +110,31 @@ class PdfActionsManager {
|
|||||||
|
|
||||||
const moveUp = document.createElement("button");
|
const moveUp = document.createElement("button");
|
||||||
moveUp.classList.add("pdf-actions_move-left-button", "btn", "btn-secondary");
|
moveUp.classList.add("pdf-actions_move-left-button", "btn", "btn-secondary");
|
||||||
moveUp.innerHTML = `<span class="material-symbols-rounded">arrow_${leftDirection}_alt</span><span class="btn-tooltip">${window.translations.moveLeft}</span>`;
|
moveUp.innerHTML = `<span class="material-symbols-rounded">arrow_${leftDirection}_alt</span>`;
|
||||||
moveUp.onclick = this.moveUpButtonCallback;
|
moveUp.onclick = this.moveUpButtonCallback;
|
||||||
buttonContainer.appendChild(moveUp);
|
buttonContainer.appendChild(moveUp);
|
||||||
|
|
||||||
const moveDown = document.createElement("button");
|
const moveDown = document.createElement("button");
|
||||||
moveDown.classList.add("pdf-actions_move-right-button", "btn", "btn-secondary");
|
moveDown.classList.add("pdf-actions_move-right-button", "btn", "btn-secondary");
|
||||||
moveDown.innerHTML = `<span class="material-symbols-rounded">arrow_${rightDirection}_alt</span><span class="btn-tooltip">${window.translations.moveRight}</span>`;
|
moveDown.innerHTML = `<span class="material-symbols-rounded">arrow_${rightDirection}_alt</span>`;
|
||||||
moveDown.onclick = this.moveDownButtonCallback;
|
moveDown.onclick = this.moveDownButtonCallback;
|
||||||
buttonContainer.appendChild(moveDown);
|
buttonContainer.appendChild(moveDown);
|
||||||
|
|
||||||
|
|
||||||
const rotateCCW = document.createElement("button");
|
const rotateCCW = document.createElement("button");
|
||||||
rotateCCW.classList.add("btn", "btn-secondary");
|
rotateCCW.classList.add("btn", "btn-secondary");
|
||||||
rotateCCW.innerHTML = `<span class="material-symbols-rounded">rotate_left</span><span class="btn-tooltip">${window.translations.rotateLeft}</span>`;
|
rotateCCW.innerHTML = `<span class="material-symbols-rounded">rotate_left</span>`;
|
||||||
rotateCCW.onclick = this.rotateCCWButtonCallback;
|
rotateCCW.onclick = this.rotateCCWButtonCallback;
|
||||||
buttonContainer.appendChild(rotateCCW);
|
buttonContainer.appendChild(rotateCCW);
|
||||||
|
|
||||||
const rotateCW = document.createElement("button");
|
const rotateCW = document.createElement("button");
|
||||||
rotateCW.classList.add("btn", "btn-secondary");
|
rotateCW.classList.add("btn", "btn-secondary");
|
||||||
rotateCW.innerHTML = `<span class="material-symbols-rounded">rotate_right</span><span class="btn-tooltip">${window.translations.rotateRight}</span>`;
|
rotateCW.innerHTML = `<span class="material-symbols-rounded">rotate_right</span>`;
|
||||||
rotateCW.onclick = this.rotateCWButtonCallback;
|
rotateCW.onclick = this.rotateCWButtonCallback;
|
||||||
buttonContainer.appendChild(rotateCW);
|
buttonContainer.appendChild(rotateCW);
|
||||||
|
|
||||||
const deletePage = document.createElement("button");
|
const deletePage = document.createElement("button");
|
||||||
deletePage.classList.add("btn", "btn-danger");
|
deletePage.classList.add("btn", "btn-danger");
|
||||||
deletePage.innerHTML = `<span class="material-symbols-rounded">delete</span><span class="btn-tooltip"></span><span class="btn-tooltip">${window.translations.delete}</span>`;
|
deletePage.innerHTML = `<span class="material-symbols-rounded">delete</span>`;
|
||||||
deletePage.onclick = this.deletePageButtonCallback;
|
deletePage.onclick = this.deletePageButtonCallback;
|
||||||
buttonContainer.appendChild(deletePage);
|
buttonContainer.appendChild(deletePage);
|
||||||
|
|
||||||
@@ -190,19 +189,19 @@ class PdfActionsManager {
|
|||||||
|
|
||||||
const insertFileButton = document.createElement("button");
|
const insertFileButton = document.createElement("button");
|
||||||
insertFileButton.classList.add("btn", "btn-primary", "pdf-actions_insert-file-button");
|
insertFileButton.classList.add("btn", "btn-primary", "pdf-actions_insert-file-button");
|
||||||
insertFileButton.innerHTML = `<span class="material-symbols-rounded">add</span></span><span class="btn-tooltip">${window.translations.addFile}</span>`;
|
insertFileButton.innerHTML = `<span class="material-symbols-rounded">add</span>`;
|
||||||
insertFileButton.onclick = this.insertFileButtonCallback;
|
insertFileButton.onclick = this.insertFileButtonCallback;
|
||||||
insertFileButtonContainer.appendChild(insertFileButton);
|
insertFileButtonContainer.appendChild(insertFileButton);
|
||||||
|
|
||||||
const splitFileButton = document.createElement("button");
|
const splitFileButton = document.createElement("button");
|
||||||
splitFileButton.classList.add("btn", "btn-primary", "pdf-actions_split-file-button");
|
splitFileButton.classList.add("btn", "btn-primary", "pdf-actions_split-file-button");
|
||||||
splitFileButton.innerHTML = `<span class="material-symbols-rounded">cut</span></span><span class="btn-tooltip">${window.translations.split}</span>`;
|
splitFileButton.innerHTML = `<span class="material-symbols-rounded">cut</span>`;
|
||||||
splitFileButton.onclick = this.splitFileButtonCallback;
|
splitFileButton.onclick = this.splitFileButtonCallback;
|
||||||
insertFileButtonContainer.appendChild(splitFileButton);
|
insertFileButtonContainer.appendChild(splitFileButton);
|
||||||
|
|
||||||
const insertFileBlankButton = document.createElement("button");
|
const insertFileBlankButton = document.createElement("button");
|
||||||
insertFileBlankButton.classList.add("btn", "btn-primary", "pdf-actions_insert-file-blank-button");
|
insertFileBlankButton.classList.add("btn", "btn-primary", "pdf-actions_insert-file-blank-button");
|
||||||
insertFileBlankButton.innerHTML = `<span class="material-symbols-rounded">insert_page_break</span></span><span class="btn-tooltip">${window.translations.insertPageBreak}</span>`;
|
insertFileBlankButton.innerHTML = `<span class="material-symbols-rounded">insert_page_break</span>`;
|
||||||
insertFileBlankButton.onclick = this.insertFileBlankButtonCallback;
|
insertFileBlankButton.onclick = this.insertFileBlankButtonCallback;
|
||||||
insertFileButtonContainer.appendChild(insertFileBlankButton);
|
insertFileButtonContainer.appendChild(insertFileBlankButton);
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ class PdfContainer {
|
|||||||
this.updatePagesFromCSV = this.updatePagesFromCSV.bind(this);
|
this.updatePagesFromCSV = this.updatePagesFromCSV.bind(this);
|
||||||
this.addFilesBlankAll = this.addFilesBlankAll.bind(this)
|
this.addFilesBlankAll = this.addFilesBlankAll.bind(this)
|
||||||
this.removeAllElements = this.removeAllElements.bind(this);
|
this.removeAllElements = this.removeAllElements.bind(this);
|
||||||
this.resetPages = this.resetPages.bind(this);
|
|
||||||
|
|
||||||
this.pdfAdapters = pdfAdapters;
|
this.pdfAdapters = pdfAdapters;
|
||||||
|
|
||||||
@@ -56,7 +55,6 @@ class PdfContainer {
|
|||||||
window.updatePageNumbersAndCheckboxes = this.updatePageNumbersAndCheckboxes;
|
window.updatePageNumbersAndCheckboxes = this.updatePageNumbersAndCheckboxes;
|
||||||
window.addFilesBlankAll = this.addFilesBlankAll
|
window.addFilesBlankAll = this.addFilesBlankAll
|
||||||
window.removeAllElements = this.removeAllElements;
|
window.removeAllElements = this.removeAllElements;
|
||||||
window.resetPages = this.resetPages;
|
|
||||||
|
|
||||||
const filenameInput = document.getElementById("filename-input");
|
const filenameInput = document.getElementById("filename-input");
|
||||||
const downloadBtn = document.getElementById("export-button");
|
const downloadBtn = document.getElementById("export-button");
|
||||||
@@ -122,24 +120,12 @@ class PdfContainer {
|
|||||||
async addFilesFromFiles(files, nextSiblingElement) {
|
async addFilesFromFiles(files, nextSiblingElement) {
|
||||||
this.fileName = files[0].name;
|
this.fileName = files[0].name;
|
||||||
for (var i = 0; i < files.length; i++) {
|
for (var i = 0; i < files.length; i++) {
|
||||||
const startTime = Date.now();
|
|
||||||
let processingTime, errorMessage = null, pageCount = 0;
|
|
||||||
try {
|
|
||||||
const file = files[i];
|
const file = files[i];
|
||||||
if (file.type === "application/pdf") {
|
if (file.type === "application/pdf") {
|
||||||
const { renderer, pdfDocument } = await this.loadFile(file);
|
await this.addPdfFile(file, nextSiblingElement);
|
||||||
pageCount = renderer.pageCount || 0;
|
|
||||||
await this.addPdfFile(renderer, pdfDocument, nextSiblingElement);
|
|
||||||
} else if (file.type.startsWith("image/")) {
|
} else if (file.type.startsWith("image/")) {
|
||||||
await this.addImageFile(file, nextSiblingElement);
|
await this.addImageFile(file, nextSiblingElement);
|
||||||
}
|
}
|
||||||
processingTime = Date.now() - startTime;
|
|
||||||
this.captureFileProcessingEvent(true, file, processingTime, null, pageCount);
|
|
||||||
} catch (error) {
|
|
||||||
processingTime = Date.now() - startTime;
|
|
||||||
errorMessage = error.message || "Unknown error";
|
|
||||||
this.captureFileProcessingEvent(false, files[i], processingTime, errorMessage, pageCount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelectorAll(".enable-on-file").forEach((element) => {
|
document.querySelectorAll(".enable-on-file").forEach((element) => {
|
||||||
@@ -147,23 +133,6 @@ class PdfContainer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
captureFileProcessingEvent(success, file, processingTime, errorMessage, pageCount) {
|
|
||||||
try{
|
|
||||||
if(analyticsEnabled){
|
|
||||||
posthog.capture('file_processing', {
|
|
||||||
success,
|
|
||||||
file_type: file?.type || 'unknown',
|
|
||||||
file_size: file?.size || 0,
|
|
||||||
processing_time: processingTime,
|
|
||||||
error_message: errorMessage,
|
|
||||||
pdf_pages: pageCount,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}catch{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async addFilesBlank(nextSiblingElement) {
|
async addFilesBlank(nextSiblingElement) {
|
||||||
const pdfContent = `
|
const pdfContent = `
|
||||||
%PDF-1.4
|
%PDF-1.4
|
||||||
@@ -217,12 +186,14 @@ class PdfContainer {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async addPdfFile(renderer, pdfDocument, nextSiblingElement) {
|
async addPdfFile(file, nextSiblingElement) {
|
||||||
|
const { renderer, pdfDocument } = await this.loadFile(file);
|
||||||
|
|
||||||
for (var i = 0; i < renderer.pageCount; i++) {
|
for (var i = 0; i < renderer.pageCount; i++) {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
|
|
||||||
div.classList.add("page-container");
|
div.classList.add("page-container");
|
||||||
div.id = "page-container-" + (i + 1);
|
|
||||||
var img = document.createElement("img");
|
var img = document.createElement("img");
|
||||||
img.classList.add("page-image");
|
img.classList.add("page-image");
|
||||||
const imageSrc = await renderer.renderPage(i);
|
const imageSrc = await renderer.renderPage(i);
|
||||||
@@ -231,6 +202,7 @@ class PdfContainer {
|
|||||||
img.rend = renderer;
|
img.rend = renderer;
|
||||||
img.doc = pdfDocument;
|
img.doc = pdfDocument;
|
||||||
div.appendChild(img);
|
div.appendChild(img);
|
||||||
|
|
||||||
this.pdfAdapters.forEach((adapter) => {
|
this.pdfAdapters.forEach((adapter) => {
|
||||||
adapter.adapt?.(div);
|
adapter.adapt?.(div);
|
||||||
});
|
});
|
||||||
@@ -369,8 +341,8 @@ class PdfContainer {
|
|||||||
toggleSelectAll() {
|
toggleSelectAll() {
|
||||||
const checkboxes = document.querySelectorAll(".pdf-actions_checkbox");
|
const checkboxes = document.querySelectorAll(".pdf-actions_checkbox");
|
||||||
window.selectAll = !window.selectAll;
|
window.selectAll = !window.selectAll;
|
||||||
const selectIcon = document.getElementById("select-All-Container");
|
const selectIcon = document.getElementById("select-icon");
|
||||||
const deselectIcon = document.getElementById("deselect-All-Container");
|
const deselectIcon = document.getElementById("deselect-icon");
|
||||||
|
|
||||||
if (selectIcon.style.display === "none") {
|
if (selectIcon.style.display === "none") {
|
||||||
selectIcon.style.display = "inline";
|
selectIcon.style.display = "inline";
|
||||||
@@ -469,7 +441,7 @@ class PdfContainer {
|
|||||||
const selectedPagesList = document.getElementById("selected-pages-list");
|
const selectedPagesList = document.getElementById("selected-pages-list");
|
||||||
const selectedPagesInput = document.getElementById("csv-input");
|
const selectedPagesInput = document.getElementById("csv-input");
|
||||||
selectedPagesList.innerHTML = ""; // Clear the list
|
selectedPagesList.innerHTML = ""; // Clear the list
|
||||||
window.selectedPages.sort((a, b) => a - b);
|
|
||||||
window.selectedPages.forEach((page) => {
|
window.selectedPages.forEach((page) => {
|
||||||
const pageItem = document.createElement("div");
|
const pageItem = document.createElement("div");
|
||||||
pageItem.className = "page-item";
|
pageItem.className = "page-item";
|
||||||
@@ -729,31 +701,6 @@ class PdfContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resetPages() {
|
|
||||||
const pageContainers = this.pagesContainer.querySelectorAll(".page-container");
|
|
||||||
|
|
||||||
pageContainers.forEach((container, index) => {
|
|
||||||
container.id = "page-container-" + (index + 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
const checkboxes = document.querySelectorAll(".pdf-actions_checkbox");
|
|
||||||
window.selectAll = false;
|
|
||||||
const selectIcon = document.getElementById("select-All-Container");
|
|
||||||
const deselectIcon = document.getElementById("deselect-All-Container");
|
|
||||||
|
|
||||||
selectIcon.style.display = "inline";
|
|
||||||
deselectIcon.style.display = "none";
|
|
||||||
|
|
||||||
checkboxes.forEach((checkbox) => {
|
|
||||||
const pageNumber = Array.from(checkbox.parentNode.parentNode.children).indexOf(checkbox.parentNode) + 1;
|
|
||||||
|
|
||||||
const index = window.selectedPages.indexOf(pageNumber);
|
|
||||||
if (index !== -1) {
|
|
||||||
window.selectedPages.splice(index, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
window.toggleSelectPageVisibility();
|
|
||||||
}
|
|
||||||
|
|
||||||
setDownloadAttribute() {
|
setDownloadAttribute() {
|
||||||
this.downloadLink.setAttribute("download", this.fileName ? this.fileName : "managed.pdf");
|
this.downloadLink.setAttribute("download", this.fileName ? this.fileName : "managed.pdf");
|
||||||
@@ -798,7 +745,7 @@ class PdfContainer {
|
|||||||
const selectedPages = document.getElementById("selected-pages-display");
|
const selectedPages = document.getElementById("selected-pages-display");
|
||||||
selectedPages.classList.toggle("hidden", !window.selectPage);
|
selectedPages.classList.toggle("hidden", !window.selectPage);
|
||||||
const selectAll = document.getElementById("select-All-Container");
|
const selectAll = document.getElementById("select-All-Container");
|
||||||
selectAll.classList.toggle("hidden", !window.selectPage);
|
selectedPages.classList.toggle("hidden", !window.selectPage);
|
||||||
const exportSelected = document.getElementById("export-selected-button");
|
const exportSelected = document.getElementById("export-selected-button");
|
||||||
exportSelected.classList.toggle("hidden", !window.selectPage);
|
exportSelected.classList.toggle("hidden", !window.selectPage);
|
||||||
const selectPagesButton = document.getElementById("select-pages-button");
|
const selectPagesButton = document.getElementById("select-pages-button");
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ window.onload = function () {
|
|||||||
// Show search results as user types in search box
|
// Show search results as user types in search box
|
||||||
document.querySelector("#navbarSearchInput").addEventListener("input", function (e) {
|
document.querySelector("#navbarSearchInput").addEventListener("input", function (e) {
|
||||||
var searchText = e.target.value.trim().toLowerCase(); // Trim whitespace and convert to lowercase
|
var searchText = e.target.value.trim().toLowerCase(); // Trim whitespace and convert to lowercase
|
||||||
var items = document.querySelectorAll('a.dropdown-item[data-bs-tags]');
|
var items = document.querySelectorAll(".dropdown-item, .nav-link");
|
||||||
var resultsBox = document.querySelector("#searchResults");
|
var resultsBox = document.querySelector("#searchResults");
|
||||||
|
|
||||||
// Clear any previous results
|
// Clear any previous results
|
||||||
|
|||||||
@@ -19,30 +19,27 @@
|
|||||||
<form id="PDFToCSVForm" th:action="@{'/api/v1/convert/pdf/csv'}" method="post" enctype="multipart/form-data">
|
<form id="PDFToCSVForm" th:action="@{'/api/v1/convert/pdf/csv'}" method="post" enctype="multipart/form-data">
|
||||||
<input id="pageId" type="hidden" name="pageId">
|
<input id="pageId" type="hidden" name="pageId">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{PDFToCSV.submit}" id="submitBtn"></button>
|
<button type="submit" class="btn btn-primary" th:text="#{PDFToCSV.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
<p id="instruction-text" style="margin: 0; display: none" th:text="#{PDFToCSV.prompt}"></p>
|
<p id="instruction-text" style="margin: 0; display: none" th:text="#{PDFToCSV.prompt}"></p>
|
||||||
|
|
||||||
<div style="position: relative; width: auto;" id="canvasesContainer">
|
<div style="position: relative; display: inline-block;">
|
||||||
<div>
|
<div>
|
||||||
<div style="display:none ;margin: 3px;position: absolute;top: 0;width: 120px;justify-content:space-between;z-index: 10" id="pagination-button-container">
|
<div style="display:none ;margin: 3px;position: absolute;top: 0;width: 120px;justify-content:space-between;z-index: 10" id="pagination-button-container">
|
||||||
<button id='previous-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> < </button>
|
<button id='previous-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> < </button>
|
||||||
<button id='next-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> > </button>
|
<button id='next-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> > </button>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="cropPdfCanvas" style="width: 100%"></canvas>
|
<canvas id="crop-pdf-canvas" style="position: absolute; top: 0; left: 0; z-index: 1;"></canvas>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2; width: 100%"></canvas>
|
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2;"></canvas>
|
||||||
</div>
|
</div>
|
||||||
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
||||||
<script>
|
<script>
|
||||||
let pdfCanvas = document.getElementById('cropPdfCanvas');
|
let pdfCanvas = document.getElementById('crop-pdf-canvas');
|
||||||
let overlayCanvas = document.getElementById('overlayCanvas');
|
let overlayCanvas = document.getElementById('overlayCanvas');
|
||||||
let canvasesContainer = document.getElementById('canvasesContainer');
|
|
||||||
canvasesContainer.style.display = "none";
|
|
||||||
// let paginationBtnContainer = ;
|
// let paginationBtnContainer = ;
|
||||||
|
|
||||||
let context = pdfCanvas.getContext('2d');
|
let context = pdfCanvas.getContext('2d');
|
||||||
let overlayContext = overlayCanvas.getContext('2d');
|
|
||||||
|
|
||||||
let btn1Object = document.getElementById('previous-page-btn');
|
let btn1Object = document.getElementById('previous-page-btn');
|
||||||
let btn2Object = document.getElementById('next-page-btn');
|
let btn2Object = document.getElementById('next-page-btn');
|
||||||
@@ -63,8 +60,6 @@
|
|||||||
let rectWidth = 0;
|
let rectWidth = 0;
|
||||||
let rectHeight = 0;
|
let rectHeight = 0;
|
||||||
|
|
||||||
let timeId = null; // timeout id for resizing canvases event
|
|
||||||
|
|
||||||
btn1Object.addEventListener('click',function (e){
|
btn1Object.addEventListener('click',function (e){
|
||||||
if (currentPage !== 1) {
|
if (currentPage !== 1) {
|
||||||
currentPage = currentPage - 1;
|
currentPage = currentPage - 1;
|
||||||
@@ -107,13 +102,14 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function renderPageFromFile(file) {
|
fileInput.addEventListener('change', function(e) {
|
||||||
|
file = e.target.files[0];
|
||||||
if (file.type === 'application/pdf') {
|
if (file.type === 'application/pdf') {
|
||||||
let reader = new FileReader();
|
let reader = new FileReader();
|
||||||
reader.onload = function (ev) {
|
reader.onload = function(ev) {
|
||||||
let typedArray = new Uint8Array(reader.result);
|
let typedArray = new Uint8Array(reader.result);
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs';
|
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs';
|
||||||
pdfjsLib.getDocument(typedArray).promise.then(function (pdf) {
|
pdfjsLib.getDocument(typedArray).promise.then(function(pdf) {
|
||||||
pdfDoc = pdf;
|
pdfDoc = pdf;
|
||||||
totalPages = pdf.numPages;
|
totalPages = pdf.numPages;
|
||||||
renderPage(currentPage);
|
renderPage(currentPage);
|
||||||
@@ -121,37 +117,9 @@
|
|||||||
pageId.value = currentPage;
|
pageId.value = currentPage;
|
||||||
};
|
};
|
||||||
reader.readAsArrayBuffer(file);
|
reader.readAsArrayBuffer(file);
|
||||||
document.getElementById("pagination-button-container").style.display = "flex";
|
document.getElementById("pagination-button-container").style.display="flex";
|
||||||
document.getElementById("instruction-text").style.display = "block";
|
document.getElementById("instruction-text").style.display="block";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("resize", function() {
|
|
||||||
clearTimeout(timeId);
|
|
||||||
timeId = setTimeout(function () {
|
|
||||||
if (fileInput.files.length == 0) return;
|
|
||||||
let canvasesContainer = document.getElementById('canvasesContainer');
|
|
||||||
let containerRect = canvasesContainer.getBoundingClientRect();
|
|
||||||
|
|
||||||
context.clearRect(0, 0, pdfCanvas.width, pdfCanvas.height);
|
|
||||||
|
|
||||||
overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height);
|
|
||||||
|
|
||||||
pdfCanvas.width = containerRect.width;
|
|
||||||
pdfCanvas.height = containerRect.height;
|
|
||||||
|
|
||||||
overlayCanvas.width = containerRect.width;
|
|
||||||
overlayCanvas.height = containerRect.height;
|
|
||||||
|
|
||||||
let file = fileInput.files[0];
|
|
||||||
renderPageFromFile(file);
|
|
||||||
}, 1000);
|
|
||||||
});
|
|
||||||
|
|
||||||
fileInput.addEventListener('change', function(e) {
|
|
||||||
canvasesContainer.style.display = "block"; // set for visual purposes
|
|
||||||
file = e.target.files[0];
|
|
||||||
renderPageFromFile(file);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function renderPage(pageNumber) {
|
function renderPage(pageNumber) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<div class="col-md-9 bg-card">
|
<div class="col-md-9 bg-card">
|
||||||
<div class="tool-header">
|
<div class="tool-header">
|
||||||
<span class="material-symbols-rounded tool-header-icon organize">database</span>
|
<span class="material-symbols-rounded tool-header-icon organize">database</span>
|
||||||
<span class="tool-header-text" th:text="#{database.title}">Database Im-/Export</span>
|
<span class="tool-header-text" text="#{database.title}">Database Im-/Export</span>
|
||||||
</div>
|
</div>
|
||||||
<p th:if="${error}" th:text="#{'database.' + ${error}}" class="alert alert-danger text-center"></p>
|
<p th:if="${error}" th:text="#{'database.' + ${error}}" class="alert alert-danger text-center"></p>
|
||||||
<p th:if="${infoMessage}" th:text="#{'database.' + ${infoMessage}}" class="alert alert-success text-center"></p>
|
<p th:if="${infoMessage}" th:text="#{'database.' + ${infoMessage}}" class="alert alert-success text-center"></p>
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr th:each="backup : ${backupFiles}">
|
<tr th:each="backup : ${systemUpdate}">
|
||||||
<td th:text="${backup.fileName}"></td>
|
<td th:text="${backup.fileName}"></td>
|
||||||
<td th:text="${backup.formattedCreationDate}"></td>
|
<td th:text="${backup.formattedCreationDate}"></td>
|
||||||
<td th:text="${backup.formattedFileSize}"></td>
|
<td th:text="${backup.formattedFileSize}"></td>
|
||||||
@@ -41,11 +41,10 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<h6 class="text-end"><span class="badge bg-dark" th:text="${databaseVersion}">DB-Version</span></h6>
|
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<form th:action="@{'/api/v1/database/import-database'}" method="post" enctype="multipart/form-data" class="bg-card mt-3 mb-3">
|
<form th:action="@{'/api/v1/database/import-database'}" method="post" enctype="multipart/form-data" class="bg-card mt-3 mb-3">
|
||||||
<div style="background: var(--md-sys-color-error-container);border-radius: 2rem;" class="mb-3 p-3">
|
<div style="background: var(--md-sys-color-error-container);padding: .8rem;border-radius: 2rem;" class="mb-3">
|
||||||
<p th:text="#{database.info_1}"></p>
|
<p th:text="#{database.info_1}"></p>
|
||||||
<p th:text="#{database.info_2}"></p>
|
<p th:text="#{database.info_2}"></p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ca_CA"> <img th:src="@{'/images/flags/es-ct.svg'}" alt="icon" width="20" height="15"> Català</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ca_CA"> <img th:src="@{'/images/flags/es-ct.svg'}" alt="icon" width="20" height="15"> Català</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="zh_CN"> <img th:src="@{'/images/flags/cn.svg'}" alt="icon" width="20" height="15"> 简体中文</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="zh_CN"> <img th:src="@{'/images/flags/cn.svg'}" alt="icon" width="20" height="15"> 简体中文</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="zh_TW"> <img th:src="@{'/images/flags/tw.svg'}" alt="icon" width="20" height="15"> 繁體中文</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="zh_TW"> <img th:src="@{'/images/flags/tw.svg'}" alt="icon" width="20" height="15"> 繁體中文</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="az_AZ"> <img th:src="@{'/images/flags/az.svg'}" alt="icon" width="20" height="15"> Azərbaycan Dili</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="da_DK"> <img th:src="@{'/images/flags/dk.svg'}" alt="icon" width="20" height="15"> Dansk</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="da_DK"> <img th:src="@{'/images/flags/dk.svg'}" alt="icon" width="20" height="15"> Dansk</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="de_DE"> <img th:src="@{'/images/flags/de.svg'}" alt="icon" width="20" height="15"> Deutsch</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="de_DE"> <img th:src="@{'/images/flags/de.svg'}" alt="icon" width="20" height="15"> Deutsch</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="en_GB"> <img th:src="@{'/images/flags/gb.svg'}" alt="icon" width="20" height="15"> English (GB)</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="en_GB"> <img th:src="@{'/images/flags/gb.svg'}" alt="icon" width="20" height="15"> English (GB)</a>
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
<div>
|
<div>
|
||||||
<span th:utext="#{multiTool-advert.message(|/multi-tool|)}"></span>
|
<span th:utext="#{multiTool-advert.message(|/multi-tool|)}"></span>
|
||||||
<button id="closeMultiToolAdvert" style="position: absolute;
|
<button id="closeMultiToolAdvert" style="position: absolute;
|
||||||
inset-inline-end: 12px;
|
top: 10px;
|
||||||
inset-block-start: 10px;
|
right: 12px;
|
||||||
border: none;
|
border: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: white;
|
color: white;
|
||||||
@@ -16,13 +16,13 @@
|
|||||||
<style>
|
<style>
|
||||||
.multi-toolAdvert {
|
.multi-toolAdvert {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
margin-inline-start: 50%;
|
margin-left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
max-width: 52rem;
|
max-width: 52rem;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
background-color: var(--md-sys-color-surface-5);
|
background-color: var(--md-sys-color-surface-5);
|
||||||
border-radius: 2rem;
|
border-radius: 2rem;
|
||||||
padding-block: 10px;
|
padding: 10px 27px 10px 20px;
|
||||||
padding-inline: 20px 27px;
|
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
display: none;
|
display: none;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -43,7 +43,6 @@
|
|||||||
const closeBtn = document.getElementById('closeMultiToolAdvert');
|
const closeBtn = document.getElementById('closeMultiToolAdvert');
|
||||||
|
|
||||||
const cacheKey = `closeMultiToolAdvert_${window.location.pathname}`;
|
const cacheKey = `closeMultiToolAdvert_${window.location.pathname}`;
|
||||||
const isRTL = document.documentElement.dir === 'rtl';
|
|
||||||
|
|
||||||
if (localStorage.getItem(cacheKey) !== 'true') {
|
if (localStorage.getItem(cacheKey) !== 'true') {
|
||||||
advert.style.display = 'flex';
|
advert.style.display = 'flex';
|
||||||
@@ -53,13 +52,6 @@
|
|||||||
advert.style.display = 'none';
|
advert.style.display = 'none';
|
||||||
localStorage.setItem(cacheKey, 'true');
|
localStorage.setItem(cacheKey, 'true');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (isRTL) {
|
|
||||||
advert.style.transform = 'translateX(50%)'; // Flip direction for RTL
|
|
||||||
} else {
|
|
||||||
advert.style.transform = 'translateX(-50%)';
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
<div class="navbar-item col-lg-2 col-sm-6 py px-xl-1 px-2">
|
<div class="navbar-item col-lg-2 col-sm-6 py px-xl-1 px-2">
|
||||||
<h6 class="menu-title" th:text="#{navbar.sections.organize}"></h6>
|
<h6 class="menu-title" th:text="#{navbar.sections.organize}"></h6>
|
||||||
<div
|
<div
|
||||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('multi-tool', 'construction', 'home.multiTool.title', 'home.multiTool.desc', 'multiTool.tags', 'organize')}">
|
th:replace="~{fragments/navbarEntry :: navbarEntry ('compress-pdf', 'zoom_in_map', 'home.compressPdfs.title', 'home.compressPdfs.desc', 'compressPdfs.tags', 'advance')}">
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('merge-pdfs', 'add_to_photos', 'home.merge.title', 'home.merge.desc', 'merge.tags', 'organize')}">
|
th:replace="~{fragments/navbarEntry :: navbarEntry ('merge-pdfs', 'add_to_photos', 'home.merge.title', 'home.merge.desc', 'merge.tags', 'organize')}">
|
||||||
@@ -214,7 +214,7 @@
|
|||||||
<div class="navbar-item col-lg-2 col-sm-6 py px-xl-1 px-2">
|
<div class="navbar-item col-lg-2 col-sm-6 py px-xl-1 px-2">
|
||||||
<h6 class="menu-title" th:text="#{navbar.sections.advance}"></h6>
|
<h6 class="menu-title" th:text="#{navbar.sections.advance}"></h6>
|
||||||
<div
|
<div
|
||||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('compress-pdf', 'zoom_in_map', 'home.compressPdfs.title', 'home.compressPdfs.desc', 'compressPdfs.tags', 'advance')}">
|
th:replace="~{fragments/navbarEntry :: navbarEntry ('multi-tool', 'construction', 'home.multiTool.title', 'home.multiTool.desc', 'multiTool.tags', 'advance')}">
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('pipeline', 'family_history', 'home.pipeline.title', 'home.pipeline.desc', 'pipeline.tags', 'advance')}">
|
th:replace="~{fragments/navbarEntry :: navbarEntry ('pipeline', 'family_history', 'home.pipeline.title', 'home.pipeline.desc', 'pipeline.tags', 'advance')}">
|
||||||
@@ -330,7 +330,7 @@
|
|||||||
<span class="material-symbols-rounded" id="dark-mode-icon">
|
<span class="material-symbols-rounded" id="dark-mode-icon">
|
||||||
dark_mode
|
dark_mode
|
||||||
</span>
|
</span>
|
||||||
<span class="icon-text icon-hide" id="dark-mode-text" th:data-text="#{navbar.darkmode}" th:text="#{navbar.darkmode}"></span>
|
<span class="icon-text icon-hide tooltip-text" id="dark-mode-text" th:data-text="#{navbar.darkmode}" th:text="#{navbar.darkmode}"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
@@ -380,7 +380,7 @@
|
|||||||
<span class="material-symbols-rounded">
|
<span class="material-symbols-rounded">
|
||||||
settings
|
settings
|
||||||
</span>
|
</span>
|
||||||
<span class="icon-text icon-hide" th:data-text="#{navbar.settings}" th:text="#{navbar.settings}"></span>
|
<span class="icon-text icon-hide tooltip-text" th:data-text="#{navbar.settings}" th:text="#{navbar.settings}"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -411,7 +411,7 @@
|
|||||||
th:title="#{visitGithub}">
|
th:title="#{visitGithub}">
|
||||||
<img th:src="@{'/images/github.svg'}" alt="github">
|
<img th:src="@{'/images/github.svg'}" alt="github">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://hub.docker.com/r/stirlingtools/stirling-pdf" class="mx-1" role="button" target="_blank"th:title="#{seeDockerHub}">
|
<a href="https://hub.docker.com/r/frooodle/s-pdf" class="mx-1" role="button" target="_blank"th:title="#{seeDockerHub}">
|
||||||
<img th:src="@{'/images/docker.svg'}" alt="docker">
|
<img th:src="@{'/images/docker.svg'}" alt="docker">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://discord.gg/Cn8pWhQRxZ" class="mx-1" role="button" target="_blank" th:title="#{joinDiscord}">
|
<a href="https://discord.gg/Cn8pWhQRxZ" class="mx-1" role="button" target="_blank" th:title="#{joinDiscord}">
|
||||||
|
|||||||
@@ -31,79 +31,67 @@
|
|||||||
<span class="material-symbols-rounded">
|
<span class="material-symbols-rounded">
|
||||||
add
|
add
|
||||||
</span>
|
</span>
|
||||||
<span class="btn-tooltip" th:text="#{multiTool.addFile}"></span>
|
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-secondary enable-on-file" onclick="rotateAll(-90)" disabled>
|
<button class="btn btn-secondary enable-on-file" onclick="rotateAll(-90)" disabled>
|
||||||
<span class="material-symbols-rounded">
|
<span class="material-symbols-rounded">
|
||||||
rotate_left
|
rotate_left
|
||||||
</span>
|
</span>
|
||||||
<span class="btn-tooltip" th:text="#{multiTool.rotateLeft}"></span>
|
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-secondary enable-on-file" onclick="rotateAll(90)" disabled>
|
<button class="btn btn-secondary enable-on-file" onclick="rotateAll(90)" disabled>
|
||||||
<span class="material-symbols-rounded">
|
<span class="material-symbols-rounded">
|
||||||
rotate_right
|
rotate_right
|
||||||
</span>
|
</span>
|
||||||
<span class="btn-tooltip" th:text="#{multiTool.rotateRight}"></span>
|
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-secondary enable-on-file" onclick="splitAll()" disabled>
|
<button class="btn btn-secondary enable-on-file" onclick="splitAll()" disabled>
|
||||||
<span class="material-symbols-rounded">
|
<span class="material-symbols-rounded">
|
||||||
cut
|
cut
|
||||||
</span>
|
</span>
|
||||||
<span class="btn-tooltip" th:text="#{multiTool.split}"></span>
|
</button>
|
||||||
|
<button id="select-pages-container" class="btn btn-secondary enable-on-file"
|
||||||
|
th:title="#{multiTool.selectPages}" onclick="toggleSelectPageVisibility()" disabled>
|
||||||
|
<span id="select-pages-button" class="material-symbols-rounded">
|
||||||
|
event_list
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button id="select-All-Container" class="btn btn-secondary enable-on-file hidden"
|
||||||
|
onclick="toggleSelectAll()" disabled>
|
||||||
|
<span th:title="#{multiTool.selectAll}" class="material-symbols-rounded"
|
||||||
|
id="select-icon">select_all</span>
|
||||||
|
<span th:title="#{multiTool.deselectAll}" class="material-symbols-rounded" style="display: none;"
|
||||||
|
id="deselect-icon">deselect</span>
|
||||||
|
</button>
|
||||||
|
<div class=" button-container">
|
||||||
|
<button th:title="#{multiTool.deleteSelected}" id="delete-button" class="btn btn-danger hidden"
|
||||||
|
onclick="deleteSelected()">
|
||||||
|
<span class="material-symbols-rounded">delete</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button id="export-selected-button" class="btn btn-primary enable-on-file hidden"
|
||||||
|
onclick="exportPdf(true)" disabled>
|
||||||
|
<span th:title="#{multiTool.downloadSelected}" class="material-symbols-rounded">
|
||||||
|
file_save
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-secondary enable-on-file" onclick="addFilesBlankAll()" disabled>
|
<button class="btn btn-secondary enable-on-file" onclick="addFilesBlankAll()" disabled>
|
||||||
<span class="material-symbols-rounded">
|
<span class="material-symbols-rounded">
|
||||||
insert_page_break
|
insert_page_break
|
||||||
</span>
|
</span>
|
||||||
<span class="btn-tooltip" th:text="#{multiTool.insertPageBreak}"></span>
|
|
||||||
</button>
|
</button>
|
||||||
<button id="select-pages-container" class="btn btn-secondary enable-on-file"
|
<button id="export-button" class="btn btn-primary enable-on-file" onclick="exportPdf(false)" disabled>
|
||||||
onclick="toggleSelectPageVisibility()" disabled>
|
<span th:title="#{multiTool.downloadAll}" class="material-symbols-rounded">
|
||||||
<span id="select-pages-button" class="material-symbols-rounded">
|
download
|
||||||
event_list
|
|
||||||
</span>
|
</span>
|
||||||
<span class="btn-tooltip" th:text="#{multiTool.selectPages}"></span>
|
|
||||||
|
|
||||||
</button>
|
</button>
|
||||||
<button id="deselect-All-Container" class="btn btn-secondary enable-on-file hidden"
|
</div>
|
||||||
onclick="toggleSelectAll()" disabled>
|
<div class="mb-3">
|
||||||
<span class="material-symbols-rounded" id="deselect-icon">deselect</span>
|
<button type="button" id="resetFileInputBtn" class="btn btn-danger" onclick="removeAllElements()" th:text="#{reset}">Reset</button>
|
||||||
<span class="btn-tooltip" th:text="#{multiTool.deselectAll}"></span>
|
|
||||||
</button>
|
|
||||||
<button id="select-All-Container" class="btn btn-secondary enable-on-file hidden"
|
|
||||||
onclick="toggleSelectAll()" disabled>
|
|
||||||
<span class="material-symbols-rounded"
|
|
||||||
id="select-icon">select_all</span>
|
|
||||||
<span class="btn-tooltip" th:text="#{multiTool.selectAll}"></span>
|
|
||||||
</button>
|
|
||||||
<div class="button-container">
|
|
||||||
<button id="delete-button" class="btn btn-danger delete hidden" onclick="deleteSelected()">
|
|
||||||
<span class="material-symbols-rounded">delete</span>
|
|
||||||
<span class="btn-tooltip" th:text="#{multiTool.deleteSelected}"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div style="margin-left:auto">
|
|
||||||
<button id="export-selected-button" class="btn btn-primary enable-on-file hidden"
|
|
||||||
onclick="exportPdf(true)" disabled>
|
|
||||||
<span class="btn-tooltip" th:text="#{multiTool.downloadSelected}"></span>
|
|
||||||
<span class="material-symbols-rounded">
|
|
||||||
file_save
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
<button id="export-button" class="btn btn-primary enable-on-file" onclick="exportPdf(false)"
|
|
||||||
disabled>
|
|
||||||
<span class="material-symbols-rounded">
|
|
||||||
download
|
|
||||||
</span>
|
|
||||||
<span class="btn-tooltip" th:text="#{multiTool.downloadAll}"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="selected-pages-display" class="selected-pages-container hidden">
|
<div id="selected-pages-display" class="selected-pages-container hidden">
|
||||||
<div style="display:flex; height:3rem; margin-right:1rem">
|
<div style="display:flex; height:3rem; margin-right:1rem">
|
||||||
<h5 th:text="#{multiTool.selectedPages}" style="white-space: nowrap; margin-right: 1rem;">Selected
|
<h5 th:text="#{multiTool.selectedPages}" style="white-space: nowrap; margin-right: 1rem;">Selected
|
||||||
Pages</h5>
|
Pages</h5>
|
||||||
<input type="text" id="csv-input" class="form-control" style="height:2.5rem" placeholder="1,3,5-10" value="">
|
<input type="text" id="csv-input" class="form-control" style="height:2.5rem" placeholder="1,3,5-10"
|
||||||
|
value="">
|
||||||
</div>
|
</div>
|
||||||
<ul id="selected-pages-list" class="pages-list"></ul>
|
<ul id="selected-pages-list" class="pages-list"></ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -112,6 +100,13 @@
|
|||||||
<div class="multi-tool-container">
|
<div class="multi-tool-container">
|
||||||
<div class="d-flex flex-wrap" id="pages-container-wrapper">
|
<div class="d-flex flex-wrap" id="pages-container-wrapper">
|
||||||
<div id="pages-container">
|
<div id="pages-container">
|
||||||
|
<div class="page-container" th:each="file, status: ${fileList}"
|
||||||
|
th:id="'page-container-' + ${status.index}">
|
||||||
|
<div class="page-number-container">
|
||||||
|
<span th:text="${status.index + 1}"></span>
|
||||||
|
</div>
|
||||||
|
<img th:src="${file.imageUrl}" alt="File Page">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -129,21 +124,6 @@
|
|||||||
window.selectedPages = [];
|
window.selectedPages = [];
|
||||||
window.selectPage = false;
|
window.selectPage = false;
|
||||||
window.selectAll = false;
|
window.selectAll = false;
|
||||||
|
|
||||||
window.translations = {
|
|
||||||
rotateLeft: '[[#{multiTool.rotateLeft}]]',
|
|
||||||
rotateRight: '[[#{multiTool.rotateRight}]]',
|
|
||||||
moveLeft: '[[#{multiTool.moveLeft}]]',
|
|
||||||
moveRight: '[[#{multiTool.moveRight}]]',
|
|
||||||
delete: '[[#{multiTool.delete}]]',
|
|
||||||
split: '[[#{multiTool.split}]]',
|
|
||||||
addFile: '[[#{multiTool.addFile}]]',
|
|
||||||
insertPageBreak:'[[#{multiTool.insertPageBreak}]]',
|
|
||||||
dragDropMessage:'[[#{multiTool.dragDropMessage}]]'
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const csvInput = document.getElementById("csv-input");
|
const csvInput = document.getElementById("csv-input");
|
||||||
csvInput.addEventListener("keydown", function (event) {
|
csvInput.addEventListener("keydown", function (event) {
|
||||||
if (event.key === "Enter") {
|
if (event.key === "Enter") {
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||||
xmlns:th="https://www.thymeleaf.org">
|
<head>
|
||||||
|
|
||||||
<head>
|
|
||||||
<th:block th:insert="~{fragments/common :: head(title=#{sign.title}, header=#{sign.header})}"></th:block>
|
<th:block th:insert="~{fragments/common :: head(title=#{sign.title}, header=#{sign.header})}"></th:block>
|
||||||
<link rel="stylesheet" th:href="@{'/css/sign.css'}">
|
<link rel="stylesheet" th:href="@{'/css/sign.css'}">
|
||||||
|
|
||||||
<th:block th:each="font : ${fonts}">
|
<th:block th:each="font : ${fonts}">
|
||||||
<style th:inline="text">
|
<style th:inline="text">
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "[[${font.name}]]";
|
font-family: "[[${font.name}]]";
|
||||||
@@ -18,435 +16,372 @@
|
|||||||
cursive;
|
cursive;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
||||||
<script th:src="@{'/js/thirdParty/signature_pad.umd.min.js'}"></script>
|
<script th:src="@{'/js/thirdParty/signature_pad.umd.min.js'}"></script>
|
||||||
<script th:src="@{'/js/thirdParty/interact.min.js'}"></script>
|
<script th:src="@{'/js/thirdParty/interact.min.js'}"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="page-container">
|
<div id="page-container">
|
||||||
<div id="content-wrap">
|
<div id="content-wrap">
|
||||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||||
<br><br>
|
<br><br>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6 bg-card">
|
<div class="col-md-6 bg-card">
|
||||||
<div class="tool-header">
|
<div class="tool-header">
|
||||||
<span class="material-symbols-rounded tool-header-icon sign">signature</span>
|
<span class="material-symbols-rounded tool-header-icon sign">signature</span>
|
||||||
<span class="tool-header-text" th:text="#{sign.header}"></span>
|
<span class="tool-header-text" th:text="#{sign.header}"></span>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- pdf selector -->
|
|
||||||
<div
|
|
||||||
th:replace="~{fragments/common :: fileSelector(name='pdf-upload', multipleInputsForSingleRequest=false, disableMultipleFiles=true, accept='application/pdf')}">
|
|
||||||
</div>
|
|
||||||
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
|
||||||
<script>
|
|
||||||
let currentPreviewSrc = null;
|
|
||||||
|
|
||||||
function toggleSignatureView() {
|
|
||||||
const gridView = document.getElementById('gridView');
|
|
||||||
const listView = document.getElementById('listView');
|
|
||||||
const gridText = document.querySelector('.grid-view-text');
|
|
||||||
const listText = document.querySelector('.list-view-text');
|
|
||||||
|
|
||||||
if (gridView.style.display !== 'none') {
|
|
||||||
gridView.style.display = 'none';
|
|
||||||
listView.style.display = 'block';
|
|
||||||
gridText.style.display = 'none';
|
|
||||||
listText.style.display = 'inline';
|
|
||||||
} else {
|
|
||||||
gridView.style.display = 'block';
|
|
||||||
listView.style.display = 'none';
|
|
||||||
gridText.style.display = 'inline';
|
|
||||||
listText.style.display = 'none';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function previewSignature(element) {
|
|
||||||
const src = element.dataset.src;
|
|
||||||
currentPreviewSrc = src;
|
|
||||||
|
|
||||||
// Extract filename from the data source path
|
|
||||||
const filename = element.querySelector('.signature-list-name').textContent;
|
|
||||||
|
|
||||||
// Update preview modal
|
|
||||||
const previewImage = document.getElementById('previewImage');
|
|
||||||
const previewFileName = document.getElementById('previewFileName');
|
|
||||||
|
|
||||||
previewImage.src = src;
|
|
||||||
previewFileName.textContent = filename;
|
|
||||||
|
|
||||||
const modal = new bootstrap.Modal(document.getElementById('signaturePreview'));
|
|
||||||
modal.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
function addSignatureFromPreview() {
|
|
||||||
if (currentPreviewSrc) {
|
|
||||||
DraggableUtils.createDraggableCanvasFromUrl(currentPreviewSrc);
|
|
||||||
bootstrap.Modal.getInstance(document.getElementById('signaturePreview')).hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let originalFileName = '';
|
|
||||||
document.querySelector('input[name=pdf-upload]').addEventListener('change', async (event) => {
|
|
||||||
const file = event.target.files[0];
|
|
||||||
if (file) {
|
|
||||||
originalFileName = file.name.replace(/\.[^/.]+$/, "");
|
|
||||||
const pdfData = await file.arrayBuffer();
|
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs';
|
|
||||||
const pdfDoc = await pdfjsLib.getDocument({ data: pdfData }).promise;
|
|
||||||
await DraggableUtils.renderPage(pdfDoc, 0);
|
|
||||||
|
|
||||||
document.querySelectorAll(".show-on-file-selected").forEach(el => {
|
|
||||||
el.style.cssText = '';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
|
||||||
document.querySelectorAll(".show-on-file-selected").forEach(el => {
|
|
||||||
el.style.cssText = "display:none !important";
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<div class="tab-group show-on-file-selected">
|
|
||||||
<div class="tab-container" th:title="#{sign.upload}">
|
|
||||||
<div
|
|
||||||
th:replace="~{fragments/common :: fileSelector(name='image-upload', disableMultipleFiles=true, multipleInputsForSingleRequest=true, accept='image/*', inputText=#{imgPrompt})}">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab-container drawing-pad-container" th:title="#{sign.draw}">
|
<!-- pdf selector -->
|
||||||
<canvas id="drawing-pad-canvas"></canvas>
|
<div th:replace="~{fragments/common :: fileSelector(name='pdf-upload', multipleInputsForSingleRequest=false, disableMultipleFiles=true, accept='application/pdf')}"></div>
|
||||||
<br>
|
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
||||||
<button id="clear-signature" class="btn btn-outline-danger mt-2" onclick="signaturePad.clear()"
|
<script>
|
||||||
th:text="#{sign.clear}"></button>
|
let currentPreviewSrc = null;
|
||||||
<button id="save-signature" class="btn btn-outline-success mt-2" onclick="addDraggableFromPad()"
|
|
||||||
th:text="#{sign.add}"></button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="tab-container" th:title="#{sign.saved}">
|
function toggleSignatureView() {
|
||||||
<div class="saved-signatures-section" th:if="${not #lists.isEmpty(signatures)}">
|
const gridView = document.getElementById('gridView');
|
||||||
<!-- View Toggle Button -->
|
const listView = document.getElementById('listView');
|
||||||
<div class="view-toggle mb-3">
|
const gridText = document.querySelector('.grid-view-text');
|
||||||
<button class="btn btn-outline-secondary btn-sm" onclick="toggleSignatureView()">
|
const listText = document.querySelector('.list-view-text');
|
||||||
<span class="material-symbols-rounded grid-view-text">view_list</span>
|
|
||||||
<span class="material-symbols-rounded list-view-text" style="display: none;">grid_view</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Preview Modal -->
|
if (gridView.style.display !== 'none') {
|
||||||
<div class="modal fade" id="signaturePreview" tabindex="-1">
|
gridView.style.display = 'none';
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
listView.style.display = 'block';
|
||||||
<div class="modal-content">
|
gridText.style.display = 'none';
|
||||||
<div class="modal-header">
|
listText.style.display = 'inline';
|
||||||
<h5 class="modal-title"><span id="previewFileName"></span></h5>
|
} else {
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
gridView.style.display = 'block';
|
||||||
</div>
|
listView.style.display = 'none';
|
||||||
<div class="modal-body text-center">
|
gridText.style.display = 'inline';
|
||||||
<img id="previewImage" src="" alt="Signature Preview" style="max-width: 100%;">
|
listText.style.display = 'none';
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"
|
|
||||||
th:text="#{close}"></button>
|
|
||||||
<button type="button" class="btn btn-primary" onclick="addSignatureFromPreview()"
|
|
||||||
th:text="#{addToDoc}">Add to Document</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Grid View -->
|
|
||||||
<div id="gridView">
|
|
||||||
<!-- Personal Signatures -->
|
|
||||||
<div class="signature-category" th:if="${not #lists.isEmpty(signatures.?[category == 'Personal'])}">
|
|
||||||
<h5 th:text="#{sign.personalSigs}"></h5>
|
|
||||||
<div class="signature-grid">
|
|
||||||
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Personal'}" class="signature-item">
|
|
||||||
<img th:src="@{'/api/v1/general/sign/' + ${sig.fileName}}" th:alt="${sig.fileName}"
|
|
||||||
th:data-filename="${sig.fileName}" style="max-width: 200px; cursor: pointer;"
|
|
||||||
onclick="DraggableUtils.createDraggableCanvasFromUrl(this.src)" />
|
|
||||||
<div class="signature-name" th:text="${sig.fileName}"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Shared Signatures -->
|
|
||||||
<div class="signature-category" th:if="${not #lists.isEmpty(signatures.?[category == 'Shared'])}">
|
|
||||||
<h5 th:text="#{sign.sharedSigs}"></h5>
|
|
||||||
<div class="signature-grid">
|
|
||||||
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Shared'}" class="signature-item">
|
|
||||||
<img th:src="@{'/api/v1/general/sign/' + ${sig.fileName}}" th:alt="${sig.fileName}"
|
|
||||||
th:data-filename="${sig.fileName}" style="max-width: 200px; cursor: pointer;"
|
|
||||||
onclick="DraggableUtils.createDraggableCanvasFromUrl(this.src)" />
|
|
||||||
<div class="signature-name" th:text="${sig.fileName}"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- List View (Initially Hidden) -->
|
|
||||||
<div id="listView" style="display: none;">
|
|
||||||
<!-- Personal Signatures -->
|
|
||||||
<div class="signature-category" th:if="${not #lists.isEmpty(signatures.?[category == 'Personal'])}">
|
|
||||||
<h5 th:text="#{sign.personalSigs}"></h5>
|
|
||||||
<div class="signature-list">
|
|
||||||
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Personal'}"
|
|
||||||
class="signature-list-item" th:data-src="@{'/api/v1/general/sign/' + ${sig.fileName}}"
|
|
||||||
onclick="previewSignature(this)">
|
|
||||||
<div class="signature-list-info">
|
|
||||||
<span th:text="${sig.fileName}" class="signature-list-name"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Shared Signatures -->
|
|
||||||
<div class="signature-category" th:if="${not #lists.isEmpty(signatures.?[category == 'Shared'])}">
|
|
||||||
<h5 th:text="#{sign.sharedSigs}"></h5>
|
|
||||||
<div class="signature-list">
|
|
||||||
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Shared'}"
|
|
||||||
class="signature-list-item" th:data-src="@{'/api/v1/general/sign/' + ${sig.fileName}}"
|
|
||||||
onclick="previewSignature(this)">
|
|
||||||
<div class="signature-list-info">
|
|
||||||
<span th:text="${sig.fileName}" class="signature-list-name"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div th:if="${#lists.isEmpty(signatures)}" class="text-center p-3">
|
|
||||||
<p th:text="#{sign.noSavedSigs}">No saved signatures found</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="tab-container" th:title="#{sign.text}">
|
|
||||||
<label class="form-check-label" for="sigText" th:text="#{text}"></label>
|
|
||||||
<textarea class="form-control" id="sigText" name="sigText" rows="3"></textarea>
|
|
||||||
<label th:text="#{font}"></label>
|
|
||||||
<select class="form-control" name="font" id="font-select">
|
|
||||||
<option th:each="font : ${fonts}" th:value="${font.name}" th:text="${font.name}"
|
|
||||||
th:class="${font.name.toLowerCase()+'-font'}"></option>
|
|
||||||
</select>
|
|
||||||
<div class="margin-auto-parent">
|
|
||||||
<button id="save-text-signature" class="btn btn-outline-success mt-2 margin-center"
|
|
||||||
onclick="addDraggableFromText()" th:text="#{sign.add}"></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
const imageUpload = document.querySelector('input[name=image-upload]');
|
|
||||||
imageUpload.addEventListener('change', e => {
|
|
||||||
if (!e.target.files) return;
|
|
||||||
for (const imageFile of e.target.files) {
|
|
||||||
var reader = new FileReader();
|
|
||||||
reader.readAsDataURL(imageFile);
|
|
||||||
reader.onloadend = function (e) {
|
|
||||||
DraggableUtils.createDraggableCanvasFromUrl(e.target.result);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<script>
|
|
||||||
const signaturePadCanvas = document.getElementById('drawing-pad-canvas');
|
|
||||||
const signaturePad = new SignaturePad(signaturePadCanvas, {
|
|
||||||
minWidth: 1,
|
|
||||||
maxWidth: 2,
|
|
||||||
penColor: 'black',
|
|
||||||
});
|
|
||||||
|
|
||||||
function addDraggableFromPad() {
|
|
||||||
if (signaturePad.isEmpty()) return;
|
|
||||||
const startTime = Date.now();
|
|
||||||
const croppedDataUrl = getCroppedCanvasDataUrl(signaturePadCanvas);
|
|
||||||
console.log(Date.now() - startTime);
|
|
||||||
DraggableUtils.createDraggableCanvasFromUrl(croppedDataUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCroppedCanvasDataUrl(canvas) {
|
|
||||||
let originalCtx = canvas.getContext('2d');
|
|
||||||
let originalWidth = canvas.width;
|
|
||||||
let originalHeight = canvas.height;
|
|
||||||
let imageData = originalCtx.getImageData(0, 0, originalWidth, originalHeight);
|
|
||||||
|
|
||||||
let minX = originalWidth + 1, maxX = -1, minY = originalHeight + 1, maxY = -1, x = 0, y = 0, currentPixelColorValueIndex;
|
|
||||||
|
|
||||||
for (y = 0; y < originalHeight; y++) {
|
|
||||||
for (x = 0; x < originalWidth; x++) {
|
|
||||||
currentPixelColorValueIndex = (y * originalWidth + x) * 4;
|
|
||||||
let currentPixelAlphaValue = imageData.data[currentPixelColorValueIndex + 3];
|
|
||||||
if (currentPixelAlphaValue > 0) {
|
|
||||||
if (minX > x) minX = x;
|
|
||||||
if (maxX < x) maxX = x;
|
|
||||||
if (minY > y) minY = y;
|
|
||||||
if (maxY < y) maxY = y;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let croppedWidth = maxX - minX;
|
function previewSignature(element) {
|
||||||
let croppedHeight = maxY - minY;
|
const src = element.dataset.src;
|
||||||
if (croppedWidth < 0 || croppedHeight < 0) return null;
|
currentPreviewSrc = src;
|
||||||
let cuttedImageData = originalCtx.getImageData(minX, minY, croppedWidth, croppedHeight);
|
|
||||||
|
|
||||||
let croppedCanvas = document.createElement('canvas'),
|
// Extract filename from the data source path
|
||||||
croppedCtx = croppedCanvas.getContext('2d');
|
const filename = element.querySelector('.signature-list-name').textContent;
|
||||||
|
|
||||||
croppedCanvas.width = croppedWidth;
|
// Update preview modal
|
||||||
croppedCanvas.height = croppedHeight;
|
const previewImage = document.getElementById('previewImage');
|
||||||
croppedCtx.putImageData(cuttedImageData, 0, 0);
|
const previewFileName = document.getElementById('previewFileName');
|
||||||
|
|
||||||
return croppedCanvas.toDataURL();
|
previewImage.src = src;
|
||||||
}
|
previewFileName.textContent = filename;
|
||||||
|
|
||||||
function resizeCanvas() {
|
const modal = new bootstrap.Modal(document.getElementById('signaturePreview'));
|
||||||
var ratio = Math.max(window.devicePixelRatio || 1, 1);
|
modal.show();
|
||||||
var additionalFactor = 10;
|
|
||||||
|
|
||||||
signaturePadCanvas.width = signaturePadCanvas.offsetWidth * ratio * additionalFactor;
|
|
||||||
signaturePadCanvas.height = signaturePadCanvas.offsetHeight * ratio * additionalFactor;
|
|
||||||
signaturePadCanvas.getContext("2d").scale(ratio * additionalFactor, ratio * additionalFactor);
|
|
||||||
|
|
||||||
signaturePad.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
new IntersectionObserver((entries, observer) => {
|
|
||||||
if (entries.some(entry => entry.intersectionRatio > 0)) {
|
|
||||||
resizeCanvas();
|
|
||||||
}
|
}
|
||||||
}).observe(signaturePadCanvas);
|
|
||||||
|
|
||||||
new ResizeObserver(resizeCanvas).observe(signaturePadCanvas);
|
function addSignatureFromPreview() {
|
||||||
</script>
|
if (currentPreviewSrc) {
|
||||||
<script>
|
DraggableUtils.createDraggableCanvasFromUrl(currentPreviewSrc);
|
||||||
function addDraggableFromText() {
|
bootstrap.Modal.getInstance(document.getElementById('signaturePreview')).hide();
|
||||||
const sigText = document.getElementById('sigText').value;
|
}
|
||||||
const font = document.querySelector('select[name=font]').value;
|
}
|
||||||
const fontSize = 100;
|
|
||||||
|
|
||||||
const canvas = document.createElement('canvas');
|
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
ctx.font = `${fontSize}px ${font}`;
|
|
||||||
const textWidth = ctx.measureText(sigText).width;
|
|
||||||
const textHeight = fontSize;
|
|
||||||
|
|
||||||
let paragraphs = sigText.split(/\r?\n/);
|
let originalFileName = '';
|
||||||
|
document.querySelector('input[name=pdf-upload]').addEventListener('change', async (event) => {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
if (file) {
|
||||||
|
originalFileName = file.name.replace(/\.[^/.]+$/, "");
|
||||||
|
const pdfData = await file.arrayBuffer();
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs';
|
||||||
|
const pdfDoc = await pdfjsLib.getDocument({ data: pdfData }).promise;
|
||||||
|
await DraggableUtils.renderPage(pdfDoc, 0);
|
||||||
|
|
||||||
canvas.width = textWidth;
|
document.querySelectorAll(".show-on-file-selected").forEach(el => {
|
||||||
canvas.height = paragraphs.length * textHeight * 1.35; // for tails
|
el.style.cssText = '';
|
||||||
ctx.font = `${fontSize}px ${font}`;
|
});
|
||||||
|
}
|
||||||
ctx.textBaseline = 'top';
|
|
||||||
|
|
||||||
let y = 0;
|
|
||||||
|
|
||||||
paragraphs.forEach(paragraph => {
|
|
||||||
ctx.fillText(paragraph, 0, y);
|
|
||||||
y += fontSize;
|
|
||||||
});
|
});
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
document.querySelectorAll(".show-on-file-selected").forEach(el => {
|
||||||
|
el.style.cssText = "display:none !important";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
const dataURL = canvas.toDataURL();
|
<div class="tab-group show-on-file-selected">
|
||||||
DraggableUtils.createDraggableCanvasFromUrl(dataURL);
|
<div class="tab-container" th:title="#{sign.upload}">
|
||||||
}
|
<div th:replace="~{fragments/common :: fileSelector(name='image-upload', disableMultipleFiles=true, multipleInputsForSingleRequest=true, accept='image/*', inputText=#{imgPrompt})}"></div>
|
||||||
</script>
|
<script>
|
||||||
|
const imageUpload = document.querySelector('input[name=image-upload]');
|
||||||
|
imageUpload.addEventListener('change', e => {
|
||||||
|
if (!e.target.files) return;
|
||||||
|
for (const imageFile of e.target.files) {
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.readAsDataURL(imageFile);
|
||||||
|
reader.onloadend = function (e) {
|
||||||
|
DraggableUtils.createDraggableCanvasFromUrl(e.target.result);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- draggables box -->
|
<div class="tab-container drawing-pad-container" th:title="#{sign.draw}">
|
||||||
<div id="box-drag-container" class="show-on-file-selected">
|
<canvas id="drawing-pad-canvas"></canvas>
|
||||||
<canvas id="pdf-canvas"></canvas>
|
<br>
|
||||||
<script th:src="@{'/js/thirdParty/pdf-lib.min.js'}"></script>
|
<button id="clear-signature" class="btn btn-outline-danger mt-2" onclick="signaturePad.clear()" th:text="#{sign.clear}"></button>
|
||||||
<script th:src="@{'/js/draggable-utils.js'}"></script>
|
<button id="save-signature" class="btn btn-outline-success mt-2" onclick="addDraggableFromPad()" th:text="#{sign.add}"></button>
|
||||||
<div class="draggable-buttons-box ignore-rtl">
|
<script>
|
||||||
<button class="btn btn-outline-secondary"
|
const signaturePadCanvas = document.getElementById('drawing-pad-canvas');
|
||||||
onclick="DraggableUtils.deleteDraggableCanvas(DraggableUtils.getLastInteracted())">
|
const signaturePad = new SignaturePad(signaturePadCanvas, {
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash"
|
minWidth: 1,
|
||||||
viewBox="0 0 16 16">
|
maxWidth: 2,
|
||||||
<path
|
penColor: 'black',
|
||||||
d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5Zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5Zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6Z" />
|
});
|
||||||
<path
|
|
||||||
d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1ZM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118ZM2.5 3h11V2h-11v1Z" />
|
function addDraggableFromPad() {
|
||||||
</svg>
|
if (signaturePad.isEmpty()) return;
|
||||||
<span class="btn-tooltip" th:text="#{sign.delete}"></span>
|
const startTime = Date.now();
|
||||||
</button>
|
const croppedDataUrl = getCroppedCanvasDataUrl(signaturePadCanvas);
|
||||||
<button class="btn btn-outline-secondary"
|
console.log(Date.now() - startTime);
|
||||||
onclick="DraggableUtils.addAllPagesDraggableCanvas(DraggableUtils.getLastInteracted())">
|
DraggableUtils.createDraggableCanvasFromUrl(croppedDataUrl);
|
||||||
<span class="material-symbols-rounded">
|
}
|
||||||
content_copy
|
|
||||||
</span>
|
function getCroppedCanvasDataUrl(canvas) {
|
||||||
<span class="btn-tooltip" th:text="#{sign.addToAll}"></span>
|
let originalCtx = canvas.getContext('2d');
|
||||||
</button>
|
let originalWidth = canvas.width;
|
||||||
<button class="btn btn-outline-secondary" onclick="goToFirstOrLastPage(false)" style="margin-left:auto">
|
let originalHeight = canvas.height;
|
||||||
<span class="material-symbols-rounded">
|
let imageData = originalCtx.getImageData(0, 0, originalWidth, originalHeight);
|
||||||
keyboard_double_arrow_left
|
|
||||||
</span>
|
let minX = originalWidth + 1, maxX = -1, minY = originalHeight + 1, maxY = -1, x = 0, y = 0, currentPixelColorValueIndex;
|
||||||
<span class="btn-tooltip" th:text="#{sign.first}"></span>
|
|
||||||
</button>
|
for (y = 0; y < originalHeight; y++) {
|
||||||
<button class="btn btn-outline-secondary" id="incrementPage"
|
for (x = 0; x < originalWidth; x++) {
|
||||||
onclick="document.documentElement.getAttribute('dir')==='rtl' ? DraggableUtils.incrementPage() : DraggableUtils.decrementPage()">
|
currentPixelColorValueIndex = (y * originalWidth + x) * 4;
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
|
let currentPixelAlphaValue = imageData.data[currentPixelColorValueIndex + 3];
|
||||||
class="bi bi-chevron-left" viewBox="0 0 16 16">
|
if (currentPixelAlphaValue > 0) {
|
||||||
<path fill-rule="evenodd"
|
if (minX > x) minX = x;
|
||||||
d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z" />
|
if (maxX < x) maxX = x;
|
||||||
</svg>
|
if (minY > y) minY = y;
|
||||||
<span class="btn-tooltip" th:text="#{sign.previous}"></span>
|
if (maxY < y) maxY = y;
|
||||||
</button>
|
}
|
||||||
<button class="btn btn-outline-secondary" id="decrementPage"
|
}
|
||||||
onclick="document.documentElement.getAttribute('dir')==='rtl' ? DraggableUtils.decrementPage() : DraggableUtils.incrementPage()">
|
}
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
|
|
||||||
class="bi bi-chevron-right" viewBox="0 0 16 16">
|
let croppedWidth = maxX - minX;
|
||||||
<path fill-rule="evenodd"
|
let croppedHeight = maxY - minY;
|
||||||
d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z" />
|
if (croppedWidth < 0 || croppedHeight < 0) return null;
|
||||||
</svg>
|
let cuttedImageData = originalCtx.getImageData(minX, minY, croppedWidth, croppedHeight);
|
||||||
<span class="btn-tooltip" th:text="#{sign.next}"></span>
|
|
||||||
</button>
|
let croppedCanvas = document.createElement('canvas'),
|
||||||
<button class="btn btn-outline-secondary" onclick="goToFirstOrLastPage(true)">
|
croppedCtx = croppedCanvas.getContext('2d');
|
||||||
<span class="material-symbols-rounded">
|
|
||||||
keyboard_double_arrow_right
|
croppedCanvas.width = croppedWidth;
|
||||||
</span>
|
croppedCanvas.height = croppedHeight;
|
||||||
<span class="btn-tooltip" th:text="#{sign.last}"></span>
|
croppedCtx.putImageData(cuttedImageData, 0, 0);
|
||||||
</button>
|
|
||||||
|
return croppedCanvas.toDataURL();
|
||||||
|
}
|
||||||
|
|
||||||
|
function resizeCanvas() {
|
||||||
|
var ratio = Math.max(window.devicePixelRatio || 1, 1);
|
||||||
|
var additionalFactor = 10;
|
||||||
|
|
||||||
|
signaturePadCanvas.width = signaturePadCanvas.offsetWidth * ratio * additionalFactor;
|
||||||
|
signaturePadCanvas.height = signaturePadCanvas.offsetHeight * ratio * additionalFactor;
|
||||||
|
signaturePadCanvas.getContext("2d").scale(ratio * additionalFactor, ratio * additionalFactor);
|
||||||
|
|
||||||
|
signaturePad.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
new IntersectionObserver((entries, observer) => {
|
||||||
|
if (entries.some(entry => entry.intersectionRatio > 0)) {
|
||||||
|
resizeCanvas();
|
||||||
|
}
|
||||||
|
}).observe(signaturePadCanvas);
|
||||||
|
|
||||||
|
new ResizeObserver(resizeCanvas).observe(signaturePadCanvas);
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-container" th:title="#{sign.saved}">
|
||||||
|
<div class="saved-signatures-section" th:if="${not #lists.isEmpty(signatures)}">
|
||||||
|
<!-- View Toggle Button -->
|
||||||
|
<div class="view-toggle mb-3">
|
||||||
|
<button class="btn btn-outline-secondary btn-sm" onclick="toggleSignatureView()">
|
||||||
|
<span class="material-symbols-rounded grid-view-text">view_list</span>
|
||||||
|
<span class="material-symbols-rounded list-view-text" style="display: none;">grid_view</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Preview Modal -->
|
||||||
|
<div class="modal fade" id="signaturePreview" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title"><span id="previewFileName"></span></h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body text-center">
|
||||||
|
<img id="previewImage" src="" alt="Signature Preview" style="max-width: 100%;">
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" th:text="#{close}"></button>
|
||||||
|
<button type="button" class="btn btn-primary" onclick="addSignatureFromPreview()" th:text="#{addToDoc}">Add to Document</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Grid View -->
|
||||||
|
<div id="gridView">
|
||||||
|
<!-- Personal Signatures -->
|
||||||
|
<div class="signature-category" th:if="${not #lists.isEmpty(signatures.?[category == 'Personal'])}">
|
||||||
|
<h5 th:text="#{sign.personalSigs}"></h5>
|
||||||
|
<div class="signature-grid">
|
||||||
|
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Personal'}" class="signature-item">
|
||||||
|
<img th:src="@{'/api/v1/general/sign/' + ${sig.fileName}}" th:alt="${sig.fileName}" th:data-filename="${sig.fileName}" style="max-width: 200px; cursor: pointer;" onclick="DraggableUtils.createDraggableCanvasFromUrl(this.src)"/>
|
||||||
|
<div class="signature-name" th:text="${sig.fileName}"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Shared Signatures -->
|
||||||
|
<div class="signature-category" th:if="${not #lists.isEmpty(signatures.?[category == 'Shared'])}">
|
||||||
|
<h5 th:text="#{sign.sharedSigs}"></h5>
|
||||||
|
<div class="signature-grid">
|
||||||
|
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Shared'}" class="signature-item">
|
||||||
|
<img th:src="@{'/api/v1/general/sign/' + ${sig.fileName}}" th:alt="${sig.fileName}" th:data-filename="${sig.fileName}" style="max-width: 200px; cursor: pointer;" onclick="DraggableUtils.createDraggableCanvasFromUrl(this.src)"/>
|
||||||
|
<div class="signature-name" th:text="${sig.fileName}"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- List View (Initially Hidden) -->
|
||||||
|
<div id="listView" style="display: none;">
|
||||||
|
<!-- Personal Signatures -->
|
||||||
|
<div class="signature-category" th:if="${not #lists.isEmpty(signatures.?[category == 'Personal'])}">
|
||||||
|
<h5 th:text="#{sign.personalSigs}"></h5>
|
||||||
|
<div class="signature-list">
|
||||||
|
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Personal'}" class="signature-list-item" th:data-src="@{'/api/v1/general/sign/' + ${sig.fileName}}" onclick="previewSignature(this)">
|
||||||
|
<div class="signature-list-info">
|
||||||
|
<span th:text="${sig.fileName}" class="signature-list-name"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Shared Signatures -->
|
||||||
|
<div class="signature-category" th:if="${not #lists.isEmpty(signatures.?[category == 'Shared'])}">
|
||||||
|
<h5 th:text="#{sign.sharedSigs}"></h5>
|
||||||
|
<div class="signature-list">
|
||||||
|
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Shared'}" class="signature-list-item" th:data-src="@{'/api/v1/general/sign/' + ${sig.fileName}}" onclick="previewSignature(this)">
|
||||||
|
<div class="signature-list-info">
|
||||||
|
<span th:text="${sig.fileName}" class="signature-list-name"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div th:if="${#lists.isEmpty(signatures)}" class="text-center p-3">
|
||||||
|
<p th:text="#{sign.noSavedSigs}">No saved signatures found</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-container" th:title="#{sign.text}">
|
||||||
|
<label class="form-check-label" for="sigText" th:text="#{text}"></label>
|
||||||
|
<textarea class="form-control" id="sigText" name="sigText" rows="3"></textarea>
|
||||||
|
<label th:text="#{font}"></label>
|
||||||
|
<select class="form-control" name="font" id="font-select">
|
||||||
|
<option th:each="font : ${fonts}" th:value="${font.name}" th:text="${font.name}" th:class="${font.name.toLowerCase()+'-font'}"></option>
|
||||||
|
</select>
|
||||||
|
<div class="margin-auto-parent">
|
||||||
|
<button id="save-text-signature" class="btn btn-outline-success mt-2 margin-center" onclick="addDraggableFromText()" th:text="#{sign.add}"></button>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
function addDraggableFromText() {
|
||||||
|
const sigText = document.getElementById('sigText').value;
|
||||||
|
const font = document.querySelector('select[name=font]').value;
|
||||||
|
const fontSize = 100;
|
||||||
|
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
ctx.font = `${fontSize}px ${font}`;
|
||||||
|
const textWidth = ctx.measureText(sigText).width;
|
||||||
|
const textHeight = fontSize;
|
||||||
|
|
||||||
|
let paragraphs = sigText.split(/\r?\n/);
|
||||||
|
|
||||||
|
canvas.width = textWidth;
|
||||||
|
canvas.height = paragraphs.length * textHeight * 1.35; // for tails
|
||||||
|
ctx.font = `${fontSize}px ${font}`;
|
||||||
|
|
||||||
|
ctx.textBaseline = 'top';
|
||||||
|
|
||||||
|
let y = 0;
|
||||||
|
|
||||||
|
paragraphs.forEach(paragraph => {
|
||||||
|
ctx.fillText(paragraph, 0, y);
|
||||||
|
y += fontSize;
|
||||||
|
});
|
||||||
|
|
||||||
|
const dataURL = canvas.toDataURL();
|
||||||
|
DraggableUtils.createDraggableCanvasFromUrl(dataURL);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- draggables box -->
|
||||||
|
<div id="box-drag-container" class="show-on-file-selected">
|
||||||
|
<canvas id="pdf-canvas"></canvas>
|
||||||
|
<script th:src="@{'/js/thirdParty/pdf-lib.min.js'}"></script>
|
||||||
|
<script th:src="@{'/js/draggable-utils.js'}"></script>
|
||||||
|
<div class="draggable-buttons-box ignore-rtl">
|
||||||
|
<button class="btn btn-outline-secondary" onclick="DraggableUtils.deleteDraggableCanvas(DraggableUtils.getLastInteracted())">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16">
|
||||||
|
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5Zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5Zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6Z" />
|
||||||
|
<path d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1ZM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118ZM2.5 3h11V2h-11v1Z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-outline-secondary" onclick="document.documentElement.getAttribute('dir')==='rtl' ? DraggableUtils.incrementPage() : DraggableUtils.decrementPage()" style="margin-left:auto">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-left" viewBox="0 0 16 16">
|
||||||
|
<path fill-rule="evenodd" d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-outline-secondary" onclick="document.documentElement.getAttribute('dir')==='rtl' ? DraggableUtils.decrementPage() : DraggableUtils.incrementPage()">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-right" viewBox="0 0 16 16">
|
||||||
|
<path fill-rule="evenodd" d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- download button -->
|
||||||
|
<div class="margin-auto-parent">
|
||||||
|
<button id="download-pdf" class="btn btn-primary mb-2 show-on-file-selected margin-center" th:text="#{downloadPdf}"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById("download-pdf").addEventListener('click', async () => {
|
||||||
|
const modifiedPdf = await DraggableUtils.getOverlayedPdfDocument();
|
||||||
|
const modifiedPdfBytes = await modifiedPdf.save();
|
||||||
|
const blob = new Blob([modifiedPdfBytes], { type: 'application/pdf' });
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = URL.createObjectURL(blob);
|
||||||
|
link.download = originalFileName + '_signed.pdf';
|
||||||
|
link.click();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- download button -->
|
|
||||||
<div class="margin-auto-parent">
|
|
||||||
<button id="download-pdf" class="btn btn-primary mb-2 show-on-file-selected margin-center"
|
|
||||||
th:text="#{downloadPdf}"></button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
async function goToFirstOrLastPage(page) {
|
|
||||||
if (page) {
|
|
||||||
const lastPage = DraggableUtils.pdfDoc.numPages
|
|
||||||
await DraggableUtils.goToPage(lastPage - 1)
|
|
||||||
} else {
|
|
||||||
await DraggableUtils.goToPage(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.getElementById("download-pdf").addEventListener('click', async () => {
|
|
||||||
const modifiedPdf = await DraggableUtils.getOverlayedPdfDocument();
|
|
||||||
const modifiedPdfBytes = await modifiedPdf.save();
|
|
||||||
const blob = new Blob([modifiedPdfBytes], { type: 'application/pdf' });
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = URL.createObjectURL(blob);
|
|
||||||
link.download = originalFileName + '_signed.pdf';
|
|
||||||
link.click();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||||
</div>
|
</div>
|
||||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
<!-- Link the draggable.js file -->
|
||||||
</div>
|
<script th:src="@{'/js/draggable.js'}"></script>
|
||||||
<!-- Link the draggable.js file -->
|
</body>
|
||||||
<script th:src="@{'/js/draggable.js'}"></script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
2
test2.sh
2
test2.sh
@@ -49,7 +49,7 @@ check_health() {
|
|||||||
build_and_test() {
|
build_and_test() {
|
||||||
local version_tag="alpha"
|
local version_tag="alpha"
|
||||||
local dockerfile_name="./Dockerfile"
|
local dockerfile_name="./Dockerfile"
|
||||||
local image_base="stirlingtools/stirling-pdf"
|
local image_base="frooodle/s-pdf"
|
||||||
local security_suffix=""
|
local security_suffix=""
|
||||||
local docker_compose_base="./exampleYmlFiles/docker-compose-latest"
|
local docker_compose_base="./exampleYmlFiles/docker-compose-latest"
|
||||||
local compose_suffix=".yml"
|
local compose_suffix=".yml"
|
||||||
|
|||||||
Reference in New Issue
Block a user