sunrize 1.2.7 → 1.3.0

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.
Files changed (62) hide show
  1. package/package.json +12 -10
  2. package/src/Application/Dashboard.js +44 -47
  3. package/src/Application/Document.js +13 -1
  4. package/src/Application/Tabs.js +81 -80
  5. package/src/Editors/OutlineEditor.js +129 -21
  6. package/src/Editors/Primitives.js +13 -2
  7. package/src/Tools/CADGeometry/IndexedQuadSetTool.js +7 -0
  8. package/src/Tools/CADGeometry/QuadSetTool.js +7 -0
  9. package/src/Tools/Core/ToolColors.js +2 -2
  10. package/src/Tools/Core/X3DBaseTool.js +61 -0
  11. package/src/Tools/Core/X3DChildNodeTool.js +2 -176
  12. package/src/Tools/Core/X3DNodeTool.js +231 -53
  13. package/src/Tools/EnvironmentalSensor/X3DEnvironmentalSensorNodeTool.x3d +1 -1
  14. package/src/Tools/Geometry2D/Arc2DTool.js +105 -0
  15. package/src/Tools/Geometry2D/ArcClose2DTool.js +105 -0
  16. package/src/Tools/Geometry2D/Circle2DTool.js +105 -0
  17. package/src/Tools/Geometry2D/Disk2DTool.js +197 -0
  18. package/src/Tools/Geometry2D/Polyline2DTool.js +7 -0
  19. package/src/Tools/Geometry2D/Polypoint2DTool.js +7 -0
  20. package/src/Tools/Geometry2D/Rectangle2DTool.js +117 -0
  21. package/src/Tools/Geometry2D/TriangleSet2DTool.js +7 -0
  22. package/src/Tools/Geometry3D/BoxTool.js +117 -0
  23. package/src/Tools/Geometry3D/ConeTool.js +151 -0
  24. package/src/Tools/Geometry3D/CylinderTool.js +159 -0
  25. package/src/Tools/Geometry3D/ElevationGridTool.js +7 -0
  26. package/src/Tools/Geometry3D/ExtrusionTool.js +7 -0
  27. package/src/Tools/Geometry3D/IndexedFaceSetTool.js +7 -0
  28. package/src/Tools/Geometry3D/SphereTool.js +116 -0
  29. package/src/Tools/Geospatial/GeoElevationGridTool.js +15 -0
  30. package/src/Tools/Grouping/X3DBoundedObjectTool.x3d +5 -2
  31. package/src/Tools/Grouping/X3DTransformNodeTool.js +4 -2
  32. package/src/Tools/Grouping/X3DTransformNodeTool.x3d +42 -17
  33. package/src/Tools/Lighting/X3DLightNodeTool.x3d +1 -1
  34. package/src/Tools/NURBS/NurbsCurveTool.js +7 -0
  35. package/src/Tools/NURBS/NurbsPatchSurfaceTool.js +7 -0
  36. package/src/Tools/NURBS/NurbsSweptSurfaceTool.js +7 -0
  37. package/src/Tools/NURBS/NurbsSwungSurfaceTool.js +7 -0
  38. package/src/Tools/NURBS/NurbsTrimmedSurfaceTool.js +7 -0
  39. package/src/Tools/Navigation/X3DViewpointNodeTool.x3d +1 -1
  40. package/src/Tools/Rendering/IndexedLineSetTool.js +7 -0
  41. package/src/Tools/Rendering/IndexedTriangleFanSetTool.js +7 -0
  42. package/src/Tools/Rendering/IndexedTriangleSetTool.js +7 -0
  43. package/src/Tools/Rendering/IndexedTriangleStripSetTool.js +7 -0
  44. package/src/Tools/Rendering/LineSetTool.js +7 -0
  45. package/src/Tools/Rendering/PointSetTool.js +7 -0
  46. package/src/Tools/Rendering/TriangleFanSetTool.js +7 -0
  47. package/src/Tools/Rendering/TriangleSetTool.js +7 -0
  48. package/src/Tools/Rendering/TriangleStripSetTool.js +7 -0
  49. package/src/Tools/Rendering/X3DGeometryNodeTool.js +52 -0
  50. package/src/Tools/Rendering/X3DGeometryNodeTool.x3d +70 -0
  51. package/src/Tools/Rendering/X3DLineGeometryNodeTool.js +40 -0
  52. package/src/Tools/Rendering/X3DLineGeometryNodeTool.x3d +62 -0
  53. package/src/Tools/Rendering/X3DPointGeometryNodeTool.js +40 -0
  54. package/src/Tools/Rendering/X3DPointGeometryNodeTool.x3d +52 -0
  55. package/src/Tools/Sound/SoundTool.x3d +3 -3
  56. package/src/Tools/Text/TextTool.js +7 -0
  57. package/src/Tools/TextureProjection/X3DTextureProjectorNodeTool.x3d +1 -1
  58. package/src/Undo/Editor.js +1 -1
  59. package/src/assets/html/application.html +71 -0
  60. package/src/assets/html/window.html +37 -0
  61. package/src/assets/themes/default.css +1333 -0
  62. package/src/assets/themes/prompt.css +48 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sunrize",
