@osfarm/itineraire-technique 1.1.11 → 1.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/editor.html CHANGED
@@ -51,6 +51,7 @@
51
51
  <span class="visually-hidden">Autres options de chargement</span>
52
52
  </button>
53
53
  <ul class="dropdown-menu">
54
+ <li><a class="dropdown-item" href="#" onclick="showSaveAsModal()"><i class="fa fa-save" aria-hidden="true"></i> Enregistrer sous</a></li>
54
55
  <li><a class="dropdown-item" href="#" onclick="exportToJsonFile()"><i class="fa fa-download" aria-hidden="true"></i> Exporter</a></li>
55
56
  </ul>
56
57
  </div>
@@ -271,6 +272,47 @@
271
272
  </div>
272
273
  </div>
273
274
 
275
+ <!-- Save As Modal -->
276
+ <div class="modal fade" id="saveAsModal" tabindex="-1" aria-labelledby="saveAsModalLabel" aria-hidden="true">
277
+ <div class="modal-dialog">
278
+ <div class="modal-content">
279
+ <div class="modal-header">
280
+ <h5 class="modal-title" id="saveAsModalLabel">Enregistrer sous</h5>
281
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
282
+ </div>
283
+ <div class="modal-body">
284
+ <form>
285
+ <div class="mb-3 form-check">
286
+ <input type="checkbox" class="form-check-input" id="saveAsUseExistingPage">
287
+ <label class="form-check-label" for="saveAsUseExistingPage">
288
+ Enregistrer sous une page existante
289
+ </label>
290
+ </div>
291
+ <div class="mb-3" id="saveAsPageSelectContainer">
292
+ <label for="saveAsPageSelect" class="form-label">Page parent</label>
293
+ <select class="form-select" id="saveAsPageSelect" disabled>
294
+ <option value="">Sélectionner une page...</option>
295
+ </select>
296
+ <div class="form-text">Si non coché, le fichier sera enregistré sous "Non classified"</div>
297
+ </div>
298
+ <div class="mb-3">
299
+ <label for="saveAsFilename" class="form-label">Nom du fichier</label>
300
+
301
+ <div class="input-group mb-3">
302
+ <input type="text" class="form-control" id="saveAsFilename" placeholder="Nom du fichier (sans extension)">
303
+ <span class="input-group-text" id="basic-addon2">.json</span>
304
+ </div>
305
+ </div>
306
+ </form>
307
+ </div>
308
+ <div class="modal-footer">
309
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
310
+ <button type="button" class="btn btn-primary" id="saveAsConfirmBtn">Enregistrer</button>
311
+ </div>
312
+ </div>
313
+ </div>
314
+ </div>
315
+
274
316
  <!-- Modal -->
275
317
  <div class="modal fade" id="modalParams" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
276
318
  <div class="modal-dialog">
@@ -645,6 +687,17 @@
645
687
 
646
688
  we = new WikiEditor();
647
689
  we.loadPageFromURL();
690
+
691
+ // Set up Save As modal event listeners
692
+ $('#saveAsUseExistingPage').on('change', function() {
693
+ $('#saveAsPageSelect').prop('disabled', !this.checked);
694
+ });
695
+
696
+ $('#saveAsConfirmBtn').on('click', function() {
697
+ if (we) {
698
+ we.saveAs();
699
+ }
700
+ });
648
701
  } else {
649
702
  document.getElementById("WikiButtons").classList.add("d-none");
650
703
  document.getElementById("NonWikiButtons").classList.remove("d-none");
@@ -670,12 +723,20 @@
670
723
  }
671
724
  }
672
725
 
