Docfile commited on
Commit
efcc0c3
·
verified ·
1 Parent(s): b04d078

Update templates/viewer.html

Browse files
Files changed (1) hide show
  1. templates/viewer.html +152 -96
templates/viewer.html CHANGED
@@ -1,54 +1,79 @@
1
  <!DOCTYPE html>
2
- <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Visualiseur de PDF</title>
7
  <style>
8
- body {
9
- font-family: Arial, sans-serif;
 
 
 
 
 
 
 
 
 
10
  margin: 0;
11
  padding: 0;
 
 
 
 
 
 
 
12
  display: flex;
13
  flex-direction: column;
14
- min-height: 100vh;
15
  }
16
 
17
  #pdf-container {
18
- flex-grow: 1;
19
  overflow-y: auto;
20
- padding: 10px;
21
- background-color: #f8f9fa;
 
22
  }
23
 
24
  .page {
25
- margin-bottom: 20px;
26
- text-align: center;
27
- border: 1px solid #ddd;
28
  background-color: #fff;
29
- padding: 10px;
30
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
31
- position: relative; /* Pour positionner l'indicateur de chargement */
 
 
 
 
 
 
32
  }
33
 
34
  .page img {
35
- max-width: 100%;
36
  height: auto;
37
- display: block; /* Empêche l'espace sous l'image */
 
38
  }
39
 
40
  .page button {
41
- margin-top: 10px;
42
- padding: 10px 15px;
43
- background-color: #007bff;
44
  color: white;
45
  border: none;
46
- border-radius: 4px;
47
  cursor: pointer;
 
 
 
48
  }
49
 
50
  .page button:hover {
51
- background-color: #0056b3;
52
  }
53
 
54
  .loading-indicator {
@@ -56,87 +81,119 @@
56
  top: 50%;
57
  left: 50%;
58
  transform: translate(-50%, -50%);
59
- border: 4px solid rgba(0, 0, 0, 0.1);
60
- border-top: 4px solid #007bff;
 
 
61
  border-radius: 50%;
62
- width: 30px;
63
- height: 30px;
64
  animation: spin 1s linear infinite;
65
- display: none; /* Masqué par défaut */
66
  }
67
 
68
  .page.loading .loading-indicator {
69
- display: block; /* Affiché pendant le chargement */
70
  }
71
 
72
- .page .error-message {
73
- color: red;
74
- margin-top: 10px;
 
 
75
  }
76
 
77
  #navigation {
78
- background-color: #eee;
79
- padding: 10px;
80
- text-align: center;
81
- border-bottom: 1px solid #ccc;
82
- position: sticky; /* Barre de navigation fixe en haut */
83
  top: 0;
84
- z-index: 10; /* S'assurer qu'elle est au-dessus du contenu */
 
 
 
 
 
85
  }
86
 
87
  #navigation button {
88
- padding: 8px 12px;
89
- margin: 0 5px;
90
- background-color: #007bff;
91
  color: white;
92
  border: none;
93
- border-radius: 4px;
94
  cursor: pointer;
 
 
 
 
 
 
 
95
  }
96
 
97
  #navigation button:disabled {
98
- opacity: 0.6;
99
- cursor: default;
 
 
 
 
 
 
 
 
100
  }
101
 
