@osfarm/itineraire-technique 1.0.7 → 1.1.1

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.
@@ -1 +1 @@
1
- div.mainITKContainer{container-type:inline-size;container-name:myparent;line-height:1rem}div.mainITKContainer .left-transcript{display:none;width:50%;font-family:Segoe UI}div.mainITKContainer .chart-div{width:100%}div.mainITKContainer .bottom-transcript{display:block;font-family:Segoe UI}@container myparent (min-width: 800px){div.mainITKContainer .left-transcript{display:block}div.mainITKContainer .chart-div{width:50%}div.mainITKContainer .bottom-transcript{display:none}}@container myparent (min-width: 1200px){div.mainITKContainer .left-transcript{display:block;width:40%}div.mainITKContainer .chart-div{width:60%}div.mainITKContainer .bottom-transcript{display:none}}div.mainITKContainer div.rotation_item{background-color:#f8fafc;border-left:#fff 14px solid;border-radius:7px;padding:8px 3px 5px 9px;margin:12px 0;overflow-x:hidden}div.mainITKContainer div.rotation_item.highlighted{box-shadow:0px 4px 4px 0px var(--UI-Shadow, rgba(17, 36, 69, 0.16)),0px 1px 16px 0px var(--UI-Shadow, rgba(17, 36, 69, 0.16));background-color:#f0f3f5}div.mainITKContainer div.rotation_item div.step-header h4{margin-bottom:0;margin-top:0}div.mainITKContainer div.rotation_item div.step-header div.step_dates{font-size:11px;background-color:#cdcccc;color:#fff;margin:5px;padding:2px 5px;border-radius:5px;height:20px;float:right}div.mainITKContainer div.rotation_item div.step-header div.collapse-button{border-radius:50%;width:30px;height:30px;text-align:center;padding:5px 0px;margin:0 5px 3px 0;cursor:pointer;background:#dfe6f7;color:#7a8bad;float:right;transition:transform .3s ease-in-out}div.mainITKContainer div.rotation_item .step_description{clear:both}div.mainITKContainer div.rotation_item.show-all div.collapse-button{transform:rotate(180deg)}div.mainITKContainer div.rotation_item.show-all div.details{max-height:10000px}div.mainITKContainer div.rotation_item div.details{max-height:0px;overflow:hidden;transition:max-height .3s ease-in-out}div.mainITKContainer div.rotation_item div.details div.intervention{background-color:#fff;border-radius:5px;margin-bottom:11px;padding:13px;cursor:pointer}div.mainITKContainer div.rotation_item div.details div.intervention span.intervention_title{font-weight:bold}div.mainITKContainer div.rotation_item div.details div.intervention span.intervention_date{color:#707070;background-color:#f0f3f5;float:right}div.mainITKContainer div.rotation_item div.details div.intervention div.intervention_description{margin-top:5px}div.mainITKContainer div.rotation_item .step-edit{display:none}div.mainITKContainer .charts{width:100%;height:500px;display:inline-block}div.mainITKContainer .transcript{font-size:80%;width:100%;max-height:450px;overflow-y:scroll;scroll-behavior:smooth;padding:3px}/*# sourceMappingURL=styles-rendering.css.map */
1
+ div.mainITKContainer{container-type:inline-size;container-name:myparent;line-height:1rem}div.mainITKContainer .left-transcript{display:none;width:50%;font-family:Segoe UI}div.mainITKContainer .chart-div{width:100%}div.mainITKContainer .bottom-transcript{display:block;font-family:Segoe UI}@container myparent (min-width: 800px){div.mainITKContainer .left-transcript{display:block}div.mainITKContainer .chart-div{width:50%}div.mainITKContainer .bottom-transcript{display:none}}@container myparent (min-width: 1200px){div.mainITKContainer .left-transcript{display:block;width:40%}div.mainITKContainer .chart-div{width:60%}div.mainITKContainer .bottom-transcript{display:none}}div.mainITKContainer div.rotation_item{background-color:#f8fafc;border-left:#fff 14px solid;border-radius:7px;padding:8px 3px 5px 9px;margin:12px 0;overflow-x:hidden}div.mainITKContainer div.rotation_item.highlighted{box-shadow:0px 4px 4px 0px var(--UI-Shadow, rgba(17, 36, 69, 0.16)),0px 1px 16px 0px var(--UI-Shadow, rgba(17, 36, 69, 0.16));background-color:#f0f3f5}div.mainITKContainer div.rotation_item div.step-header h4{margin-bottom:0;margin-top:0}div.mainITKContainer div.rotation_item div.step-header div.step_dates{font-size:11px;background-color:#cdcccc;color:#fff;margin:5px;padding:2px 5px;border-radius:5px;height:20px;float:right}div.mainITKContainer div.rotation_item div.step-header div.collapse-button{border-radius:50%;width:30px;height:30px;text-align:center;padding:5px 0px;margin:0 5px 3px 0;cursor:pointer;background:#dfe6f7;color:#7a8bad;float:right;transition:transform .3s ease-in-out}div.mainITKContainer div.rotation_item .step_description{clear:both}div.mainITKContainer div.rotation_item.show-all div.collapse-button{transform:rotate(180deg)}div.mainITKContainer div.rotation_item.show-all div.details{max-height:10000px}div.mainITKContainer div.rotation_item div.details{max-height:0px;overflow:hidden;transition:max-height .3s ease-in-out}div.mainITKContainer div.rotation_item div.details div.intervention{background-color:#fff;border-radius:5px;margin-bottom:11px;padding:13px;cursor:pointer}div.mainITKContainer div.rotation_item div.details div.intervention span.intervention_title{font-weight:bold}div.mainITKContainer div.rotation_item div.details div.intervention span.intervention_date{color:#707070;background-color:#f0f3f5;float:right}div.mainITKContainer div.rotation_item div.details div.intervention div.intervention_description{margin-top:5px}div.mainITKContainer div.rotation_item .step-edit{display:none}div.mainITKContainer .charts{width:100%;height:500px;display:inline-block}div.mainITKContainer .transcript{font-size:80%;width:100%;max-height:450px;overflow-y:scroll;scroll-behavior:smooth;padding:3px}.rotation-tooltip{width:400px}/*# sourceMappingURL=styles-rendering.css.map */
@@ -1 +1 @@
1
- {"version":3,"sourceRoot":"","sources":["../scss/styles-rendering.scss"],"names":[],"mappings":"AAAA,qBACI,2BACA,wBACA,iBAEA,sCACI,aACA,UACA,qBAGJ,gCACI,WAGJ,wCACI,cACA,qBAGJ,uCACI,sCACI,cAGJ,gCACI,UAGJ,wCACI,cAIR,wCACI,sCACI,cACA,UAGJ,gCACI,UAGJ,wCACI,cAIR,uCACI,yBACA,4BACA,kBACA,wBACA,cACA,kBAEA,mDACI,8HAEA,yBAIA,0DACI,gBACA,aAGJ,sEACI,eACA,yBACA,WACA,WACA,gBACA,kBACA,YACA,YAGJ,2EACI,kBACA,WACA,YACA,kBACA,gBACA,mBACA,eACA,mBACA,cACA,YACA,qCAIR,yDACI,WAIA,oEACI,yBAGJ,4DACI,mBAKR,mDACI,eACA,gBACA,sCAEA,oEACI,sBACA,kBACA,mBACA,aACA,eAEA,4FACI,iBAGJ,2FACI,cACA,yBACA,YAGJ,iGACI,eAKZ,kDACI,aAIR,6BACI,WACA,aACA,qBAGJ,iCACI,cACA,WACA,iBACA,kBACA,uBACA","file":"styles-rendering.css"}
1
+ {"version":3,"sourceRoot":"","sources":["../scss/styles-rendering.scss"],"names":[],"mappings":"AAAA,qBACI,2BACA,wBACA,iBAEA,sCACI,aACA,UACA,qBAGJ,gCACI,WAGJ,wCACI,cACA,qBAGJ,uCACI,sCACI,cAGJ,gCACI,UAGJ,wCACI,cAIR,wCACI,sCACI,cACA,UAGJ,gCACI,UAGJ,wCACI,cAIR,uCACI,yBACA,4BACA,kBACA,wBACA,cACA,kBAEA,mDACI,8HAEA,yBAIA,0DACI,gBACA,aAGJ,sEACI,eACA,yBACA,WACA,WACA,gBACA,kBACA,YACA,YAGJ,2EACI,kBACA,WACA,YACA,kBACA,gBACA,mBACA,eACA,mBACA,cACA,YACA,qCAIR,yDACI,WAIA,oEACI,yBAGJ,4DACI,mBAKR,mDACI,eACA,gBACA,sCAEA,oEACI,sBACA,kBACA,mBACA,aACA,eAEA,4FACI,iBAGJ,2FACI,cACA,yBACA,YAGJ,iGACI,eAKZ,kDACI,aAIR,6BACI,WACA,aACA,qBAGJ,iCACI,cACA,WACA,iBACA,kBACA,uBACA,YAIR,kBACI","file":"styles-rendering.css"}
package/editor.html CHANGED
@@ -20,12 +20,13 @@
20
20
  <script src="./js/editor-interventions.js"></script>
21
21
  <script src="./js/editor-crops.js"></script>
22
22
  <script src="./js/editor-export.js"></script>
23
+ <script src="./js/editor-wiki-editor.js"></script>
23
24
 
24
25
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
25
26
  integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
26
27
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
27
28
  <link href="./css/styles-editor.css" rel="stylesheet">
28
- <link href="./css/styles-rendering.css" rel="stylesheet">
29
+ <link href="./css/styles-rendering.css" rel="stylesheet">
29
30
  </head>
30
31
 
31
32
  <body>
@@ -35,7 +36,7 @@
35
36
  <button type="button" onclick="importFromJsonFile()" class="btn btn-outline-primary primary-button"
36
37
  id="importFromJsonButton"><i class="fa fa-upload" aria-hidden="true"></i> Charger (JSON)</button>
37
38
  <button type="button" onclick="importFromTestJson()" class="btn btn-outline-primary primary-button"
38
- id="importFromJsonButton"><i class="fa fa-upload" aria-hidden="true"></i> Charger un
39
+ id="importFromExampleJsonButton"><i class="fa fa-upload" aria-hidden="true"></i> Charger un
39
40
  exemple</button>
40
41
  <button type="button" onclick="exportToJsonFile(crops)"
41
42
  class="btn btn-outline-primary primary-button" id="exportToJsonButton"><i
@@ -292,6 +293,9 @@
292
293
  enableTitleEditing();
293
294
 
294
295
  $('.close-step-button').click(function() {
296
+ // Set the current step to be fully edited now:
297
+ selectedStep.setAsEdited();
298
+
295
299
  displayCropListView();
296
300
  });
297
301
 
@@ -379,6 +383,8 @@
379
383
 
380
384
  refreshAllTables();
381
385
  });