726
+ function showSaveAsModal() {
727
+ if (typeof we !== 'undefined') {
728
+ we.showSaveAsModal();
729
+ } else {
730
+ console.error('WikiEditor instance not available');
731
+ }
732
+ }
733
+
673
734
  class StepModel {
674
735
  constructor(step) {
675
736
  this.step = step; // keep a reference to the original object
676
737
 
677
738
  this.step.id = step.id ?? crypto.randomUUID();
678
- this.step.name = step.name ?? "Nouvelle culture";
739
+ this.step.name = step.name ?? "";
679
740
  this.step.color = step.color ?? "#0db3bf";
680
741
  this.step.startDate = step.startDate ? new Date(step.startDate) : new Date();
681
742
  this.step.endDate = step.endDate ? new Date(step.endDate) : new Date();
@@ -1013,7 +1074,9 @@
1013
1074
  if (this.textContent.trim() === "") {
1014
1075
  this.textContent = DEFAULT_TITLE;
1015
1076
  }
1077
+
1016
1078
  crops.title = this.textContent;
1079
+ crops.defaultTitle = false;
1017
1080
  });
1018
1081
  }
1019
1082
 
@@ -100,7 +100,7 @@ function showJsonErrorModal(errorMessage) {
100
100
  function showConfirmationModal(onConfirm) {
101
101
 
102
102
  if (crops?.steps.length === 0)
103
- return true;
103
+ return onConfirm();
104
104
 
105
105
  const confirmationModal = new bootstrap.Modal(document.getElementById('confirmationModal'));
106
106
  const confirmButton = document.getElementById('confirmImport');
@@ -53,7 +53,6 @@ class WikiEditor {
53
53
  const jsonErrorModal = new bootstrap.Modal(document.getElementById('jsonErrorModal'));
54
54
  jsonErrorModal.show();
55
55
  }
56
-
57
56
  }
58
57
  });
59
58
 