3
3
  "productName": "Sunrize X3D Editor",
4
- "version": "1.2.7",
4
+ "version": "1.3.0",
5
5
  "description": "A Multi-Platform X3D Editor",
6
6
  "main": "src/main.js",
7
7
  "bin": {
@@ -20,8 +20,9 @@
20
20
  "premake": "npm i -D electron",
21
21
  "make": "electron-forge make",
22
22
  "postmake": "npm i -P electron",
23
- "release": "node build/publish.js",
24
- "docs": "cd docs && bundle exec jekyll serve --incremental --host=192.168.0.18"
23
+ "release": "node build/release.js",
24
+ "docs": "cd docs && bundle exec jekyll serve --incremental --host=192.168.0.18",
25
+ "make-x_ite-for-sunrize": "sh build/make-x_ite-for-sunrize.sh"
25
26
  },
26
27
  "repository": {
27
28
  "type": "git",
@@ -62,16 +63,17 @@
62
63
  }
63
64
  ],
64
65
  "devDependencies": {
65
- "@electron-forge/cli": "^7.1.0",
66
- "@electron-forge/maker-deb": "^7.1.0",
67
- "@electron-forge/maker-rpm": "^7.1.0",
68
- "@electron-forge/maker-squirrel": "^7.1.0",
69
- "@electron-forge/maker-zip": "^7.1.0"
66
+ "@electron-forge/cli": "^7.2.0",
67
+ "@electron-forge/maker-deb": "^7.2.0",
68
+ "@electron-forge/maker-rpm": "^7.2.0",
69
+ "@electron-forge/maker-squirrel": "^7.2.0",
70
+ "@electron-forge/maker-zip": "^7.2.0",
71
+ "shell-tools": "^1.1.5"
70
72
  },
71
73
  "dependencies": {
72
74
  "capitalize": "^2.0.4",
73
75
  "console": "^0.7.2",
74
- "electron": "^27.1.2",
76
+ "electron": "^27.1.3",
75
77
  "electron-prompt": "^1.7.0",
76
78
  "electron-squirrel-startup": "^1.0.0",
77
79
  "electron-tabs": "^1.0.2",
@@ -88,7 +90,7 @@
88
90
  "qtip2": "^3.0.3",
89
91
  "spectrum-colorpicker2": "^2.0.10",
90
92
  "string-similarity": "^4.0.4",
91
- "x_ite": "^9.1.5"
93
+ "x_ite": "^9.1.7"
92
94
  },