386
+
387
+ let we = new WikiEditor();
382
388
  }
383
389
 
384
390
  class StepModel {
@@ -399,6 +405,12 @@
399
405
  this.step.useDefaultEndDate = step.useDefaultEndDate ?? true;
400
406
  }
401
407
 
408
+ setAsEdited() {
409
+ this.step.useDefaultColor = false;
410
+ this.step.useDefaultStartDate = false;
411
+ this.step.useDefaultEndDate = false;
412
+ }
413
+
402
414
  getStep() {
403
415
  return this.step;
404
416
  }
@@ -29,12 +29,20 @@ class RotationRenderer {
29
29
 
30
30
  this.itk_container = $("#" + divID).css({ 'width': '100%' });
31
31
 
32
- if (this.itk_container.find('.mainITKContainer').length == 0) {
33
- this.itk_container.append(`<div class="row mainITKContainer">
34
- <div class="col-auto left-transcript"><div class="transcript"></div></div>
35
- <div class="col col-auto chart-div"><div class="charts"></div></div>
36
- <div class="col col-12 bottom-transcript"><div class="transcript"></div></div>
37
- </div>`);
32
+ if (this.data.options.show_transcript) {
33
+ if (this.itk_container.find('.mainITKContainer').length == 0) {
34
+ this.itk_container.append(`<div class="row mainITKContainer">
35
+ <div class="col-auto left-transcript"><div class="transcript"></div></div>
36
+ <div class="col col-auto chart-div"><div class="charts"></div></div>
37
+ <div class="col col-12 bottom-transcript"><div class="transcript"></div></div>
38
+ </div>`);
39
+ }
40
+ } else {
41
+ if (this.itk_container.find('.mainITKContainer').length == 0) {
42
+ this.itk_container.append(`<div class="row mainITKContainer">
43
+ <div class="col col-12 chart-div"><div class="charts"></div></div>
44
+ </div>`);
45
+ }
38
46
  }
39
47
  }
40
48
 
@@ -281,7 +289,7 @@ class RotationRenderer {
281
289
  startDate: new Date(item.startDate.valueOf()), // Date de début
282
290
  endDate: new Date(item.endDate.valueOf()), // Date de fin
283
291
  duration: item.duration,
284
- description: (item.description ?? ''),
292
+ description: self.getHTMLFormatedDescription(item.description),
285
293
  value: [
286
294
  1, // Parcelle (index de la série)
287
295
  item.startDate.valueOf(), // Date de début
@@ -682,7 +690,7 @@ class RotationRenderer {
682
690
  'startDate': new Date(item.startDate.valueOf()), // Date de début
683
691
  'endDate': new Date(item.endDate.valueOf()), // Date de fin
684
692
  'duration': item.duration,
685
- 'description': (item.description ?? '')// + (item.attributes ? item.attributes.map((attribute) => { return '<p><dt>' + attribute.name + '</dt><dd>' + attribute.value + '</dd></p>' }).join('') : '')
693
+ 'description': self.getHTMLFormatedDescription(item.description)
686
694
  };
687
695
 
688
696
  if (pieItem.color != '#ffffff')
@@ -814,6 +822,8 @@ class RotationRenderer {
814
822
  }
815
823
 
816
824
  option.tooltip = {
825
+ extraCssText: "text-wrap: wrap;",
826
+ className: "rotation-tooltip",
817
827
  formatter: function (params) {
818
828
  if (params.data.type == 'rotation_item') {
819
829
  let start = params.data.startDate.toLocaleDateString('fr-FR', { day: 'numeric', month: 'short', year: '2-digit' });
@@ -869,4 +879,18 @@ class RotationRenderer {
869
879
 
870
880
  return option;
871
881
  }
882
+
883
+ getHTMLFormatedDescription(description) {
884
+
885
+ if (description == undefined)
886
+ return '';
887
+
888
+ // If a line has a column in it, split the line in two and add bold to the first part:
889
+ description = description.replace(/^([^:\n]+):/gm, "<b>$1:</b>");
890
+ description = description.replace(/\n([^:\n]+):/gm, "\n<b>$1:</b>");
891
+
892
+ description = description.replace(/\n/g, '<br/>');
893
+
894
+ return description;
895
+ }
872
896
  }
@@ -28,24 +28,28 @@ function importFromTestJson() {
28
28
  });
29
29
  } else {
30
30
  importTestJSON();
31
- }
31
+ }
32
32
  }
33
33
 
34
34
  function importTestJSON() {
35
- fetch('test/test.json')
36
- .then(response => {
37
- if (!response.ok) {
38
- throw new Error("Erreur HTTP " + response.status);
39
- }
40
- return response.json();
41
- })
42
- .then(data => {
43
- console.log("Données JSON :", data);
44
- reloadCropsFromJson(data);
45
- })
46
- .catch(error => {
47
- console.error("Impossible de charger le JSON :", error);
48
- });
35
+ fetch('test/test.json')
36
+ .then(response => {
37
+ if (!response.ok) {
38
+ throw new Error("Erreur HTTP " + response.status);
39
+ }
40
+ return response.json();
41
+ })
42
+ .then(data => {
43
+ console.log("Données JSON :", data);
44
+ data.steps.forEach(step => {
45
+ let sm = new StepModel(step)
46
+ sm.setAsEdited();
47
+ });
48
+ reloadCropsFromJson(data);
49
+ })
50
+ .catch(error => {
51
+ console.error("Impossible de charger le JSON :", error);
52
+ });
49
53
  }
50
54
 
51
55
  function wipe() {
@@ -67,7 +71,7 @@ function wipe() {
67
71
  });
68
72
  } else {
69
73
  reloadCropsFromJson(crops);
70
- }
74
+ }
71
75
  }