@@ -66,17 +65,13 @@ class WikiEditor {
66
65
  const self = this;
67
66
 
68
67
  if (!self.pageTitle) {
69
- alert("Aucun titre de page spécifié pour l'enregistrement.");
68
+ self.showSaveAsModal();
70
69
  return;
71
70
  }
72
71
 
73
72
  // If a page title is provided, save to that page
74
73
  self.savePageToWiki(self.pageTitle, JSON.stringify(crops, null, 2))
75
- .then(() => {
76
-
77
- // TODO : Also set a few semantic properties on the page, including the chart type, the geolocation, etc.
78
-
79
-
74
+ .then(async () => {
80
75
  alert("Itinéraire technique enregistré avec succès !");
81
76
  })
82
77
  .catch(err => {
@@ -151,6 +146,25 @@ class WikiEditor {
151
146
  }
152
147
  }
153
148
 
149
+
150
+ async getWikiUserPages(username) {
151
+ try {
152
+ // Encode the username for the URL
153
+ const encodedUsername = 'User:' + username;
154
+ const query = encodeURIComponent(`[[Page author::${encodedUsername}]][[A un type de page::+]]`);
155
+ const url = `/api.php?action=ask&query=${query}|sort=Modification date|order=desc&format=json`;
156
+
157
+ const response = await fetch(url, {
158
+ credentials: 'include'
159
+ });
160
+ const data = await response.json();
161
+ return data;
162
+ } catch (error) {
163
+ console.error("Error fetching wiki files:", error);
164
+ throw error;
165
+ }
166
+ }
167
+
154
168
  async loadFromWiki() {
155
169
  // Show the modal
156
170
  const modal = new bootstrap.Modal(document.getElementById('wikiFilesModal'));
@@ -220,4 +234,121 @@ class WikiEditor {
220
234
  }
221
235
  }
222
236
 
237
+ /**
238
+ * Show the Save As modal and handle the save as functionality
239
+ */
240
+ async showSaveAsModal() {
241
+ const self = this;
242
+
243
+ try {
244
+ // Get user info to check if logged in
245
+ const userInfo = await this.getWikiUserInfo();
246
+
247
+ if (!userInfo.id || userInfo.id === 0) {
248
+ alert('Vous devez être connecté au wiki pour utiliser cette fonctionnalité.');
249
+ return;
250
+ }
251
+
252
+ // Get user's existing pages
253
+ const pagesData = await this.getWikiUserPages(userInfo.name);
254
+
255
+ // Show the modal
256
+ const modal = new bootstrap.Modal(document.getElementById('saveAsModal'));
257
+ modal.show();
258
+
259
+ // Populate the select with user's pages
260
+ const pageSelect = $('#saveAsPageSelect');
261
+ pageSelect.empty();
262
+ pageSelect.append('<option value="">Sélectionner une page...</option>');
263
+
264
+ if (pagesData.query?.results) {
265
+ for (const [pageTitle, pageData] of Object.entries(pagesData.query.results)) {
266
+ const displayTitle = pageData.displaytitle || pageTitle;
267
+ pageSelect.append(`<option value="${pageTitle}">${displayTitle}</option>`);
268
+ }
269
+ }
270
+
271
+ // Set default filename from title if it's been changed
272
+ const filenameInput = $('#saveAsFilename');
273
+ const currentTitle = crops.title || '';
274
+ if (crops.defaultTitle === false) {
275
+ filenameInput.val(currentTitle);
276
+ } else {
277
+ filenameInput.val('');
278
+ }
279
+
280
+ } catch (error) {
281
+ console.error("Error showing save as modal:", error);
282
+ alert('Erreur lors du chargement des données utilisateur.');
283
+ }
284
+ }
285
+
286
+ /**
287
+ * Build the URL for saving based on the save as modal selections
288
+ */
289
+ buildSaveAsUrl() {
290
+ const useExistingPage = $('#saveAsUseExistingPage').prop('checked');
291
+ const selectedPage = $('#saveAsPageSelect').val();
292
+ const filename = $('#saveAsFilename').val().trim();
293
+
294
+ if (!filename) {
295
+ alert('Veuillez saisir un nom de fichier.');
296
+ return null;
297
+ }
298
+
299
+ let subpageName;
300
+
301
+ if (useExistingPage && selectedPage) {
302
+ subpageName = selectedPage;
303
+ } else {
304
+ subpageName = 'Non classified';
305
+ }
306
+
307
+ // Build the final URL: subpagename/filename.json
308
+ const finalUrl = `${subpageName}/${filename}.json`;
309
+
310
+ if (crops.defaultTitle !== false) {
311
+ crops.title = filename;
312
+ }
313
+
314
+ return finalUrl;
315
+ }
316
+
317
+ /**
318
+ * Handle the save as operation
319
+ */
320
+ async saveAs() {
321
+ const url = this.buildSaveAsUrl();
322
+
323
+ if (!url) {
324
+ return; // Error already handled in buildSaveAsUrl
325
+ }
326
+
327
+ const self = this;
328
+ const oldPageTitle = self.pageTitle;
329
+
330
+ try {
331
+ // Set the new page title
332
+ self.pageTitle = url;
333
+
334
+ // Save to the wiki first
335
+ await self.savePageToWiki(self.pageTitle, JSON.stringify(crops, null, 2));
336
+
337
+ // Close the modal
338
+ const modal = bootstrap.Modal.getInstance(document.getElementById('saveAsModal'));
339
+ modal.hide();
340
+
341
+ alert(`Itinéraire technique enregistré avec succès sous "${url}"`);
342
+
343
+ // Only navigate after successful save
344
+ const newEditorUrl = `editor.html?wiki=${encodeURIComponent(self.pageTitle)}`;
345
+ window.location.href = newEditorUrl;
346
+
347
+ } catch (error) {
348
+ // Restore the old page title if save failed
349
+ self.pageTitle = oldPageTitle;
350
+ console.error("Error saving as new file:", error);
351
+ alert('Erreur lors de l\'enregistrement du fichier.');
352
+ }
353
+ }
223
354
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osfarm/itineraire-technique",
3
- "version": "1.1.11",
3
+ "version": "1.1.13",
4
4
  "description": "A visualisation tool to show agricultural technical itineraries based on Echarts",
5
5
  "main": "editor.html",
6
6
  "scripts": {