Skip to content

Commit f222673

Browse files
committed
Verbeterde import/export met file API indien de browser dit ondersteunt. Fallback naar de klassieke methodes indien niet.
1 parent 39c3551 commit f222673

File tree

9 files changed

+1080
-405
lines changed

9 files changed

+1080
-405
lines changed

builddate.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
var CONF_builddate="20240929-165826"
1+
var CONF_builddate="20241005-205608"

compile

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,7 @@
22

33
cd src
44

5-
tsc general.ts SVGelement.ts \
6-
importExport.ts undoRedo.ts \
7-
List_Item/List_Item.ts \
8-
List_Item/Electro_Item.ts \
9-
List_Item/Schakelaars/Schakelaar.ts \
10-
List_Item/Schakelaars/Schakelaars.ts \
11-
List_Item/Schakelaars/Lichtcircuit.ts \
12-
List_Item/*.ts \
13-
Properties.ts SVGSymbols.ts Hierarchical_List.ts Print_Table.ts config.ts ../prop/prop_scripts.ts main.ts \
14-
--outfile swap.js
5+
tsc # Uses the tsconfig.json file
156

167
cat GPL3.js swap.js > eendraadschema.js
178
cp eendraadschema.js ..

eendraadschema.js

Lines changed: 403 additions & 163 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"devDependencies": {
3+
"typescript": "^5.6.2"
4+
},
5+
"dependencies": {
6+
"node-typescript": "^0.1.3"
7+
}
8+
}

prop/prop_scripts.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,12 @@ function PROP_development_options() {
3434
function loadFileFromText() {
3535
let str:string = (document.getElementById('HL_loadfromtext') as HTMLInputElement).value;
3636
import_to_structure(str);
37+
fileAPIobj.clear();
3738
}
3839

3940
/// --- END OF DEVELOPMENT OPTIONS ---
4041

41-
function exportjson() {
42+
function exportjson(saveAs: boolean = true) { //if the boolean is false and the file API is installed, a normal save is performed (known filename)
4243
var filename:string;
4344

4445
/* We use the Pako library to entropy code the data
@@ -60,7 +61,11 @@ function exportjson() {
6061
} catch (error) {
6162
text = "TXT0040000" + text;
6263
} finally {
63-
download_by_blob(text, filename, 'data:text/eds;charset=utf-8');
64+
if ((window as any).showOpenFilePicker) { // Use fileAPI
65+
if (saveAs) this.fileAPIobj.saveAs(text); else this.fileAPIobj.save(text);
66+
} else { // legacy
67+
download_by_blob(text, filename, 'data:text/eds;charset=utf-8');
68+
}
6469
}
6570
}
6671

src/eendraadschema.js

Lines changed: 403 additions & 163 deletions
Large diffs are not rendered by default.

src/importExport.ts

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,141 @@
1+
class importExportUsingFileAPI {
2+
3+
saveNeeded: boolean;
4+
fileHandle: any;
5+
filename: string;
6+
lastsaved: string;
7+
8+
constructor() {
9+
this.clear();
10+
//this.updateButtons();
11+
}
12+
13+
clear() {
14+
this.saveNeeded = false;
15+
this.fileHandle = null;
16+
this.filename = null;
17+
}
18+
19+
updateLastSaved() {
20+
var currentdate = new Date();
21+
this.lastsaved = currentdate.getHours().toString().padStart(2, '0') + ":" +
22+
currentdate.getMinutes().toString().padStart(2, '0') + ":" +
23+
currentdate.getSeconds().toString().padStart(2, '0');;
24+
25+
//If there is an object on the screen that needs updating, do it
26+
if (document.getElementById('exportscreen') as HTMLInputElement) {
27+
exportscreen(); // Update the export screen if we are actually on the export screen
28+
}
29+
}
30+
31+
//updateButtons() {
32+
//document.getElementById('saveAsButton').disabled = !(this.fileAPIdata.saveNeeded);
33+
/* document.getElementById('saveAsButton').disabled = false;
34+
document.getElementById('saveButton').disabled = !(this.fileAPIdata.saveNeeded);
35+
}*/
36+
37+
setSaveNeeded(input) {
38+
let lastSaveNeeded = this.saveNeeded;
39+
this.saveNeeded = input;
40+
//if (input !== lastSaveNeeded) this.updateButtons();
41+
}
42+
43+
async readFile() {
44+
45+
[this.fileHandle] = await (window as any).showOpenFilePicker({
46+
types: [{
47+
description: 'Eendraadschema (.eds)',
48+
accept: {'application/eds': ['.eds']},
49+
}],
50+
});
51+
52+
const file = await (this.fileHandle as any).getFile();
53+
const contents = await file.text();
54+
55+
this.filename = file.name;
56+
structure.properties.filename = file.name;
57+
58+
this.setSaveNeeded(false);
59+
60+
this.updateLastSaved(); // Needed because import_to_structure whipes everything
61+
62+
return contents;
63+
}
64+
65+
async saveAs(content: string) {
66+
const options = {
67+
suggestedName: structure.properties.filename,
68+
types: [{
69+
description: 'Eendraadschema (.eds)',
70+
accept: {'application/eds': ['.eds']},
71+
}],
72+
startIn: 'documents' // Suggests the Documents folder
73+
};
74+
75+
this.fileHandle = await (window as any).showSaveFilePicker(options);
76+
await this.saveFile(content, this.fileHandle);
77+
78+
79+
};
80+
81+
async saveFile(content: any, handle: any) {
82+
const writable = await handle.createWritable();
83+
await writable.write(content);
84+
await writable.close();
85+
86+
this.filename = handle.name;
87+
structure.properties.filename = handle.name;
88+
89+
this.setSaveNeeded(false);
90+
91+
this.updateLastSaved();
92+
};
93+
94+
async save(content: string) {
95+
await this.saveFile(content, this.fileHandle);
96+
};
97+
}
98+
99+
var fileAPIobj = new importExportUsingFileAPI();
100+
101+
/* FUNCTION importjson
102+
103+
This is the callback function for the legacy filepicker if the file API is not available in the browser */
104+
105+
var importjson = function(event) {
106+
var input = event.target;
107+
var reader = new FileReader();
108+
var text:string = "";
109+
110+
reader.onload = function(){
111+
import_to_structure(reader.result.toString());
112+
};
113+
114+
reader.readAsText(input.files[0]);
115+
116+
// Scroll to top left for the SVG, this can only be done at the end because "right col" has to actually be visible
117+
/*const rightelem = document.getElementById("right_col");
118+
if (rightelem != null) {
119+
rightelem.scrollTop = 0;
120+
rightelem.scrollLeft = 0;
121+
}*/
122+
};
123+
124+
/* FUNCTION importclicked()
125+
126+
Gets called when a user wants to open a file. Checks if the fileAPI is available in the browser.
127+
If so, the fileAPI is used. If not, the legacy function importjson is called */
128+
129+
async function importclicked() {
130+
if ((window as any).showOpenFilePicker) { // Use fileAPI
131+
let data = await fileAPIobj.readFile();
132+
import_to_structure(data);
133+
} else { // Legacy
134+
document.getElementById('importfile').click();
135+
(document.getElementById('importfile') as HTMLInputElement).value = "";
136+
}
137+
}
138+
1139
/* FUNCTION upgrade_version
2140
3141
Takes a structure, usually imported from json into javascript object, and performs a version upgrade if needed.
@@ -212,6 +350,20 @@ function import_to_structure(mystring: string, redraw = true) {
212350
// Clear the undo stack and push this one on top
213351
undostruct.clear();
214352
undostruct.store();
353+
354+
// Scroll to top left for the SVG and HTML, this can only be done at the end because "right col" has to actually be visible
355+
const leftelem = document.getElementById("left_col");
356+
if (leftelem != null) {
357+
leftelem.scrollTop = 0;
358+
leftelem.scrollLeft = 0;
359+
}
360+
361+
const rightelem = document.getElementById("right_col");
362+
if (rightelem != null) {
363+
rightelem.scrollTop = 0;
364+
rightelem.scrollLeft = 0;
365+
}
366+
215367
}
216368

217369
function structure_to_json() {
@@ -231,4 +383,79 @@ function structure_to_json() {
231383

232384
return(text);
233385

386+
}
387+
388+
/* FUNCTION download_by_blob
389+
390+
Downloads an EDS file to the user's PC
391+
392+
*/
393+
394+
function download_by_blob(text, filename, mimeType) {
395+
396+
var element = document.createElement('a');
397+
if (navigator.msSaveBlob) {
398+
navigator.msSaveBlob(new Blob([text], {
399+
type: mimeType
400+
}), filename);
401+
} else if (URL && 'download' in element) {
402+
let uriContent = URL.createObjectURL(new Blob([text], {type : mimeType}));
403+
element.setAttribute('href', uriContent);
404+
element.setAttribute('download', filename);
405+
element.style.display = 'none';
406+
document.body.appendChild(element);
407+
element.click();
408+
document.body.removeChild(element);
409+
} else {
410+
this.location.go(`${mimeType},${encodeURIComponent(text)}`);
411+
}
412+
413+
}
414+
415+
/* FUNCTION exportScreen
416+
417+
Shows the exportscreen. It will look different depending on whether the browser supports the file API or not
418+
419+
*/
420+
421+
function exportscreen() {
422+
423+
var strleft: string = '<br><span id="exportscreen"></span>'; //We need the id to check elsewhere that the screen is open
424+
425+
if ((window as any).showOpenFilePicker) { // Use fileAPI
426+
427+
if (fileAPIobj.filename != null) {
428+
strleft += 'Laatst geopend of opgeslagen om <b>' + fileAPIobj.lastsaved + '</b> met naam <b>' + fileAPIobj.filename + '</b><br><br>'
429+
+ 'Klik hieronder om bij te werken<br><br>'
430+
strleft += '<button onclick="exportjson(saveAs = false)">Opslaan</button>&nbsp;';
431+
strleft += '<button onclick="exportjson(saveAs = true)">Opslaan als</button><br><br>';
432+
} else {
433+
strleft += 'Uw werk werd nog niet opgeslagen. Klik hieronder.<br><br>';
434+
strleft += '<button onclick="exportjson(saveAs = true)">Opslaan als</button>';
435+
strleft += '<br><br>';
436+
}
437+
strleft += '<table border=0>';
438+
strleft += PROP_GDPR(); //Function returns empty for GIT version, returns GDPR notice when used online.
439+
strleft += '</table>';
440+
441+
} else { // Legacy
442+
strleft += '<table border=0><tr><td width=500 style="vertical-align:top;padding:5px">';
443+
strleft += 'Bestandsnaam: <span id="settings"><code>' + structure.properties.filename + '</code><br><button onclick="HL_enterSettings()">Wijzigen</button>&nbsp;<button onclick="exportjson()">Opslaan</button></span>';
444+
strleft += '</td><td style="vertical-align:top;padding:5px">'
445+
strleft += 'U kan het schema opslaan op uw lokale harde schijf voor later gebruik. De standaard-naam is eendraadschema.eds. U kan deze wijzigen door links op "wijzigen" te klikken. ';
446+
strleft += 'Klik vervolgens op "opslaan" en volg de instructies van uw browser. '
447+
strleft += 'In de meeste gevallen zal uw browser het bestand automatisch plaatsen in de Downloads-folder tenzij u uw browser instelde dat die eerst een locatie moet vragen.<br><br>'
448+
strleft += 'Eens opgeslagen kan het schema later opnieuw geladen worden door in het menu "openen" te kiezen en vervolgens het bestand op uw harde schijf te selecteren.<br><br>'
449+
strleft += '</td></tr>';
450+
451+
strleft += PROP_GDPR(); //Function returns empty for GIT version, returns GDPR notice when used online.
452+
453+
strleft += '</table>';
454+
455+
// Plaats input box voor naam van het schema bovenaan --
456+
strleft += '<br>';
457+
}
458+
459+
document.getElementById("configsection").innerHTML = strleft;
460+
hide2col();
234461
}

0 commit comments

Comments
 (0)