93
95
  "config": {
94
96
  "forge": {
@@ -1,20 +1,20 @@
1
- "use strict"
1
+ "use strict";
2
2
 
3
3
  const
4
4
  $ = require ("jquery"),
5
5
  X3D = require ("../X3D"),
6
6
  Interface = require ("./Interface"),
7
- _ = require ("./GetText")
7
+ _ = require ("./GetText");
8
8
 
9
9
  module .exports = class Dashboard extends Interface
10
10
  {
11
11
  constructor (element)
12
12
  {
13
- super ("Sunrize.Dashboard.")
13
+ super ("Sunrize.Dashboard.");
14
14
 
15
- this .toolbar = element
15
+ this .toolbar = element;
16
16
 
17
- this .setup ()
17
+ this .setup ();
18
18
  }
19
19
 
20
20
  async initialize ()
@@ -23,15 +23,15 @@ module .exports = class Dashboard extends Interface
23
23
  .addClass (["image-icon", "hand"])
24
24
  .attr ("title", _ ("Switch to browser mode."))
25
25
  .appendTo (this .toolbar)
26
- .on ("click", () => this .hand ())
26
+ .on ("click", () => this .hand ());
27
27
 
28
- this .handButton .addClass ("active")
28
+ this .handButton .addClass ("active");
29
29
 
30
30
  this .arrowButton = $("<span></span>")
31
31
  .addClass (["image-icon", "arrow"])
32
32
  .attr ("title", _ ("Switch to edit mode."))
33
33
  .appendTo (this .toolbar)
34
- .on ("click", () => this .arrow ())
34
+ .on ("click", () => this .arrow ());
35
35
 
36
36
  this .playButton = $("<span></span>")
37
37
  .addClass (["material-icons"])
@@ -39,23 +39,23 @@ module .exports = class Dashboard extends Interface
39
39
  .css ({ position: "relative", left: "-1px", "font-weight": "bold" })
40
40
  .text ("play_arrow")
41
41
  .appendTo (this .toolbar)
42
- .on ("click", () => this .play (!this .fileConfig .play))
42
+ .on ("click", () => this .play (!this .fileConfig .play));
43
43
 
44
- $("<span></span>") .addClass ("separator") .appendTo (this .toolbar)
44
+ $("<span></span>") .addClass ("separator") .appendTo (this .toolbar);
45
45
 
46
46
  this .viewAllButton = $("<span></span>")
47
47
  .addClass (["material-symbols-outlined"])
48
48
  .attr ("title", _ ("View all objects in active layer."))
49
49
  .text ("center_focus_strong")
50
50
  .appendTo (this .toolbar)
51
- .on ("click", () => this .viewAll ())
51
+ .on ("click", () => this .viewAll ());
52
52
 
53
53
  this .straightenButton = $("<span></span>")
54
54
  .addClass (["material-symbols-outlined", "active"])
55
55
  .attr ("title", _ ("Straighten horizon."))
56
56
  .text ("wb_twilight")
57
57
  .appendTo (this .toolbar)
58
- .on ("click", () => this .straighten (!this .browser .getBrowserOption ("StraightenHorizon")))
58
+ .on ("click", () => this .straighten (!this .browser .getBrowserOption ("StraightenHorizon")));
59
59
  }
60
60
 
61
61
  configure ()
@@ -63,56 +63,58 @@ module .exports = class Dashboard extends Interface
63
63
  this .fileConfig .setDefaultValues ({
64
64
  pointer: "hand",
65
65
  play: false,
66
- })
66
+ });
67
67
 
68
- this [this .fileConfig .pointer] ()
69
- this .play (this .fileConfig .play)
70
- this .straighten (this .browser .getBrowserOption ("StraightenHorizon"))
68
+ this [this .fileConfig .pointer] ();
69
+ this .play (this .fileConfig .play);
70
+ this .straighten (this .browser .getBrowserOption ("StraightenHorizon"));
71
71
  }
72
72
 
73
73
  hand ()
