sunrize 1.6.14 → 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 +10 -6
- package/src/Application/Application.js +7 -7
- package/src/Application/Document.js +0 -2
- package/src/Application/Tabs.js +4 -6
- package/src/Controls/AudioPreviewPopover.js +74 -0
- package/src/Controls/MaterialPreviewPopover.js +135 -0
- package/src/Controls/Popover.js +8 -0
- package/src/Controls/TexturePreviewPopover.js +192 -0
- package/src/Controls/VideoPreviewPopover.js +117 -0
- package/src/Editors/OutlineEditor.js +2 -0
- package/src/Editors/OutlineView.js +260 -115
- package/src/Editors/Panel.js +11 -9
- package/src/Editors/ScriptEditor.js +1 -0
- package/src/assets/X3D/MaterialPreview.x3d +177 -0
- package/src/assets/X3D/TexturePreview.x3d +268 -0
- package/src/assets/X3D/Volume.x3d +182 -0
- package/src/assets/themes/default-template.css +54 -29
- package/src/assets/themes/default.css +54 -29
- package/src/assets/themes/system-colors.css +44 -26
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sunrize",
|
|
3
3
|
"productName": "Sunrize X3D Editor",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.7.0",
|
|
5
5
|
"description": "A Multi-Platform X3D Editor",
|
|
6
6
|
"main": "src/main.js",
|
|
7
7
|
"bin": {
|
|
@@ -68,6 +68,10 @@
|
|
|
68
68
|
"url": "https://github.com/create3000"
|
|
69
69
|
}
|
|
70
70
|
],
|
|
71
|
+
"funding": {
|
|
72
|
+
"type": "patreon",
|
|
73
|
+
"url": "https://patreon.com/X_ITE"
|
|
74
|
+
},
|
|
71
75
|
"devDependencies": {
|
|
72
76
|
"@electron-forge/cli": "^7.4.0",
|
|
73
77
|
"@electron-forge/maker-deb": "^7.4.0",
|
|
@@ -81,26 +85,26 @@
|
|
|
81
85
|
"dependencies": {
|
|
82
86
|
"capitalize": "^2.0.4",
|
|
83
87
|
"console": "^0.7.2",
|
|
84
|
-
"electron": "^30.0.
|
|
88
|
+
"electron": "^30.0.9",
|
|
85
89
|
"electron-prompt": "^1.7.0",
|
|
86
90
|
"electron-squirrel-startup": "^1.0.1",
|
|
87
91
|
"electron-tabs": "^1.0.4",
|
|
88
92
|
"fullname": "^5.0.0",
|
|
89
93
|
"jquery": "^3.7.1",
|
|
90
|
-
"jquery-ui-dist": "^1.13.
|
|
94
|
+
"jquery-ui-dist": "^1.13.3",
|
|
91
95
|
"jstree": "^3.3.16",
|
|
92
96
|
"material-icons": "^1.13.12",
|
|
93
|
-
"material-symbols": "^0.
|
|
97
|
+
"material-symbols": "^0.19.0",
|
|
94
98
|
"md5": "^2.3.0",
|
|
95
99
|
"mime-types": "^2.1.35",
|
|
96
|
-
"monaco-editor": "^0.
|
|
100
|
+
"monaco-editor": "^0.49.0",
|
|
97
101
|
"node-localstorage": "^3.0.5",
|
|
98
102
|
"qtip2": "^3.0.3",
|
|
99
103
|
"spectrum-colorpicker2": "^2.0.10",
|
|
100
104
|
"string-similarity": "^4.0.4",
|
|
101
105
|
"tweakpane": "^3.1.10",
|
|
102
106
|
"update-electron-app": "^3.0.0",
|
|
103
|
-
"x_ite": "^9.
|
|
107
|
+
"x_ite": "^9.7.0"
|
|
104
108
|
},
|
|
105
109
|
"config": {
|
|
106
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)
|
package/src/Application/Tabs.js
CHANGED
|
@@ -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
|
+
|
package/src/Controls/Popover.js
CHANGED
|
@@ -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 ())
|