mirror of
				https://github.com/Frooodle/Stirling-PDF.git
				synced 2025-11-01 01:21:18 +01:00 
			
		
		
		
	Add on hover color to sign (#2059)
* Fixed layering issue with z-index, and added smoother transitions for… (#1996) Fixed layering issue with z-index, and added smoother transitions for signing Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> * Delete package-lock.json --------- Co-authored-by: Surya Karthikeyan Vijayalakshmi <108506548+SuryaKV101@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									04d5ae1912
								
							
						
					
					
						commit
						cae8cd0aa9
					
				@ -1,7 +1,9 @@
 | 
			
		||||
select#font-select,
 | 
			
		||||
select#font-select option {
 | 
			
		||||
  height: 60px; /* Adjust as needed */
 | 
			
		||||
  font-size: 30px; /* Adjust as needed */
 | 
			
		||||
  height: 60px;
 | 
			
		||||
  /* Adjust as needed */
 | 
			
		||||
  font-size: 30px;
 | 
			
		||||
  /* Adjust as needed */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.drawing-pad-container {
 | 
			
		||||
@ -13,10 +15,12 @@ select#font-select option {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 300px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#box-drag-container {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  margin: 20px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.draggable-buttons-box {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 0;
 | 
			
		||||
@ -24,16 +28,37 @@ select#font-select option {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  gap: 5px;
 | 
			
		||||
  z-index: 5;
 | 
			
		||||
}
 | 
			
		||||
.draggable-buttons-box > button {
 | 
			
		||||
  z-index: 10;
 | 
			
		||||
 | 
			
		||||
.draggable-buttons-box>button {
 | 
			
		||||
  z-index: 4;
 | 
			
		||||
  background-color: rgba(13, 110, 253, 0.1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.draggable-canvas {
 | 
			
		||||
  border: 1px solid red;
 | 
			
		||||
  border: 2px solid #3498db;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  touch-action: none;
 | 
			
		||||
  user-select: none;
 | 
			
		||||
  top: 0px;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  z-index: 100;
 | 
			
		||||
  cursor: grab;
 | 
			
		||||
  transition: transform 0.1s ease-out;
 | 
			
		||||
  background-color: rgba(52, 152, 219, 0.1);
 | 
			
		||||
  /* Light blue background */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.draggable-canvas:active {
 | 
			
		||||
  cursor: grabbing;
 | 
			
		||||
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
 | 
			
		||||
  /* Shadow on active drag */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.draggable-canvas:hover {
 | 
			
		||||
  border: 2px solid #2980b9;
 | 
			
		||||
  /* Darker border on hover */
 | 
			
		||||
  background-color: rgba(52, 152, 219, 0.2);
 | 
			
		||||
  /* Darken background on hover */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										36
									
								
								src/main/resources/static/js/draggable.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/main/resources/static/js/draggable.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
			
		||||
const draggableElement = document.querySelector('.draggable-canvas');
 | 
			
		||||
 | 
			
		||||
// Variables to store the current position of the draggable element
 | 
			
		||||
let offsetX, offsetY, isDragging = false;
 | 
			
		||||
 | 
			
		||||
draggableElement.addEventListener('mousedown', (e) => {
 | 
			
		||||
  // Get the offset when the mouse is clicked inside the element
 | 
			
		||||
  offsetX = e.clientX - draggableElement.getBoundingClientRect().left;
 | 
			
		||||
  offsetY = e.clientY - draggableElement.getBoundingClientRect().top;
 | 
			
		||||
 | 
			
		||||
  // Set isDragging to true
 | 
			
		||||
  isDragging = true;
 | 
			
		||||
 | 
			
		||||
  // Add event listeners for mouse movement and release
 | 
			
		||||
  document.addEventListener('mousemove', onMouseMove);
 | 
			
		||||
  document.addEventListener('mouseup', onMouseUp);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function onMouseMove(e) {
 | 
			
		||||
  if (isDragging) {
 | 
			
		||||
    // Calculate the new position of the element
 | 
			
		||||
    const left = e.clientX - offsetX;
 | 
			
		||||
    const top = e.clientY - offsetY;
 | 
			
		||||
 | 
			
		||||
    // Move the element by setting its style
 | 
			
		||||
    draggableElement.style.left = `${left}px`;
 | 
			
		||||
    draggableElement.style.top = `${top}px`;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function onMouseUp() {
 | 
			
		||||
  // Stop dragging and remove event listeners
 | 
			
		||||
  isDragging = false;
 | 
			
		||||
  document.removeEventListener('mousemove', onMouseMove);
 | 
			
		||||
  document.removeEventListener('mouseup', onMouseUp);
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +1,11 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
 | 
			
		||||
  <head>
 | 
			
		||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
 | 
			
		||||
  xmlns:th="https://www.thymeleaf.org">
 | 
			
		||||
 | 
			
		||||
<head>
 | 
			
		||||
  <th:block th:insert="~{fragments/common :: head(title=#{sign.title}, header=#{sign.header})}"></th:block>
 | 
			
		||||
  <link rel="stylesheet" th:href="@{'/css/sign.css'}">
 | 
			
		||||
 | 
			
		||||
  <th:block th:each="font : ${fonts}">
 | 
			
		||||
    <style th:inline="text">
 | 
			
		||||
      @font-face {
 | 
			
		||||
@ -11,18 +14,17 @@
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      #font-select option[value="[[${font.name}]]"] {
 | 
			
		||||
        font-family: "[[${font.name}]]", cursive;
 | 
			
		||||
      }
 | 
			
		||||
      #font-select option[value='/*[[${font.name}]]*/'] {
 | 
			
		||||
        font-family: '/*[[${font.name}]]*/', cursive;
 | 
			
		||||
        font-family: "[[${font.name}]]",
 | 
			
		||||
        cursive;
 | 
			
		||||
      }
 | 
			
		||||
    </style>
 | 
			
		||||
  </th:block>
 | 
			
		||||
 | 
			
		||||
  <script th:src="@{'/js/thirdParty/signature_pad.umd.min.js'}"></script>
 | 
			
		||||
  <script th:src="@{'/js/thirdParty/interact.min.js'}"></script>
 | 
			
		||||
  </head>
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
  <body>
 | 
			
		||||
<body>
 | 
			
		||||
  <div id="page-container">
 | 
			
		||||
    <div id="content-wrap">
 | 
			
		||||
      <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
 | 
			
		||||
@ -36,7 +38,9 @@
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <!-- pdf selector -->
 | 
			
		||||
              <div th:replace="~{fragments/common :: fileSelector(name='pdf-upload', multipleInputsForSingleRequest=false, disableMultipleFiles=true,  accept='application/pdf')}"></div>
 | 
			
		||||
            <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 originalFileName = '';
 | 
			
		||||
@ -45,30 +49,31 @@
 | 
			
		||||
                if (file) {
 | 
			
		||||
                  originalFileName = file.name.replace(/\.[^/.]+$/, "");
 | 
			
		||||
                  const pdfData = await file.arrayBuffer();
 | 
			
		||||
                    pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'
 | 
			
		||||
                  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', multipleInputsForSingleRequest=true, accept='image/*', inputText=#{imgPrompt})}"></div>
 | 
			
		||||
                <div
 | 
			
		||||
                  th:replace="~{fragments/common :: fileSelector(name='image-upload', multipleInputsForSingleRequest=true, accept='image/*', inputText=#{imgPrompt})}">
 | 
			
		||||
                </div>
 | 
			
		||||
                <script>
 | 
			
		||||
                  const imageUpload = document.querySelector('input[name=image-upload]');
 | 
			
		||||
                  imageUpload.addEventListener('change', e => {
 | 
			
		||||
                        if(!e.target.files) {
 | 
			
		||||
                          return;
 | 
			
		||||
                        }
 | 
			
		||||
                    if (!e.target.files) return;
 | 
			
		||||
                    for (const imageFile of e.target.files) {
 | 
			
		||||
                      var reader = new FileReader();
 | 
			
		||||
                      reader.readAsDataURL(imageFile);
 | 
			
		||||
@ -79,11 +84,14 @@
 | 
			
		||||
                  });
 | 
			
		||||
                </script>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
              <div class="tab-container drawing-pad-container" th:title="#{sign.draw}">
 | 
			
		||||
                <canvas id="drawing-pad-canvas"></canvas>
 | 
			
		||||
                <br>
 | 
			
		||||
                    <button id="clear-signature" class="btn btn-outline-danger mt-2" onclick="signaturePad.clear()" th:text="#{sign.clear}"></button>
 | 
			
		||||
                    <button id="save-signature" class="btn btn-outline-success mt-2" onclick="addDraggableFromPad()" th:text="#{sign.add}"></button>
 | 
			
		||||
                <button id="clear-signature" class="btn btn-outline-danger mt-2" onclick="signaturePad.clear()"
 | 
			
		||||
                  th:text="#{sign.clear}"></button>
 | 
			
		||||
                <button id="save-signature" class="btn btn-outline-success mt-2" onclick="addDraggableFromPad()"
 | 
			
		||||
                  th:text="#{sign.add}"></button>
 | 
			
		||||
                <script>
 | 
			
		||||
                  const signaturePadCanvas = document.getElementById('drawing-pad-canvas');
 | 
			
		||||
                  const signaturePad = new SignaturePad(signaturePadCanvas, {
 | 
			
		||||
@ -91,20 +99,20 @@
 | 
			
		||||
                    maxWidth: 2,
 | 
			
		||||
                    penColor: 'black',
 | 
			
		||||
                  });
 | 
			
		||||
 | 
			
		||||
                  function addDraggableFromPad() {
 | 
			
		||||
                    if (signaturePad.isEmpty()) return;
 | 
			
		||||
                    const startTime = Date.now();
 | 
			
		||||
                        const croppedDataUrl = getCroppedCanvasDataUrl(signaturePadCanvas)
 | 
			
		||||
                    const croppedDataUrl = getCroppedCanvasDataUrl(signaturePadCanvas);
 | 
			
		||||
                    console.log(Date.now() - startTime);
 | 
			
		||||
                    DraggableUtils.createDraggableCanvasFromUrl(croppedDataUrl);
 | 
			
		||||
                  }
 | 
			
		||||
                      function getCroppedCanvasDataUrl(canvas) {
 | 
			
		||||
                        // code is from: https://github.com/szimek/signature_pad/issues/49#issuecomment-1104035775
 | 
			
		||||
                        let originalCtx = canvas.getContext('2d');
 | 
			
		||||
 | 
			
		||||
                  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 imageData = originalCtx.getImageData(0, 0, originalWidth, originalHeight);
 | 
			
		||||
 | 
			
		||||
                    let minX = originalWidth + 1, maxX = -1, minY = originalHeight + 1, maxY = -1, x = 0, y = 0, currentPixelColorValueIndex;
 | 
			
		||||
 | 
			
		||||
@ -135,10 +143,8 @@
 | 
			
		||||
 | 
			
		||||
                    return croppedCanvas.toDataURL();
 | 
			
		||||
                  }
 | 
			
		||||
 | 
			
		||||
                  function resizeCanvas() {
 | 
			
		||||
                        // When zoomed out to less than 100%, for some very strange reason,
 | 
			
		||||
                        // some browsers report devicePixelRatio as less than 1
 | 
			
		||||
                        // and only part of the canvas is cleared then.
 | 
			
		||||
                    var ratio = Math.max(window.devicePixelRatio || 1, 1);
 | 
			
		||||
                    var additionalFactor = 10;
 | 
			
		||||
 | 
			
		||||
@ -146,31 +152,30 @@
 | 
			
		||||
                    signaturePadCanvas.height = signaturePadCanvas.offsetHeight * ratio * additionalFactor;
 | 
			
		||||
                    signaturePadCanvas.getContext("2d").scale(ratio * additionalFactor, ratio * additionalFactor);
 | 
			
		||||
 | 
			
		||||
                        // This library does not listen for canvas changes, so after the canvas is automatically
 | 
			
		||||
                        // cleared by the browser, SignaturePad#isEmpty might still return false, even though the
 | 
			
		||||
                        // canvas looks empty, because the internal data of this library wasn't cleared. To make sure
 | 
			
		||||
                        // that the state of this library is consistent with visual state of the canvas, you
 | 
			
		||||
                        // have to clear it manually.
 | 
			
		||||
                    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.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>
 | 
			
		||||
                  <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>
 | 
			
		||||
                  <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() {
 | 
			
		||||
@ -187,7 +192,7 @@
 | 
			
		||||
                    let paragraphs = sigText.split(/\r?\n/);
 | 
			
		||||
 | 
			
		||||
                    canvas.width = textWidth;
 | 
			
		||||
                        canvas.height = paragraphs.length * textHeight*1.35; //for tails
 | 
			
		||||
                    canvas.height = paragraphs.length * textHeight * 1.35; // for tails
 | 
			
		||||
                    ctx.font = `${fontSize}px ${font}`;
 | 
			
		||||
 | 
			
		||||
                    ctx.textBaseline = 'top';
 | 
			
		||||
@ -203,27 +208,6 @@
 | 
			
		||||
                    DraggableUtils.createDraggableCanvasFromUrl(dataURL);
 | 
			
		||||
                  }
 | 
			
		||||
                </script>
 | 
			
		||||
                    <script>
 | 
			
		||||
                      const sigTextInput = document.getElementById('sigText');
 | 
			
		||||
                      const fontSelect = document.getElementById('font-select');
 | 
			
		||||
 | 
			
		||||
                      const updateOptionTexts = () => {
 | 
			
		||||
                        Array.from(fontSelect.options).forEach(option => {
 | 
			
		||||
                          const fontName = option.value.replace(/-regular$/i, '');
 | 
			
		||||
                          option.text = sigTextInput.value || fontName;
 | 
			
		||||
                        });
 | 
			
		||||
                      }
 | 
			
		||||
 | 
			
		||||
                      sigTextInput.addEventListener('input', updateOptionTexts);
 | 
			
		||||
 | 
			
		||||
                      fontSelect.addEventListener('change', (e) => {
 | 
			
		||||
                        e.target.style.fontFamily = e.target.value;
 | 
			
		||||
                        updateOptionTexts();
 | 
			
		||||
                      });
 | 
			
		||||
 | 
			
		||||
                      // Manually trigger the change event
 | 
			
		||||
                      fontSelect.dispatchEvent(new Event('change'));
 | 
			
		||||
                  </script>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
@ -233,20 +217,31 @@
 | 
			
		||||
              <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"/>
 | 
			
		||||
                <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"/>
 | 
			
		||||
                <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"/>
 | 
			
		||||
                <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>
 | 
			
		||||
@ -254,11 +249,12 @@
 | 
			
		||||
 | 
			
		||||
            <!-- 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>
 | 
			
		||||
              <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() => {
 | 
			
		||||
              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' });
 | 
			
		||||
@ -272,7 +268,12 @@
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
 | 
			
		||||
  </div>
 | 
			
		||||
  </body>
 | 
			
		||||
 | 
			
		||||
  <!-- Link the draggable.js file -->
 | 
			
		||||
  <script src="/path/to/your/draggable.js"></script>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user