72
76
 
73
77
  function openFileInput() {
@@ -82,6 +86,10 @@ function openFileInput() {
82
86
  reader.onload = () => {
83
87
  try {
84
88
  const jsonData = JSON.parse(reader.result);
89
+ jsonData.steps.forEach(step => {
90
+ let sm = new StepModel(step)
91
+ sm.setAsEdited();
92
+ });
85
93
  reloadCropsFromJson(jsonData);
86
94
  } catch (error) {
87
95
  console.error("Error parsing JSON file:", error);
@@ -0,0 +1,107 @@
1
+ // Encapsulate the wiki editor functionality
2
+ class WikiEditor {
3
+ constructor() {
4
+ // Initialize any properties if needed
5
+
6
+ const self = this;
7
+
8
+ // When the page loads, get the URL paremeter with the target page title we want to edit:
9
+ window.onload = function () {
10
+ const urlParams = new URLSearchParams(window.location.search);
11
+ const pageTitle = urlParams.get('wiki');
12
+
13
+ if (!pageTitle)
14
+ return; // No page title provided, we are not in wiki edit mode
15
+
16
+ // If a page title is provided, load its content
17
+ fetch(`/api.php?action=parse&page=${encodeURIComponent(pageTitle)}&format=json&prop=wikitext`, {
18
+ credentials: 'same-origin'
19
+ })
20
+ .then(response => {
21
+ let res = response.json();
22
+ return res;
23
+ })
24
+ .then(data => {
25
+ if (data.parse && data.parse.wikitext) {
26
+ try {
27
+ const content = JSON.parse(data.parse.wikitext['*']);
28
+ content.steps.forEach(step => {
29
+ let sm = new StepModel(step)
30
+ sm.setAsEdited();
31
+ });
32
+ reloadCropsFromJson(content);
33
+ } catch (e) {
34
+ console.error("Erreur lors de l'analyse du JSON de la page :", e);
35
+ $('#jsonErrorMessage').text("Le contenu de la page n'est pas un JSON valide.");
36
+ const jsonErrorModal = new bootstrap.Modal(document.getElementById('jsonErrorModal'));
37
+ jsonErrorModal.show();
38
+ }
39
+ } else {
40
+
41
+ if (data.error.code == "missingtitle") {
42
+ // The page doesn't exist yet, we can start with a blank rotation
43
+ wipe();
44
+ } else {
45
+ console.error("Erreur lors du chargement de la page :", data);
46
+ $('#jsonErrorMessage').text("Impossible de charger le contenu de la page.");
47
+ const jsonErrorModal = new bootstrap.Modal(document.getElementById('jsonErrorModal'));
48
+ jsonErrorModal.show();
49
+ }
50
+
51
+ }
52
+ });
53
+
54
+ // Add a button to save the page back the wiki
55
+ const saveButton = $(`<button type="button" class="btn btn-outline-primary primary-button" id="exportToJsonButton">
56
+ <i class="fa fa-download" aria-hidden="true"></i> Enregistrer dans le wiki
57
+ </button>`).on('click', function () {
58
+ if (pageTitle) {
59
+ // If a page title is provided, save to that page
60
+ self.savePageToWiki(pageTitle, JSON.stringify(crops, null, 2))
61
+ .then(() => {
62
+ alert("Itinéraire technique enregistré avec succès !");
63
+ })
64
+ .catch(err => {
65
+ console.error("Erreur lors de l'enregistrement de la page :", err);
66
+ alert("Une erreur s'est produite lors de l'enregistrement.");
67
+ });
68
+ } else {
69
+ // Otherwise, export to JSON file
70
+ exportToJsonFile(crops);
71
+ }
72
+ });
73
+
74
+ $(".file-icons").first().prepend(saveButton);
75
+
76
+ $('#importFromExampleJsonButton').remove();
77
+ $('#importFromJsonButton').remove();
78
+ };
79
+ }
80
+
81
+ async savePageToWiki(pageTitle, newContent) {
82
+ // 1. Obtenir un token
83
+ const tokenResp = await fetch('/api.php?action=query&meta=tokens&type=csrf&format=json', {
84
+ credentials: 'same-origin' // important pour envoyer les cookies de session
85
+ });
86
+ const tokenData = await tokenResp.json();
87
+ const token = tokenData.query.tokens.csrftoken;
88
+
89
+ // 2. Faire l’édition
90
+ const params = new URLSearchParams();
91
+ params.append('action', 'edit');
92
+ params.append('format', 'json');
93
+ params.append('title', pageTitle);
94
+ params.append('text', newContent);
95
+ params.append('token', token);
96
+ params.append('contentmodel', 'json');
97
+
98
+ const editResp = await fetch('/api.php', {
99
+ method: 'POST',
100
+ body: params,
101
+ credentials: 'same-origin'
102
+ });
103
+
104
+ const editData = await editResp.json();
105
+ console.log(editData);
106
+ }
107
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osfarm/itineraire-technique",
3
- "version": "1.0.7",
3
+ "version": "1.1.1",
4
4
  "description": "A visualisation tool to show agricultural technical itineraries based on Echarts",
5
5
  "main": "editor.html",
6
6
  "scripts": {
@@ -155,4 +155,8 @@ div.mainITKContainer {
155
155
  scroll-behavior: smooth;
156
156
  padding : 3px;
157
157
  }
158
+ }
159
+
160
+ .rotation-tooltip {
161
+ width: 400px;
158
162
  }