sunrize 1.6.15 → 1.7.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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sunrize",
3
3
  "productName": "Sunrize X3D Editor",
4
- "version": "1.6.15",
4
+ "version": "1.7.0",
5
5
  "description": "A Multi-Platform X3D Editor",
6
6
  "main": "src/main.js",
7
7
  "bin": {
@@ -85,26 +85,26 @@
85
85
  "dependencies": {
86
86
  "capitalize": "^2.0.4",
87
87
  "console": "^0.7.2",
88
- "electron": "^30.0.8",
88
+ "electron": "^30.0.9",
89
89
  "electron-prompt": "^1.7.0",
90
90
  "electron-squirrel-startup": "^1.0.1",
91
91
  "electron-tabs": "^1.0.4",
92
92
  "fullname": "^5.0.0",
93
93
  "jquery": "^3.7.1",
94
- "jquery-ui-dist": "^1.13.2",
94
+ "jquery-ui-dist": "^1.13.3",
95
95
  "jstree": "^3.3.16",
96
96
  "material-icons": "^1.13.12",
97
- "material-symbols": "^0.18.0",
97
+ "material-symbols": "^0.19.0",
98
98
  "md5": "^2.3.0",
99
99
  "mime-types": "^2.1.35",
100
- "monaco-editor": "^0.48.0",
100
+ "monaco-editor": "^0.49.0",
101
101
  "node-localstorage": "^3.0.5",
102
102
  "qtip2": "^3.0.3",
103
103
  "spectrum-colorpicker2": "^2.0.10",
104
104
  "string-similarity": "^4.0.4",
105
105
  "tweakpane": "^3.1.10",
106
106
  "update-electron-app": "^3.0.0",
107
- "x_ite": "^9.6.3"
107
+ "x_ite": "^9.7.0"
108
108
  },
109
109
  "config": {
110
110
  "forge": {
@@ -87,7 +87,6 @@ module .exports = class Application
87
87
 
88
88
  electron .ipcMain .on ("title", (event, title) => this .title = title);
89
89
  electron .ipcMain .on ("current-file", (event, currentFile) => this .currentFile = currentFile);
90
- electron .ipcMain .on ("add-recent-document", (event, filePath) => this .addRecentDocument (filePath));
91
90
  electron .ipcMain .on ("add-recent-location", (event, fileURL) => this .addRecentLocation (fileURL));
92
91
  electron .ipcMain .on ("update-menu", (event, options) => this .updateMenu (options));
93
92
  electron .ipcMain .on ("context-menu", (event, id, menu) => this .contextMenu (id, menu));
@@ -868,12 +867,7 @@ module .exports = class Application
868
867
  if (this .ready)
869
868
  {
870
869
  for (const fileURL of urls)
871
- {
872
- if (fileURL .startsWith ("file:"))
873
- this .addRecentDocument (url .fileURLToPath (fileURL));
874
- else
875
- this .addRecentLocation (fileURL);
876
- }
870
+ this .addRecentLocation (fileURL);
877
871
 
878
872
  this .mainWindow .webContents .send ("open-files", urls);
879
873
  this .mainWindow .show ();
@@ -989,6 +983,12 @@ module .exports = class Application
989
983
 
990
984
  addRecentLocation (fileURL)
991
985
  {
986
+ if (fileURL .startsWith ("id:"))
987
+ return;
988
+
989
+ if (fileURL .startsWith ("file:"))
990
+ return this .addRecentDocument (url .fileURLToPath (fileURL));
991
+
992
992
  this .config .recentLocations = this .config .recentLocations
993
993
  .filter (item => item !== fileURL)
994
994
  .toSpliced (0, 0, fileURL)
@@ -395,8 +395,6 @@ Viewpoint {
395
395
  }
396
396
 
397
397
  fs .writeFile (this .filePath, Editor .getContents (scene, path .extname (this .filePath)), Function .prototype);
398
-
399
- electron .ipcRenderer .send ("add-recent-document", this .filePath);
400
398
  }
401
399
  else
402
400
  {
@@ -133,12 +133,7 @@ module .exports = new class Tabs
133
133
  })
134
134
 
135
135
  for (const fileURL of openTabs .filter (fileURL => !fileURL .startsWith ("id:")))
136
- {
137
- if (fileURL .startsWith ("file:"))
138
- electron .ipcRenderer .send ("add-recent-document", url .fileURLToPath (fileURL));
139
- else
140
- electron .ipcRenderer .send ("add-recent-location", fileURL);
141
- }
136
+ electron .ipcRenderer .send ("add-recent-location", fileURL);
142
137
 
143
138
  if (openTabs .length)
144
139
  this .openTabs (openTabs, false);
@@ -266,6 +261,7 @@ module .exports = new class Tabs
266
261
  $(tab .element) .find (".tab-title") .attr ("title", fileURL .startsWith ("id:") ? _("Currently still unsaved.") : decodeURI (fileURL));
267
262
 
268
263
  electron .ipcRenderer .send ("title", tab .getTitle ());
264
+ electron .ipcRenderer .send ("add-recent-location", fileURL);
269
265
 
270
266
  this .saveTabs ();
271
267
  }
@@ -303,6 +299,8 @@ module .exports = new class Tabs
303
299
  {
304
300
  // If all tabs are closed, open empty tab.
305
301
 
302
+ electron .ipcRenderer .send ("add-recent-location", tab .url);
303
+
306
304
  if (!this .tabs .getTabs () .length)
307
305
  this .openTabs ();
308
306
 
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+
3
+ const
4
+ $ = require ("jquery"),
5
+ path = require ("path"),
6
+ X3D = require ("../X3D"),
7
+ Editor = require ("../Undo/Editor"),
8
+ UndoManager = require("../Undo/UndoManager"),
9
+ _ = require ("../Application/GetText");
10
+
11
+ require ("./Popover");
12
+
13
+ $.fn.audioPreviewPopover = async function (node)
14
+ {
15
+ // Create content.
16
+
17
+ const preview = $("<div></div") .css ("width", "30vh");
18
+
19
+ async function loadNow ()
20
+ {
21
+ preview .empty ();
22
+
23
+ const audio = $("<audio controls></audio>")
24
+ .css ("width", "30vh")
25
+ .appendTo (preview);
26
+
27
+ for (const url of node ._url)
28
+ {
29
+ $("<source></source>")
30
+ .attr ("src", new URL (url, node .getExecutionContext () .worldURL))
31
+ .appendTo (audio);
32
+ }
33
+ }
34
+
35
+ loadNow ();
36
+
37
+ // Reload handling.
38
+
39
+ const _url = Symbol ();
40
+
41
+ node ._url .addFieldCallback (_url, loadNow);
42
+
43
+ this .data ("preview", { loadNow });
44
+
45
+ // Create tooltip.
46
+
47
+ const tooltip = this .popover ({
48
+ preview: true,
49
+ content: preview,
50
+ show: {
51
+ modal: false,
52
+ },
53
+ style: {
54
+ classes: "qtip-tipsy qtip-preview qtip-audio",
55
+ },
56
+ events: {
57
+ hide: (event, api) =>
58
+ {
59
+ node ._url .removeFieldCallback (_url);
60
+
61
+ this .removeData ("preview");
62
+
63
+ $(".tree-view") .off (".preview");
64
+
65
+ api .destroy (true);
66
+ },
67
+ },
68
+ });
69
+
70
+ $(".tree-view") .on ("scroll.preview", () => this .qtip ("reposition"));
71
+
72
+ return this;
73
+ };
74
+
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+
3
+ const
4
+ $ = require ("jquery"),
5
+ path = require ("path"),
6
+ X3D = require ("../X3D"),
7
+ Editor = require ("../Undo/Editor"),
8
+ UndoManager = require("../Undo/UndoManager"),
9
+ _ = require ("../Application/GetText");
10
+
11
+ require ("./Popover");
12
+
13
+ $.fn.materialPreviewPopover = async function (node)
14
+ {
15
+ // Create content.
16
+
17
+ const preview = $("<div></div") .css ("width", "30vh");
18
+
19
+ const canvas = $("<x3d-canvas></x3d-canvas>")
20
+ .css ({ width: "30vh", height: "30vh" })
21
+ .attr ("cache", false)
22
+ .attr ("splashScreen", false)
23
+ .attr ("contextMenu", false)
24
+ .attr ("notifications", false)
25
+ .appendTo (preview);
26
+
27
+ const
28
+ browser = canvas .prop ("browser"),
29
+ scene = browser .createScene (browser .getProfile ("Core"));
30
+
31
+ scene .setWorldURL (node .getExecutionContext () .worldURL);
32
+
33
+ await browser .loadURL (new X3D .MFString (path .join (__dirname, "../assets/X3D/MaterialPreview.x3d")));
34
+
35
+ // Create material node.
36
+
37
+ const
38
+ appearanceNode = browser .currentScene .getExportedNode ("Appearance"),
39
+ previewNode = node .copy (scene);
40
+
41
+ // Assign material node.
42
+
43
+ for (const field of previewNode .getFields ())
44
+ {
45
+ switch (field .getType ())
46
+ {
47
+ case X3D .X3DConstants .SFNode:
48
+ field .setValue (null);
49
+ break
50
+ case X3D .X3DConstants .MFNode:
51
+ field .length = 0;
52
+ break;
53
+ default:
54
+ field .addReference (node .getField (field .getName ()));
55
+ field .removeFieldInterest (node .getField (field .getName ()));
56
+ break;
57
+ }
58
+ }
59
+
60
+ previewNode .setup ();
61
+
62
+ appearanceNode .material = previewNode;
63
+
64
+ // Handle TwoSidedMaterial;
65
+
66
+ if (node .getType () .includes (X3D .X3DConstants .TwoSidedMaterial))
67
+ {
68
+ // Create material node.
69
+
70
+ const appearanceNode = browser .currentScene .getExportedNode ("BackAppearance");
71
+
72
+ var backPreviewNode = scene .createNode ("Material");
73
+
74
+ // Assign material node.
75
+
76
+ const names = [
77
+ "ambientIntensity",
78
+ "diffuseColor",
79
+ "specularColor",
80
+ "emissiveColor",
81
+ "shininess",
82
+ "transparency",
83
+ ];
84
+
85
+ for (const name of names)
86
+ {
87
+ const
88
+ field = backPreviewNode .getField (name),
89
+ back = `back${name [0] .toUpperCase ()}${name .slice (1)}`;
90
+
91
+ switch (field .getType ())
92
+ {
93
+ case X3D .X3DConstants .SFNode:
94
+ case X3D .X3DConstants .MFNode:
95
+ break;
96
+ default:
97
+ field .addReference (node .getField (back));
98
+ field .removeFieldInterest (node .getField (back));
99
+ break;
100
+ }
101
+ }
102
+
103
+ appearanceNode .material = backPreviewNode;
104
+ }
105
+
106
+ // Create tooltip.
107
+
108
+ const tooltip = this .popover ({
109
+ preview: true,
110
+ content: preview,
111
+ show: {
112
+ modal: false,
113
+ },
114
+ style: {
115
+ classes: "qtip-tipsy qtip-preview",
116
+ },
117
+ events: {
118
+ hide: (event, api) =>
119
+ {
120
+ previewNode .dispose ();
121
+ backPreviewNode ?.dispose ();
122
+ browser .dispose ();
123
+
124
+ $(".tree-view") .off (".preview");
125
+
126
+ api .destroy (true);
127
+ },
128
+ },
129
+ });
130
+
131
+ $(".tree-view") .on ("scroll.preview", () => this .qtip ("reposition"));
132
+
133
+ return this;
134
+ };
135
+
@@ -4,14 +4,22 @@ const $ = require ("jquery");
4
4
 
5
5
  require ("qtip2");
6
6
 
7
+ $.fn.qtip.zindex = 1000; // Results in 1000 and 1001.
8
+
7
9
  $.fn.popover = function (options)
8
10
  {
11
+ $("[data-hasqtip]") .qtip ?.("hide") .qtip ("destroy", true);
12
+
13
+ if (!options .preview)
14
+ $(".show-preview.on") .removeClass ("on") .addClass ("off");
15
+
9
16
  return this .qtip ($.extend (true,
10
17
  {
11
18
  position: {
12
19
  my: "top right",
13
20
  at: "bottom left",
14
21
  viewport: $("body"),
22
+ effect: false,
15
23
  },
16
24
  style: {
17
25
  classes: "qtip-tipsy",
@@ -0,0 +1,192 @@
1
+ "use strict";
2
+
3
+ const
4
+ $ = require ("jquery"),
5
+ path = require ("path"),
6
+ X3D = require ("../X3D"),
7
+ Editor = require ("../Undo/Editor"),
8
+ UndoManager = require("../Undo/UndoManager"),
9
+ _ = require ("../Application/GetText");
10
+
11
+ require ("./Popover");
12
+
13
+ function formatTime (time)
14
+ {
15
+ const s = time % 60;
16
+
17
+ let string = s .toFixed (2) .padStart (5, "0");
18
+
19
+ time /= 60;
20
+ time = Math .floor (time);
21
+
22
+ const m = time % 60;
23
+
24
+ string = String (m) .padStart (2, "0") + ":" + string;
25
+
26
+ time /= 60;
27
+ time = Math .floor (time);
28
+
29
+ const h = time % 60;
30
+
31
+ string = String (h) .padStart (2, "0") + ":" + string;
32
+
33
+ return string;
34
+ }
35
+
36
+ $.fn.texturePreviewPopover = async function (node)
37
+ {
38
+ // Create content.
39
+
40
+ const preview = $("<div></div") .css ("width", "30vh");
41
+
42
+ const canvas = $("<x3d-canvas></x3d-canvas>")
43
+ .css ("width","30vh")
44
+ .css ("height", "30vh")
45
+ .attr ("cache", false)
46
+ .attr ("splashScreen", false)
47
+ .attr ("contextMenu", false)
48
+ .attr ("notifications", false)
49
+ .appendTo (preview);
50
+
51
+ const
52
+ browser = canvas .prop ("browser"),
53
+ scene = browser .createScene (browser .getProfile ("Core"));
54
+
55
+ scene .setWorldURL (node .getExecutionContext () .worldURL);
56
+
57
+ await browser .loadURL (new X3D .MFString (path .join (__dirname, "../assets/X3D/TexturePreview.x3d")));
58
+
59
+ // Create texture node.
60
+
61
+ const
62
+ x3dSyntax = Editor .exportX3D (node .getExecutionContext (), [node]),
63
+ nodes = await Editor .importX3D (scene, x3dSyntax, new UndoManager ()),
64
+ previewNode = nodes [0],
65
+ appearanceNode = browser .currentScene .getExportedNode ("Appearance");
66
+
67
+ // Assign texture node.
68
+
69
+ for (const field of previewNode .getFields ())
70
+ {
71
+ switch (field .getType ())
72
+ {
73
+ case X3D .X3DConstants .SFNode:
74
+ case X3D .X3DConstants .MFNode:
75
+ break;
76
+ default:
77
+ field .addReference (node .getField (field .getName ()));
78
+ field .removeFieldInterest (node .getField (field .getName ()));
79
+ break;
80
+ }
81
+ }
82
+
83
+ appearanceNode .texture = previewNode;
84
+
85
+ // Sizes and special cases.
86
+
87
+ const sizes = $("<p></p>") .appendTo (preview);
88
+
89
+ function loadState (loadState)
90
+ {
91
+ switch (loadState)
92
+ {
93
+ case X3D .X3DConstants .NOT_STARTED_STATE:
94
+ {
95
+ sizes .text (_("Loading not started."))
96
+ break;
97
+ }
98
+ case X3D .X3DConstants .IN_PROGRESS_STATE:
99
+ {
100
+ sizes .text (_("Loading in progress."))
101
+ break;
102
+ }
103
+ case X3D .X3DConstants .FAILED_STATE:
104
+ {
105
+ sizes .text (_("Loading failed."))
106
+ break;
107
+ }
108
+ case X3D .X3DConstants .COMPLETE_STATE:
109
+ {
110
+ sizesText ();
111
+ break;
112
+ }
113
+ }
114
+ }
115
+
116
+ function sizesText ()
117
+ {
118
+ for (const type of node .getType () .toReversed ())
119
+ {
120
+ switch (type)
121
+ {
122
+ case X3D .X3DConstants .MovieTexture:
123
+ {
124
+ sizes .text (`${node .getWidth ()} × ${node .getHeight ()}, ${formatTime (node ._duration_changed .getValue ())}`);
125
+ break;
126
+ }
127
+ case X3D .X3DConstants .X3DEnvironmentTextureNode:
128
+ {
129
+ sizes .text (`${node .getSize ()} × ${node .getSize ()}`);
130
+ break;
131
+ }
132
+ case X3D .X3DConstants .X3DTexture2DNode:
133
+ {
134
+ sizes .text (`${node .getWidth ()} × ${node .getHeight ()}`);
135
+ break;
136
+ }
137
+ case X3D .X3DConstants .X3DTexture3DNode:
138
+ {
139
+ sizes .text (`${node .getWidth ()} × ${node .getHeight ()} × ${node .getDepth ()}`);
140
+ break;
141
+ }
142
+ default:
143
+ continue;
144
+ }
145
+
146
+ break;
147
+ }
148
+ }
149
+
150
+ const _loadState = Symbol ();
151
+
152
+ node ._loadState .addFieldCallback (_loadState, loadState);
153
+
154
+ loadState (node ._loadState .getValue ());
155
+
156
+ // Reload handling.
157
+
158
+ this .data ("preview", previewNode);
159
+
160
+ // Create tooltip.
161
+
162
+ const tooltip = this .popover ({
163
+ preview: true,
164
+ content: preview,
165
+ show: {
166
+ modal: false,
167
+ },
168
+ style: {
169
+ classes: "qtip-tipsy qtip-preview",
170
+ },
171
+ events: {
172
+ hide: (event, api) =>
173
+ {
174
+ node ._loadState .removeFieldCallback (_loadState);
175
+
176
+ this .removeData ("preview");
177
+
178
+ previewNode .dispose ();
179
+ browser .dispose ();
180
+
181
+ $(".tree-view") .off (".preview");
182
+
183
+ api .destroy (true);
184
+ },
185
+ },
186
+ });
187
+
188
+ $(".tree-view") .on ("scroll.preview", () => this .qtip ("reposition"));
189
+
190
+ return this;
191
+ };
192
+
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+
3
+ const
4
+ $ = require ("jquery"),
5
+ path = require ("path"),
6
+ X3D = require ("../X3D"),
7
+ Editor = require ("../Undo/Editor"),
8
+ UndoManager = require("../Undo/UndoManager"),
9
+ _ = require ("../Application/GetText");
10
+
11
+ require ("./Popover");
12
+
13
+ $.fn.videoPreviewPopover = async function (node)
14
+ {
15
+ // Create content.
16
+
17
+ const
18
+ preview = $("<div></div"),
19
+ container = $("<div></div") .appendTo (preview);
20
+
21
+ preview
22
+ .css ("min-width", "300px")
23
+ .css ("width", "30vh");
24
+
25
+ async function loadNow ()
26
+ {
27
+ container .empty ();
28
+
29
+ const video = $("<video controls></video>")
30
+ .css ("min-width", "300px")
31
+ .css ("width", "30vh")
32
+ .appendTo (container);
33
+
34
+ for (const url of node ._url)
35
+ {
36
+ $("<source></source>")
37
+ .attr ("src", new URL (url, node .getExecutionContext () .worldURL))
38
+ .appendTo (video);
39
+ }
40
+ }
41
+
42
+ // Sizes and special cases.
43
+
44
+ const sizes = $("<p></p>") .appendTo (preview);
45
+
46
+ function loadState (loadState)
47
+ {
48
+ switch (loadState)
49
+ {
50
+ case X3D .X3DConstants .NOT_STARTED_STATE:
51
+ {
52
+ sizes .text (_("Loading not started."))
53
+ break;
54
+ }
55
+ case X3D .X3DConstants .IN_PROGRESS_STATE:
56
+ {
57
+ sizes .text (_("Loading in progress."))
58
+ break;
59
+ }
60
+ case X3D .X3DConstants .FAILED_STATE:
61
+ {
62
+ sizes .text (_("Loading failed."))
63
+ break;
64
+ }
65
+ case X3D .X3DConstants .COMPLETE_STATE:
66
+ {
67
+ sizes .text (`${node .getWidth ()} × ${node .getHeight ()}`);
68
+ break;
69
+ }
70
+ }
71
+ }
72
+
73
+ // Reload handling.
74
+
75
+ const
76
+ _loadState = Symbol (),
77
+ _url = Symbol ();
78
+
79
+ node ._loadState .addFieldCallback (_loadState, loadState);
80
+ node ._url .addFieldCallback (_url, loadNow);
81
+
82
+ loadState (node ._loadState .getValue ());
83
+ loadNow ();
84
+
85
+ this .data ("preview", { loadNow });
86
+
87
+ // Create tooltip.
88
+
89
+ const tooltip = this .popover ({
90
+ preview: true,
91
+ content: preview,
92
+ show: {
93
+ modal: false,
94
+ },
95
+ style: {
96
+ classes: "qtip-tipsy qtip-preview qtip-video",
97
+ },
98
+ events: {
99
+ hide: (event, api) =>
100
+ {
101
+ node ._loadState .removeFieldCallback (_loadState);
102
+ node ._url .removeFieldCallback (_url);
103
+
104
+ this .removeData ("preview");
105
+
106
+ $(".tree-view") .off (".preview");
107
+
108
+ api .destroy (true);
109
+ },
110
+ },
111
+ });
112
+
113
+ $(".tree-view") .on ("scroll.preview", () => this .qtip ("reposition"));
114
+
115
+ return this;
116
+ };
117
+
@@ -1000,6 +1000,8 @@ module .exports = class OutlineEditor extends OutlineRouteGraph
1000
1000
  copy = node .copy (executionContext),
1001
1001
  index = parseInt (element .attr ("index"));
1002
1002
 
1003
+ copy .setup ();
1004
+
1003
1005
  UndoManager .shared .beginUndo (_("Unlink Clone"));
1004
1006
 
1005
1007
  if (node .getName ())