102
  @keyframes spin {
103
- 0% { transform: translate(-50%, -50%) rotate(0deg); }
104
- 100% { transform: translate(-50%, -50%) rotate(360deg); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  }
106
  </style>
107
  </head>
108
  <body>
109
  <div id="navigation">
110
- <button id="prevPage">Page Précédente</button>
111
  <span>Page <span id="currentPage">1</span> / <span id="totalPagesSpan">210</span></span>
112
- <button id="nextPage">Page Suivante</button>
113
- <button id="gotoPage">Aller à la page:</button>
114
- <input type="number" id="pageNumberInput" min="1" value="1">
115
  </div>
116
 
117
- <div id="pdf-container">
118
- <!-- Les pages PDF seront ajoutées ici dynamiquement -->
119
- </div>
120
 
121
  <script>
122
- // Configuration de l'application
123
  const totalPages = 210;
124
- const lowResEndpoint = "/low_res/"; // Endpoint Flask pour les images basse résolution
125
- const highResEndpoint = "/high_res/"; // Endpoint Flask pour les images haute résolution
126
  let currentPage = 1;
127
 
128
- // Références aux éléments
129
- const pdfContainer = document.getElementById("pdf-container");
130
- const prevPageButton = document.getElementById("prevPage");
131
- const nextPageButton = document.getElementById("nextPage");
132
- const currentPageSpan = document.getElementById("currentPage");
133
- const totalPagesSpan = document.getElementById("totalPagesSpan");
134
- const gotoPageButton = document.getElementById("gotoPage");
135
- const pageNumberInput = document.getElementById("pageNumberInput");
 
136
 
137
- totalPagesSpan.textContent = totalPages;
138
 
139
- // Fonction pour afficher un indicateur de chargement
140
  function showLoadingIndicator(pageDiv) {
141
  const loadingIndicator = document.createElement('div');
142
  loadingIndicator.className = 'loading-indicator';
@@ -144,28 +201,28 @@
144
  pageDiv.classList.add('loading');
145
  }
146
 
147
- // Fonction pour masquer l'indicateur de chargement
148
  function hideLoadingIndicator(pageDiv) {
149
  const loadingIndicator = pageDiv.querySelector('.loading-indicator');
150
  if (loadingIndicator) {
151
- pageDiv.removeChild(loadingIndicator);
152
  }
153
  pageDiv.classList.remove('loading');
154
  }
155
 
156
- // Fonction pour charger une page spécifique
157
  function loadPage(pageNumber) {
158
  const pageDiv = document.getElementById(`page-${pageNumber}`);
159
- if (!pageDiv) return; // Vérifier si l'élément existe
160
 
161
  showLoadingIndicator(pageDiv);
162
 
163
  const img = new Image();
164
  img.src = `${lowResEndpoint}${pageNumber}`;
165
  img.alt = `Page ${pageNumber}`;
 
 
166
  img.onload = () => {
167
  hideLoadingIndicator(pageDiv);
168
- pageDiv.innerHTML = ''; // Nettoyer le contenu précédent
169
  pageDiv.appendChild(img);
170
 
171
  const button = document.createElement("button");
@@ -173,6 +230,7 @@
173
  button.onclick = () => downloadHighRes(pageNumber);
174
  pageDiv.appendChild(button);
175
  };
 
176
  img.onerror = () => {
177
  hideLoadingIndicator(pageDiv);
178
  const errorMsg = document.createElement('p');
@@ -182,13 +240,10 @@
182
  };
183
  }
184
 
185
- // Fonction pour télécharger une image en haute résolution
186
  function downloadHighRes(pageNumber) {
187
- const highResUrl = `${highResEndpoint}${pageNumber}`;
188
- window.open(highResUrl, "_blank");
189
  }
190
 
191
- // Initialisation de l'Intersection Observer pour le lazy loading
192
  function initLazyLoading() {
193
  const observer = new IntersectionObserver(entries => {
194
  entries.forEach(entry => {
@@ -198,50 +253,51 @@
198
  observer.unobserve(entry.target);
199
  }
200
  });
 
 
201
  });
202
 
203
  for (let pageNumber = 1; pageNumber <= totalPages; pageNumber++) {
204
  const pageDiv = document.createElement('div');
205
  pageDiv.className = 'page';
206
  pageDiv.id = `page-${pageNumber}`;
207
- pdfContainer.appendChild(pageDiv);
208
  observer.observe(pageDiv);
209
  }
210
  }
211
 
212
- // Gestion de la navigation
213
  function updateNavigation() {
214
- currentPageSpan.textContent = currentPage;
215
- prevPageButton.disabled = currentPage === 1;
216
- nextPageButton.disabled = currentPage === totalPages;
 
217
  }
218
 
219
  function goToPage(pageNumber) {
220
- if (pageNumber >= 1 && pageNumber <= totalPages) {
221
- currentPage = pageNumber;
222
- updateNavigation();
223
- const pageDiv = document.getElementById(`page-${pageNumber}`);
224
- if (pageDiv) {
225
- pageDiv.scrollIntoView({ behavior: 'smooth' });
226
- }
227
- }
228
  }
229
 
230
- prevPageButton.addEventListener('click', () => {
231
- goToPage(currentPage - 1);
232
-
 
 
233
  });
234
 
235
- nextPageButton.addEventListener('click', () => {
236
- goToPage(currentPage + 1);
237
- });
238
-
239
- gotoPageButton.addEventListener('click', () => {
240
- const pageNumber = parseInt(pageNumberInput.value);
241
- goToPage(pageNumber);
242
  });
243
 