74
74
  {
75
- this .fileConfig .pointer = "hand"
75
+ this .fileConfig .pointer = "hand";
76
76
 
77
77
  if (this .handButton .hasClass ("active"))
78
- return
78
+ return;
79
79
 
80
- this .arrowButton .removeClass ("active")
81
- this .handButton .addClass ("active")
80
+ this .arrowButton .removeClass ("active");
81
+ this .handButton .addClass ("active");
82
82
  }
83
83
 
84
84
  arrow ()
85
85
  {
86
- this .fileConfig .pointer = "arrow"
86
+ this .fileConfig .pointer = "arrow";
87
87
 
88
88
  if (this .arrowButton .hasClass ("active"))
89
- return
89
+ return;
90
90
 
91
- this .handButton .removeClass ("active")
92
- this .arrowButton .addClass ("active")
91
+ this .handButton .removeClass ("active");
92
+ this .arrowButton .addClass ("active");
93
93
  }
94
94
 
95
95
  play (value)
96
96
  {
97
- this .fileConfig .play = value
97
+ this .fileConfig .play = value;
98
98
 
99
99
  if (value)
100
100
  {
101
- this .playButton .addClass ("active")
102
- this .browser .beginUpdate ()
101
+ this .playButton .addClass ("active");
102
+ this .browser .beginUpdate ();
103
103
  }
104
104
  else
105
105
  {
106
- this .playButton .removeClass ("active")
107
- this .browser .endUpdate ()
106
+ this .playButton .removeClass ("active");
107
+ this .browser .endUpdate ();
108
108
  }
109
109
  }
110
110
 
111
111
  viewAll ()
112
112
  {
113
+ const types = new Set ([X3D .X3DConstants .X3DBoundedObject, X3D .X3DConstants .X3DGeometryNode]);
114
+
113
115
  const
114
116
  outlineEditor = require ("./Window") .sidebar .outlineEditor,
115
- selection = outlineEditor .sceneGraph .find (".node.selected")
117
+ selection = outlineEditor .sceneGraph .find (".node.selected");
116
118
 
117
119
  if (selection .length)
118
120
  {
@@ -120,44 +122,39 @@ module .exports = class Dashboard extends Interface
120
122
  layerNode = this .browser .getActiveLayer (),
121
123
  viewpointNode = this .browser .getActiveViewpoint (),
122
124
  bbox = new X3D .Box3 (),
123
- straighten = this .browser .getBrowserOption ("StraightenHorizon")
125
+ straighten = this .browser .getBrowserOption ("StraightenHorizon");
124
126
 
125
127
  for (const element of selection)
126
128
  {
127
- try
128
- {
129
- const node = outlineEditor .getNode ($(element)) .getInnerNode ()
129
+ const node = outlineEditor .getNode ($(element)) .getInnerNode ();
130
130
 
131
- if (!node .getType () .includes (X3D .X3DConstants .X3DBoundedObject))
132
- continue
131
+ if (!node .getType () .some (type => types .has (type)))
132
+ continue;
133
133
 
134
- const modelMatrix = outlineEditor .getModelMatrix ($(element), false)
134
+ const modelMatrix = outlineEditor .getModelMatrix ($(element), false);
135
135
 
136
- bbox .add (node .getBBox (new X3D .Box3 ()) .multRight (modelMatrix))
137
- }
138
- catch
139
- { }
136
+ bbox .add (node .getBBox (new X3D .Box3 ()) .copy () .multRight (modelMatrix));
140
137
  }
141
138
 
142
139
  if (!bbox .size .magnitude ())
143
140
  return;
144
141
 
145
- viewpointNode .lookAtBBox (layerNode, bbox, 1, straighten)
142
+ viewpointNode .lookAtBBox (layerNode, bbox, 1, straighten);
146
143
  }
147
144
  else
148
145
  {
149
- this .browser .viewAll ()
146
+ this .browser .viewAll ();
150
147
  }
151
148
  }
152
149
 
153
150
  straighten (value)
