1 | const BluePromise = require("bluebird"); |
||
2 | const fs = require("fs"); |
||
3 | const electron = require("electron"); |
||
4 | const { dialog } = electron; |
||
5 | const fs2 = BluePromise.promisifyAll(fs); |
||
0 ignored issues
–
show
Unused Code
introduced
by
![]() |
|||
6 | const _ = require("lodash"); |
||
0 ignored issues
–
show
|
|||
7 | |||
8 | module.exports = class SaveFile { |
||
9 | constructor(app) { |
||
10 | this.app = app; |
||
11 | |||
12 | // Init empty path and data |
||
13 | this.onPathChange(); |
||
14 | this.onDataChange(); |
||
15 | |||
16 | this.app.on("menu-clearRecentDocs", this.clearRecentDocs.bind(this)); |
||
17 | this.app.on("menu-openRecentDocs", this.openRecentDocs.bind(this)); |
||
18 | this.app.on("menu-open", this.openFile.bind(this)); |
||
19 | this.app.on("menu-reopen", this.reOpenFile.bind(this)); |
||
20 | this.app.on("menu-new", this.closeFile.bind(this)); |
||
21 | this.app.on("menu-save", this.saveFile.bind(this)); |
||
22 | this.app.on("menu-saveAs", this.saveAsFile.bind(this)); |
||
23 | this.app.on("menu-saveAsCopy", this.saveAsCopyFile.bind(this)); |
||
24 | this.app.on("menu-wipe", this.wipeUnusedSpace.bind(this)); |
||
25 | |||
26 | this.app.on("ipcFrom-dataUpdate", this.onDataChange.bind(this)); |
||
27 | |||
28 | this.app.on("window-ready", this.onWindowReady.bind(this)); |
||
29 | } |
||
30 | |||
31 | onWindowReady() { |
||
32 | this.onPathChange(this.filePath); |
||
33 | } |
||
34 | |||
35 | onPathChange(path = "") { |
||
36 | if (path !== "") |
||
37 | this.addRecentDocument(path); |
||
0 ignored issues
–
show
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later. Consider: if (a > 0)
b = 42;
If you or someone else later decides to put another statement in, only the first statement will be executed. if (a > 0)
console.log("a > 0");
b = 42;
In this case the statement if (a > 0) {
console.log("a > 0");
b = 42;
}
ensures that the proper code will be executed conditionally no matter how many statements are added or removed. ![]() |
|||
38 | |||
39 | this.filePath = path; |
||
40 | this.app.emit("ipcTo", "pathChange", path); |
||
41 | } |
||
42 | |||
43 | /** |
||
44 | * This should be the only method to be called to change data |
||
45 | * @param {Uint8Array} data New data to apply |
||
46 | * @param {boolean} fromRender Is this data from the render? |
||
47 | * @param {boolean} internalOnly Should this data silently change? |
||
48 | */ |
||
49 | onDataChange(data = new Uint8Array(0x8000), fromRender = false, internalOnly = false) { |
||
50 | this.fileData = data; |
||
51 | |||
52 | if (!fromRender) |
||
53 | this.app.emit("ipcTo", "dataChange", data, internalOnly); |
||
0 ignored issues
–
show
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later. Consider: if (a > 0)
b = 42;
If you or someone else later decides to put another statement in, only the first statement will be executed. if (a > 0)
console.log("a > 0");
b = 42;
In this case the statement if (a > 0) {
console.log("a > 0");
b = 42;
}
ensures that the proper code will be executed conditionally no matter how many statements are added or removed. ![]() |
|||
54 | |||
55 | if (fromRender && this.pendingSave) |
||
56 | this._writeSaveFile(); |
||
0 ignored issues
–
show
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later. Consider: if (a > 0)
b = 42;
If you or someone else later decides to put another statement in, only the first statement will be executed. if (a > 0)
console.log("a > 0");
b = 42;
In this case the statement if (a > 0) {
console.log("a > 0");
b = 42;
}
ensures that the proper code will be executed conditionally no matter how many statements are added or removed. ![]() |
|||
57 | } |
||
58 | |||
59 | // Adds a file to the list of recent documents which is persistent |
||
60 | // Only 10 unique non-duplicate files are kept meaning each entry will be |
||
61 | // a different file, the samefile will remain in the same slot |
||
62 | // They are added to the top, oldest at the bottom |
||
63 | // They are accessible via CommandOrControl+Shift+# <0-9> |
||
64 | addRecentDocument(path) { |
||
65 | let recentDocs = this.app.store.get('recentDocs', []); |
||
66 | recentDocs.unshift(path); |
||
67 | recentDocs = _.uniq(recentDocs); |
||
0 ignored issues
–
show
The variable
_ seems to be never declared. If this is a global, consider adding a /** global: _ */ comment.
This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed. To learn more about declaring variables in Javascript, see the MDN. ![]() |
|||
68 | if (recentDocs.length > 10) |
||
69 | recentDocs.length = 10; |
||
0 ignored issues
–
show
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later. Consider: if (a > 0)
b = 42;
If you or someone else later decides to put another statement in, only the first statement will be executed. if (a > 0)
console.log("a > 0");
b = 42;
In this case the statement if (a > 0) {
console.log("a > 0");
b = 42;
}
ensures that the proper code will be executed conditionally no matter how many statements are added or removed. ![]() |
|||
70 | this.app.store.set('recentDocs', recentDocs); |
||
71 | } |
||
72 | |||
73 | openRecentDocs(index) { |
||
74 | let recentDocs = this.app.store.get('recentDocs', []); |
||
75 | this.readSaveFile(recentDocs[index]); |
||
76 | } |
||
77 | |||
78 | // Handles Open File Dialog |
||
79 | // We want this to use es6 async/await and since it never throws an error |
||
80 | // we can't use Bluebird so we need to promisfy it manually |
||
81 | openOpenFileDialog(title) { |
||
82 | return new Promise((resolve) => { |
||
83 | dialog.showOpenDialog({ |
||
0 ignored issues
–
show
The variable
dialog seems to be never declared. If this is a global, consider adding a /** global: dialog */ comment.
This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed. To learn more about declaring variables in Javascript, see the MDN. ![]() |
|||
84 | title, |
||
85 | buttonLabel: "Open", |
||
86 | filters: [ |
||
87 | { name: 'SAV Files', extensions: ['sav'] }, |
||
88 | { name: 'All Files', extensions: ['*'] }, |
||
89 | ], |
||
90 | properties: [ |
||
91 | "openFile", |
||
92 | "treatPackageAsDirectory", |
||
93 | ], |
||
94 | }, (files) => { |
||
95 | resolve(files); |
||
96 | }); |
||
97 | }); |
||
98 | } |
||
99 | |||
100 | // Handles Save File Dialog |
||
101 | // We want this to use es6 async/await and since it never throws an error |
||
102 | // we can't use Bluebird so we need to promisfy it manually |
||
103 | openSaveFileDialog(title) { |
||
104 | return new Promise((resolve) => { |
||
105 | dialog.showSaveDialog({ |
||
0 ignored issues
–
show
The variable
dialog seems to be never declared. If this is a global, consider adding a /** global: dialog */ comment.
This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed. To learn more about declaring variables in Javascript, see the MDN. ![]() |
|||
106 | title, |
||
107 | buttonLabel: "Save", |
||
108 | filters: [ |
||
109 | { name: 'SAV Files', extensions: ['sav'] }, |
||
110 | { name: 'All Files', extensions: ['*'] }, |
||
111 | ], |
||
112 | }, (file) => { |
||
113 | resolve(file); |
||
114 | }); |
||
115 | }); |
||
116 | } |
||
117 | |||
118 | // Handles loading file into memory |
||
119 | async readSaveFile(filePath) { |
||
120 | // Read file |
||
121 | const data = await fs2.readFileAsync(filePath); |
||
0 ignored issues
–
show
The variable
fs2 seems to be never declared. If this is a global, consider adding a /** global: fs2 */ comment.
This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed. To learn more about declaring variables in Javascript, see the MDN. ![]() |
|||
122 | |||
123 | this.onDataChange(data); |
||
124 | this.onPathChange(filePath); |
||
125 | } |
||
126 | |||
127 | // Cache and save requested data update |
||
128 | async _writeSaveFile() { |
||
129 | await fs2.writeFileAsync(this.pendingSave, this.fileData); |
||
0 ignored issues
–
show
The variable
fs2 seems to be never declared. If this is a global, consider adding a /** global: fs2 */ comment.
This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed. To learn more about declaring variables in Javascript, see the MDN. ![]() |
|||
130 | this.pendingSave = null; |
||
131 | } |
||
132 | |||
133 | // Request data update |
||
134 | async writeSaveFile(_filePath = this.filePath) { |
||
135 | this.pendingSave = _filePath; |
||
136 | this.app.emit("ipcTo", "dataUpdate"); |
||
137 | } |
||
138 | |||
139 | clearRecentDocs() { |
||
140 | this.app.store.set('recentDocs', []); |
||
141 | } |
||
142 | |||
143 | // Initiates an open file dialog to open save file |
||
144 | async openFile() { |
||
145 | const fileNames = await this.openOpenFileDialog("Open Save File"); |
||
146 | |||
147 | if (fileNames === undefined) { |
||
148 | return; |
||
149 | } |
||
150 | |||
151 | const filePath = fileNames[0]; |
||
152 | await this.readSaveFile(filePath); |
||
153 | } |
||
154 | |||
155 | // Reloads file from disk erasing unsaved changes, if no open file is |
||
156 | // present just resets buffer |
||
157 | async reOpenFile() { |
||
158 | // If theres no open file then reload an empty array |
||
159 | if (this.filePath === "") { |
||
160 | this.onDataChange(); |
||
161 | return; |
||
162 | } |
||
163 | |||
164 | await this.readSaveFile(this.filePath); |
||
165 | } |
||
166 | |||
167 | // Closes file in memory and erases buffer |
||
168 | closeFile() { |
||
169 | this.onDataChange(); |
||
170 | this.onPathChange(); |
||
171 | } |
||
172 | |||
173 | // Save file |
||
174 | async saveFile() { |
||
175 | if (this.filePath === "") { |
||
176 | await this.saveAsFile(); |
||
177 | return; |
||
178 | } |
||
179 | |||
180 | await this.writeSaveFile(); |
||
181 | } |
||
182 | |||
183 | // Save file as... |
||
184 | async saveAsFile() { |
||
185 | const fileName = await this.openSaveFileDialog("Save File As..."); |
||
186 | |||
187 | if (fileName === undefined) { |
||
188 | return; |
||
189 | } |
||
190 | |||
191 | await this.saveFile(); |
||
192 | this.onPathChange(fileName); |
||
193 | } |
||
194 | |||
195 | // Save copy of file |
||
196 | async saveAsCopyFile() { |
||
197 | const fileName = await this.openSaveFileDialog("Save Copy As..."); |
||
198 | |||
199 | if (fileName === undefined) { |
||
200 | return; |
||
201 | } |
||
202 | |||
203 | await this.writeSaveFile(fileName); |
||
204 | } |
||
205 | |||
206 | // This erases the raw internal data completely leaving the file all zeroes |
||
207 | // Normally the expanded copy will overwrite only the used bytes and leave |
||
208 | // everything else as-is however with this method the expanded copy will |
||
209 | // still do the same but will be writing back to a clean slate thus blasting |
||
210 | // away all unused values |
||
211 | wipeUnusedSpace() { |
||
212 | // Mark internal only to be true so that the render doesn't treat it like |
||
213 | // a new file, all existing data is kept |
||
214 | this.onDataChange(undefined, false, true); |
||
215 | } |
||
216 | } |
||
217 |