244
- // Initialiser le visualiseur
245
  window.onload = () => {
246
  initLazyLoading();
247
  updateNavigation();
 
1
  <!DOCTYPE html>
2
+ <html lang="fr">
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Visualiseur de PDF</title>
7
  <style>
8
+ :root {
9
+ --primary-color: #007bff;
10
+ --primary-hover: #0056b3;
11
+ --bg-color: #f8f9fa;
12
+ --border-color: #ddd;
13
+ --text-color: #333;
14
+ --error-color: #dc3545;
15
+ }
16
+
17
+ * {
18
+ box-sizing: border-box;
19
  margin: 0;
20
  padding: 0;
21
+ }
22
+
23
+ body {
24
+ font-family: system-ui, -apple-system, sans-serif;
25
+ color: var(--text-color);
26
+ line-height: 1.6;
27
+ min-height: 100vh;
28
  display: flex;
29
  flex-direction: column;
 
30
  }
31
 
32
  #pdf-container {
33
+ flex: 1;
34
  overflow-y: auto;
35
+ padding: 20px;
36
+ background-color: var(--bg-color);
37
+ scroll-behavior: smooth;
38
  }
39
 
40
  .page {
41
+ max-width: 1000px;
42
+ margin: 0 auto 30px;
 
43
  background-color: #fff;
44
+ border-radius: 8px;
45
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
46
+ padding: 20px;
47
+ position: relative;
48
+ transition: transform 0.2s ease;
49
+ }
50
+
51
+ .page:hover {
52
+ transform: translateY(-2px);
53
  }
54
 
55
  .page img {
56
+ width: 100%;
57
  height: auto;
58
+ border-radius: 4px;
59
+ display: block;
60
  }
61
 
62
  .page button {
63
+ margin-top: 15px;
64
+ padding: 12px 20px;
65
+ background-color: var(--primary-color);
66
  color: white;
67
  border: none;
68
+ border-radius: 6px;
69
  cursor: pointer;
70
+ transition: background-color 0.2s ease;
71
+ font-weight: 500;
72
+ width: 100%;
73
  }
74
 
75
  .page button:hover {
76
+ background-color: var(--primary-hover);
77
  }
78
 
79
  .loading-indicator {
 
81
  top: 50%;
82
  left: 50%;
83
  transform: translate(-50%, -50%);
84
+ width: 40px;
85
+ height: 40px;
86
+ border: 3px solid rgba(0, 123, 255, 0.2);
87
+ border-top-color: var(--primary-color);
88
  border-radius: 50%;
 
 
89
  animation: spin 1s linear infinite;
90
+ display: none;
91
  }
92
 
93
  .page.loading .loading-indicator {
94
+ display: block;
95
  }
96
 
97
+ .error-message {
98
+ color: var(--error-color);
99
+ text-align: center;
100
+ margin-top: 15px;
101
+ font-weight: 500;
102
  }
103
 
104
  #navigation {
105
+ background-color: #fff;
106
+ padding: 15px;
107
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
108
+ position: sticky;
 
109
  top: 0;
110
+ z-index: 100;
111
+ display: flex;
112
+ align-items: center;
113
+ justify-content: center;
114
+ gap: 10px;
115
+ flex-wrap: wrap;
116
  }
117
 
118
  #navigation button {
119
+ padding: 8px 16px;
120
+ background-color: var(--primary-color);
 
121
  color: white;
122
  border: none;
123
+ border-radius: 6px;
124
  cursor: pointer;
125
+ transition: all 0.2s ease;
126
+ font-weight: 500;
127
+ }
128
+
129
+ #navigation button:hover:not(:disabled) {
130
+ background-color: var(--primary-hover);
131
+ transform: translateY(-1px);
132
  }
133
 
134
  #navigation button:disabled {
135
+ opacity: 0.5;
136
+ cursor: not-allowed;
137
+ }
138
+
139
+ #pageNumberInput {
140
+ width: 70px;
141
+ padding: 8px;
142
+ border: 1px solid var(--border-color);
143
+ border-radius: 4px;
144
+ text-align: center;
145
  }
146
 
147
  @keyframes spin {
148
+ to { transform: translate(-50%, -50%) rotate(360deg); }
149
+ }
150
+
151
+ @media (max-width: 600px) {
152
+ #navigation {
153
+ padding: 10px;
154
+ font-size: 14px;
155
+ }
156
+
157
+ #navigation button {
158
+ padding: 6px 12px;
159
+ }
160
+
161
+ .page {
162
+ margin: 0 10px 20px;
163
+ padding: 15px;
164
+ }
165
  }
166
  </style>
167
  </head>
168
  <body>
169
  <div id="navigation">
170
+ <button id="prevPage">Précédente</button>
171
  <span>Page <span id="currentPage">1</span> / <span id="totalPagesSpan">210</span></span>
172
+ <button id="nextPage">Suivante</button>
173
+ <button id="gotoPage">Aller à</button>
174
+ <input type="number" id="pageNumberInput" min="1" value="1" aria-label="Numéro de page">
175
  </div>
176
 
177
+ <div id="pdf-container"></div>
 
 
178
 