154
151
  {
155
- this .browser .setBrowserOption ("StraightenHorizon", value)
152
+ this .browser .setBrowserOption ("StraightenHorizon", value);
156
153
 
157
154
  if (value)
158
- this .straightenButton .addClass ("active")
155
+ this .straightenButton .addClass ("active");
159
156
  else
160
- this .straightenButton .removeClass ("active")
157
+ this .straightenButton .removeClass ("active");
161
158
  }
162
- }
159
+ };
163
160
 
@@ -307,7 +307,7 @@ module .exports = class Document extends Interface
307
307
 
308
308
  clearTimeout (this .#saveTimeoutId);
309
309
 
310
- this .#saveTimeoutId = setTimeout (() => this .saveFile (), 3000);
310
+ this .#saveTimeoutId = setTimeout (() => this .saveFile (), 1000);
311
311
  }
312
312
 
313
313
  exportAs (filePath)
@@ -375,8 +375,20 @@ module .exports = class Document extends Interface
375
375
  */
376
376
  setPrimitiveQuality (value)
377
377
  {
378
+ const live = this .browser .isLive ();
379
+
380
+ this .browser .beginUpdate ();
378
381
  this .browser .setBrowserOption ("PrimitiveQuality", value);
379
382
  this .browser .setDescription (`Primitive Quality: ${value .toLowerCase ()}`);
383
+
384
+ if (!live)
385
+ {
386
+ this .browser .finishedEvents () .addFieldCallback (this, () =>
387
+ {
388
+ this .browser .finishedEvents () .removeFieldCallback (this);
389
+ this .browser .endUpdate ();
390
+ })
391
+ }
380
392
  }
381
393
 
382
394
  /**
@@ -1,4 +1,4 @@
1
- "use strict"
1
+ "use strict";
2
2
 
3
3
  const
4
4
  $ = require ("jquery"),
@@ -10,24 +10,24 @@ const
10
10
  fs = require ("fs"),
11
11
  md5 = require ("md5"),
12
12
  CSS = require ("./CSS"),
13
- _ = require ("./GetText")
13
+ _ = require ("./GetText");
14
14
 
15
15
  module .exports = new class Tabs
16
16
  {
17
17
  // Construction
18
18
 
19
- config = new DataStorage (localStorage, "Sunrize.Application.")
19
+ config = new DataStorage (localStorage, "Sunrize.Application.");
20
20
 
21
21
  constructor ()
22
22
  {
23
- this .tabs = $("tab-group") .get (0)
23
+ this .tabs = $("tab-group") .get (0);
24
24
 
25
25
  this .config .setDefaultValues ({
26
26
  openTabs: [ ],
27
27
  scrollLeft: 0,
28
- })
28
+ });
29
29
 
30
- $(() => this .initialize ())
30
+ $(() => this .initialize ());
31
31
  }
32
32
 
33
33
  initialize ()
@@ -106,59 +106,60 @@ module .exports = new class Tabs
106
106
 
107
107
  restoreTabs (activeTab)
108
108
  {
109
- const config = new DataStorage (localStorage, "Sunrize.")
109
+ const config = new DataStorage (localStorage, "Sunrize.");
110
110
 
111
111
  const openTabs = this .config .openTabs .filter (fileURL =>
112
112
  {
113
113
  if (!fileURL .startsWith ("file:"))
114
- return true
114
+ return true;
115
115
 
116
116
  if (fs .existsSync (url .fileURLToPath (fileURL)))
117
- return true
117
+ return true;
118
118
 
119
119
  // Delete keys of deleted file.
120
120
 
121
- const hash = `.${md5 (fileURL)}.`
121
+ const hash = `.${md5 (fileURL)}.`;
122
122
 
123
123
  for (const key of Object .keys (config) .filter (key => key .includes (hash)))
124
- config [key] = undefined
124
+ config [key] = undefined;
125
125
 
126
- return false
126
+ return false;
127
127
  })
128
128
 
129
129
  for (const fileURL of openTabs .filter (fileURL => fileURL .startsWith ("file:")))
130
130
  electron .ipcRenderer .send ("add-recent-document", url .fileURLToPath (fileURL));
131
131
 
132
132
  if (openTabs .length)
133
- this .openTabs (openTabs, false)
133
+ this .openTabs (openTabs, false);
134
134
 
135
135
  if (this .tabs .getTabs () .length)
136
136
  {
137
- const tab = this .getTabByURL (activeTab) ?? this .tabs .getTabByPosition (0)
137
+ const tab = this .getTabByURL (activeTab) ?? this .tabs .getTabByPosition (0);
138
138
 
139
- tab .activate ()
139
+ tab .activate ();
140
140
  }
141
141
  else
142
142
  {
143
- this .openTabs ()
143
+ this .openTabs ();
144
144
  }
145
145
  }
146
146
 
147
147
  openTabs (urls = [""], activate = true)
148
148
  {
149
149
  if (!urls .length)
150
- return
150
+ return;
151
151
 
152
- const src = url .pathToFileURL (path .join (__dirname, "../assets/html/window.html"))
152
+ const src = url .pathToFileURL (path .join (__dirname, "../assets/html/window.html"));
153
153
 
154
154
  for (let fileURL of urls)
155
155
  {
156
156
  if (fileURL && this .tabs .getTabs () .some (tab => tab .url === fileURL))
157
- continue
157
+ continue;
158
158
 
159
- if (!fileURL) fileURL = `id:${md5 (Math .random ())}`
159
+ if (!fileURL)
160
+ fileURL = `id:${md5 (Math .random ())}`;
160
161
 
161
- src .searchParams .set ("url", fileURL)
162
+ src .searchParams .set ("url", fileURL);
162
163
 
163
164
  const tab = this .tabs .addTab ({
164
165
  src: src,
@@ -169,38 +170,38 @@ module .exports = new class Tabs
169
170
  },
170
171
  visible: true,
171
172
  active: false,
172
- })
173
+ });
173
174
 
174
- this .setTabURL (tab, fileURL)
175
+ this .setTabURL (tab, fileURL);
175
176
 
176
177
  tab .webview .addEventListener ("console-message", (event) =>
177
178
  {
178
- tab .webview .send ("console-message", event .level, event .sourceId, event .line, event .message)
179
- })
179
+ tab .webview .send ("console-message", event .level, event .sourceId, event .line, event .message);
180
+ });
180
181
 
181
- tab .on ("closing", (tab, abort) => this .tabClosing (tab, abort))
182
- tab .on ("close", (tab) => this .tabClose (tab))
182
+ tab .on ("closing", (tab, abort) => this .tabClosing (tab, abort));
183
+ tab .on ("close", (tab) => this .tabClose (tab));
183
184
 
184
185
  tab .webview .addEventListener ("ipc-message", (event, value) =>
185
186
  {
186
187
  if (event .channel !== "saved")
187
- return
188
+ return;
188
189
 
189
- this .setTabURL (tab, tab .url, ...event .args)
190
- })
190
+ this .setTabURL (tab, tab .url, ...event .args);
191
+ });
191
192
 
192
193
  tab .webview .addEventListener ("dom-ready", () =>
193
194
  {
194
195
  // Workaround for focus issue with webview.
195
- tab .webview .focus ()
196
- window .blur ()
197
- window .focus ()
196
+ tab .webview .focus ();
197
+ window .blur ();
198
+ window .focus ();
198
199
 
199
- tab .domReady = true
200
+ tab .domReady = true;
200
201
 
201
202
  if (this .tabs .getActiveTab () === tab)
202
- tab .webview .send ("activate")
203
- })
203
+ tab .webview .send ("activate");
204
+ });
204
205
  }
205
206
 
206
207
  if (activate)
@@ -208,72 +209,72 @@ module .exports = new class Tabs
208
209
  const tab = this .getTabs () .find (tab => urls .includes (tab .url))
209
210
  ?? this .tabs .getTabByPosition (this .tabs .getTabs () .length - 1)
210
211
 
211
- tab .activate ()
212
+ tab .activate ();
212
213
  }
213
214
 
214
- this .saveTabs ()
215
+ this .saveTabs ();
215
216
  }
216
217
 
217
218
  reloadTab ()
218
219
  {
219
- const tab = this .tabs .getActiveTab ()
220
+ const tab = this .tabs .getActiveTab ();
220
221
 
221
- tab .webview .src = tab .webview .src
222
+ tab .webview .src = tab .webview .src;
222
223
  }
223
224
 
224
225
  getTabs ()
225
226
  {
226
- const cmp = (a, b) => (a > b) - (a < b)
227
+ const cmp = (a, b) => (a > b) - (a < b);
227
228
 
228
229
  return this .tabs .getTabs ()
229
- .sort ((a, b) => cmp (a .getPosition (), b .getPosition ()))
230
+ .sort ((a, b) => cmp (a .getPosition (), b .getPosition ()));
230
231
  }
231
232
 
232
233
  getTabByURL (fileURL)
233
234
  {
234
- return this .getTabs () .findLast (tab => tab .url === fileURL)
235
+ return this .getTabs () .findLast (tab => tab .url === fileURL);
235
236
  }
236
237
 
237
238
  setTabURL (tab, fileURL, saved = true)
238
239
  {
239
- tab .url = fileURL
240
+ tab .url = fileURL;
240
241
 
241
- tab .setTitle ((fileURL .startsWith ("id:") ? _ ("New Scene") : path .basename (decodeURIComponent (new URL (fileURL) .pathname))) + (saved ? "" : "*"))
242
+ tab .setTitle ((fileURL .startsWith ("id:") ? _ ("New Scene") : path .basename (decodeURIComponent (new URL (fileURL) .pathname))) + (saved ? "" : "*"));
242
243
 
243
- $(tab .element) .find (".tab-title") .attr ("title", fileURL .startsWith ("id:") ? _ ("Currently still unsaved.") : decodeURI (fileURL))
244
+ $(tab .element) .find (".tab-title") .attr ("title", fileURL .startsWith ("id:") ? _ ("Currently still unsaved.") : decodeURI (fileURL));
244
245
 
245
- electron .ipcRenderer .send ("title", tab .getTitle ())
246
+ electron .ipcRenderer .send ("title", tab .getTitle ());
246
247
 
247
- this .saveTabs ()
248
+ this .saveTabs ();
248
249
  }
249
250
 
250
251
  saveTabs ()
251
252
  {
252
253
  const
253
254
  tabs = this .getTabs (),
254
- urls = tabs .map (tab => tab .url)
255
+ urls = tabs .map (tab => tab .url);
255
256
 
256
- this .config .openTabs = urls
257
- this .config .activeTab = tabs .length ? this .tabs .getActiveTab () .url : undefined
257
+ this .config .openTabs = urls;
258
+ this .config .activeTab = tabs .length ? this .tabs .getActiveTab () .url : undefined;
258
259
  }
259
260
 
260
261
  tabClosing (tab, abort)
261
262
  {
262
- tab .webview .send ("close")
263
+ tab .webview .send ("close");
263
264
 
264
265
  if (tab !== this .tabs .getActiveTab ())
265
- return
266
-
267
- const numTabs = this .tabs .getTabs () .length
266
+ return;
267
+ ;
268
+ const numTabs = this .tabs .getTabs () .length;
268
269
 
269
270
  if (numTabs === 1)
270
- return
271
+ return;
271
272
 
272
273
  const
273
274
  position = Math .max (tab .getPosition () - 1, 0),
274
- nextTab = this .tabs .getTabByPosition (position)
275
+ nextTab = this .tabs .getTabByPosition (position);
275
276
 
276
- nextTab .activate ()
277
+ nextTab .activate ();
277
278
  }
278
279
 
279
280
  tabClose (tab)
@@ -281,84 +282,84 @@ module .exports = new class Tabs
281
282
  // If all tabs are closed, open empty tab.
282
283
 
283
284
  if (!this .tabs .getTabs () .length)
284
- this .openTabs ()
285
+ this .openTabs ();
285
286
 
286
- this .saveTabs ()
287
+ this .saveTabs ();
287
288
  }
288
289
 
289
290
  saveFile ()
290
291
  {
291
- this .tabs .getActiveTab () .webview .send ("save-file", true)
292
+ this .tabs .getActiveTab () .webview .send ("save-file", true);
292
293
  }
293
294
 
294
295
  saveFileAs (filePath)
295
296
  {
296
297
  const
297
298
  tab = this .tabs .getActiveTab (),
298
- fileURL = url .pathToFileURL (filePath) .href
299
+ fileURL = url .pathToFileURL (filePath) .href;
299
300
 
300
- this .setTabURL (tab, fileURL)
301
+ this .setTabURL (tab, fileURL);
301
302
 
302
- tab .webview .send ("save-file-as", filePath)
303
+ tab .webview .send ("save-file-as", filePath);
303
304
  }
304
305
 
305
306
  saveAllFiles ()
306
307
  {
307
308
  for (const tab of this .tabs .getTabs ())
308
- tab .webview .send ("save-file")
309
+ tab .webview .send ("save-file");
309
310
  }
310
311
 
311
312
  close ()
312
313
  {
313
- this .saveTabs ()
314
+ this .saveTabs ();
314
315
 
315
316
  for (const tab of this .tabs .getTabs ())
316
- tab .webview .send ("close")
317
+ tab .webview .send ("close");
317
318
  }
318
319
 
319
320
  quit ()
320
321
  {
321
- this .saveTabs ()
322
+ this .saveTabs ();
322
323
 
323
- const tabs = this .tabs .getTabs () .filter (tab => tab .initialized)
324
+ const tabs = this .tabs .getTabs () .filter (tab => tab .initialized);
324
325
 
325
- let numTabs = tabs .length
326
+ let numTabs = tabs .length;
326
327
 
327
328
  for (const tab of tabs)
328
329
  {
329
330
  tab .webview .addEventListener ("ipc-message", (event) =>
330
331
  {
331
332
  if (event .channel !== "closed")
332
- return
333
+ return;
333
334
 
334
335
  if (--numTabs)
335
- return
336
+ return;
336
337
 
337
- window .close ()
338
- })
338
+ window .close ();
339
+ });
339
340
  }
340
341
 
341
342
  for (const tab of tabs)
342
- tab .webview .send ("close")
343
+ tab .webview .send ("close");
343
344
 
344
- //this .maintenance ()
345
+ //this .maintenance ();
345
346
  }
346
347
 
347
348
  maintenance ()
348
349
  {
349
350
  // Remove items older than one year, time in milliseconds.
350
- new DataStorage (localStorage, "Sunrize.") .removeItems (Date .now () - (1000 * 60 * 60 * 24 * 365))
351
+ new DataStorage (localStorage, "Sunrize.") .removeItems (Date .now () - (1000 * 60 * 60 * 24 * 365));
351
352
  }
352
353
 
353
354
  // Send messages to tabs
354
355
 
355
356
  forwardToActiveTab (channel)
356
357
  {
357
- electron .ipcRenderer .on (channel, (event, ...args) => this .tabs .getActiveTab () .webview .send (channel, ...args))
358
+ electron .ipcRenderer .on (channel, (event, ...args) => this .tabs .getActiveTab () .webview .send (channel, ...args));
358
359
  }
359
360
 
360
361
  forwardToAllTabs (channel)
361
362
  {
362
- electron .ipcRenderer .on (channel, (event, ...args) => this .tabs .getTabs () .forEach (tab => tab .webview .send (channel, ...args)))
363
+ electron .ipcRenderer .on (channel, (event, ...args) => this .tabs .getTabs () .forEach (tab => tab .webview .send (channel, ...args)));
363
364
  }
364
- }
365
+ };