179
  <script>
 
180
  const totalPages = 210;
181
+ const lowResEndpoint = "/low_res/";
182
+ const highResEndpoint = "/high_res/";
183
  let currentPage = 1;
184
 
185
+ const elements = {
186
+ pdfContainer: document.getElementById("pdf-container"),
187
+ prevPageButton: document.getElementById("prevPage"),
188
+ nextPageButton: document.getElementById("nextPage"),
189
+ currentPageSpan: document.getElementById("currentPage"),
190
+ totalPagesSpan: document.getElementById("totalPagesSpan"),
191
+ gotoPageButton: document.getElementById("gotoPage"),
192
+ pageNumberInput: document.getElementById("pageNumberInput")
193
+ };
194
 
195
+ elements.totalPagesSpan.textContent = totalPages;
196
 
 
197
  function showLoadingIndicator(pageDiv) {
198
  const loadingIndicator = document.createElement('div');
199
  loadingIndicator.className = 'loading-indicator';
 
201
  pageDiv.classList.add('loading');
202
  }
203
 
 
204
  function hideLoadingIndicator(pageDiv) {
205
  const loadingIndicator = pageDiv.querySelector('.loading-indicator');
206
  if (loadingIndicator) {
207
+ loadingIndicator.remove();
208
  }
209
  pageDiv.classList.remove('loading');
210
  }
211
 
 
212
  function loadPage(pageNumber) {
213
  const pageDiv = document.getElementById(`page-${pageNumber}`);
214
+ if (!pageDiv) return;
215
 
216
  showLoadingIndicator(pageDiv);
217
 
218
  const img = new Image();
219
  img.src = `${lowResEndpoint}${pageNumber}`;
220
  img.alt = `Page ${pageNumber}`;
221
+ img.loading = "lazy";
222
+
223
  img.onload = () => {
224
  hideLoadingIndicator(pageDiv);
225
+ pageDiv.innerHTML = '';
226
  pageDiv.appendChild(img);
227
 
228
  const button = document.createElement("button");
 
230
  button.onclick = () => downloadHighRes(pageNumber);
231
  pageDiv.appendChild(button);
232
  };
233
+
234
  img.onerror = () => {
235
  hideLoadingIndicator(pageDiv);
236
  const errorMsg = document.createElement('p');
 
240
  };
241
  }
242
 
 
243
  function downloadHighRes(pageNumber) {
244
+ window.open(`${highResEndpoint}${pageNumber}`, "_blank");
 
245
  }
246
 
 
247
  function initLazyLoading() {
248
  const observer = new IntersectionObserver(entries => {
249
  entries.forEach(entry => {
 
253
  observer.unobserve(entry.target);
254
  }
255
  });
256
+ }, {
257
+ rootMargin: '50px'
258
  });
259
 
260
  for (let pageNumber = 1; pageNumber <= totalPages; pageNumber++) {
261
  const pageDiv = document.createElement('div');
262
  pageDiv.className = 'page';
263
  pageDiv.id = `page-${pageNumber}`;
264
+ elements.pdfContainer.appendChild(pageDiv);
265
  observer.observe(pageDiv);
266
  }
267
  }
268
 
 
269
  function updateNavigation() {
270
+ elements.currentPageSpan.textContent = currentPage;
271
+ elements.prevPageButton.disabled = currentPage === 1;
272
+ elements.nextPageButton.disabled = currentPage === totalPages;
273
+ elements.pageNumberInput.value = currentPage;
274
  }
275
 
276
  function goToPage(pageNumber) {
277
+ if (pageNumber >= 1 && pageNumber <= totalPages) {
278
+ currentPage = pageNumber;
279
+ updateNavigation();
280
+ document.getElementById(`page-${pageNumber}`)?.scrollIntoView({
281
+ behavior: 'smooth',
282
+ block: 'start'
283
+ });
284
+ }
285
  }
286
 
287
+ elements.prevPageButton.addEventListener('click', () => goToPage(currentPage - 1));
288
+ elements.nextPageButton.addEventListener('click', () => goToPage(currentPage + 1));
289
+ elements.gotoPageButton.addEventListener('click', () => {
290
+ const pageNumber = parseInt(elements.pageNumberInput.value);
291
+ if (pageNumber) goToPage(pageNumber);
292
  });
293
 
294
+ elements.pageNumberInput.addEventListener('keypress', (e) => {
295
+ if (e.key === 'Enter') {
296
+ const pageNumber = parseInt(e.target.value);
297
+ if (pageNumber) goToPage(pageNumber);
298
+ }
 
 
299
  });
300
 
 
301
  window.onload = () => {
302
  initLazyLoading();
303
  updateNavigation();