sunrize 1.11.1 → 1.11.3

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.11.1",
4
+ "version": "1.11.3",
5
5
  "description": "A Multi-Platform X3D Editor",
6
6
  "main": "src/main.js",
7
7
  "bin": {
@@ -78,19 +78,20 @@
78
78
  "url": "https://patreon.com/X_ITE"
79
79
  },
80
80
  "devDependencies": {
81
- "@electron-forge/cli": "^7.9.0",
82
- "@electron-forge/maker-deb": "^7.9.0",
83
- "@electron-forge/maker-dmg": "^7.9.0",
84
- "@electron-forge/maker-rpm": "^7.9.0",
85
- "@electron-forge/maker-squirrel": "^7.9.0",
86
- "@electron-forge/maker-zip": "^7.9.0",
87
- "@electron-forge/publisher-github": "^7.9.0",
81
+ "@electron-forge/cli": "^7.10.2",
82
+ "@electron-forge/maker-deb": "^7.10.2",
83
+ "@electron-forge/maker-dmg": "^7.10.2",
84
+ "@electron-forge/maker-rpm": "^7.10.2",
85
+ "@electron-forge/maker-squirrel": "^7.10.2",
86
+ "@electron-forge/maker-zip": "^7.10.2",
87
+ "@electron-forge/publisher-github": "^7.10.2",
88
88
  "shell-tools": "^1.1.9"
89
89
  },
90
90
  "dependencies": {
91
+ "@vscode/codicons": "^0.0.41",
91
92
  "capitalize": "^2.0.4",
92
93
  "console": "^0.7.2",
93
- "electron": "^38.2.1",
94
+ "electron": "^38.4.0",
94
95
  "electron-prompt": "^1.7.0",
95
96
  "electron-squirrel-startup": "^1.0.1",
96
97
  "electron-tabs": "^1.0.4",
@@ -99,17 +100,17 @@
99
100
  "jquery-ui-dist": "^1.13.3",
100
101
  "jstree": "^3.3.17",
101
102
  "material-icons": "^1.13.14",
102
- "material-symbols": "^0.36.2",
103
+ "material-symbols": "^0.38.0",
103
104
  "md5": "^2.3.0",
104
105
  "mime-types": "^3.0.1",
105
- "monaco-editor": "^0.53.0",
106
+ "monaco-editor": "^0.54.0",
106
107
  "node-localstorage": "^3.0.5",
107
108
  "qtip2": "^3.0.3",
108
109
  "spectrum-colorpicker2": "^2.0.10",
109
110
  "string-similarity": "^4.0.4",
110
111
  "tweakpane": "^3.1.10",
111
112
  "update-electron-app": "^3.1.1",
112
- "x_ite": "^12.1.1",
113
- "x3d-traverse": "^1.0.13"
113
+ "x_ite": "^12.1.3",
114
+ "x3d-traverse": "^1.0.22"
114
115
  }
115
116
  }
@@ -180,10 +180,19 @@ module .exports = class Dashboard extends Interface
180
180
  for (const node of nodes)
181
181
  outlineEditor .expandTo (node, { expandObject: true, expandAll: true });
182
182
 
183
- const elements = nodes .map (node => outlineEditor .sceneGraph .find (`.node[node-id=${node .getId ()}]`));
183
+ const elements = nodes .map (node => outlineEditor .sceneGraph
184
+ .find (`:is(.node, .imported-node.proxy)[node-id="${node .getId ()}"]`));
184
185
 
185
- for (const [i, element] of elements .entries ())
186
- outlineEditor .selectNodeElement (element, { add: i > 0 });
186
+ outlineEditor .deselectAll ({ target: false });
187
+
188
+ for (const element of elements)
189
+ {
190
+ if (element .is (".node"))
191
+ outlineEditor .selectNodeElement (element, { add: true });
192
+
193
+ else if (element .is (".imported-node.proxy"))
194
+ outlineEditor .selectPrimaryElement (element, { add: true });
195
+ }
187
196
 
188
197
  // Scroll element into view.
189
198
  // Hide scrollbars during scroll to prevent overlay issue.
@@ -185,6 +185,10 @@ module .exports = class Document extends Interface
185
185
 
186
186
  // Restore
187
187
 
188
+ const pkg = require ("../../package.json");
189
+
190
+ console .info (`Welcome to ${pkg .productName} v${pkg .version}.`);
191
+
188
192
  await this .restoreFile ();
189
193
 
190
194
  if (!this .isInitialScene)
@@ -320,8 +324,8 @@ module .exports = class Document extends Interface
320
324
 
321
325
  const activeElement = this .activeElement;
322
326
 
323
- if (activeElement .is ("input"))
324
- return activeElement .attr ("type") === undefined || activeElement .attr ("type") === "text";
327
+ if (activeElement .is ("input:not([type]), input[type=text]"))
328
+ return true;
325
329
 
326
330
  if (activeElement .is ("textarea"))
327
331
  return true;
@@ -452,7 +456,7 @@ Viewpoint {
452
456
  pkg = require ("../../package.json"),
453
457
  generator = scene .getMetaData ("generator") ?.filter (value => !value .startsWith (pkg .productName)) ?? [ ];
454
458
 
455
- generator .push (`${pkg .productName} V${pkg .version}, ${pkg .homepage}`);
459
+ generator .unshift (`${pkg .productName} V${pkg .version}, ${pkg .homepage}`);
456
460
 
457
461
  if (!scene .getMetaData ("creator") ?.some (value => value .includes (this .fullname)))
458
462
  scene .addMetaData ("creator", this .fullname);
@@ -631,7 +635,7 @@ Viewpoint {
631
635
  if (this .activeElementIsMonacoEditor ())
632
636
  return;
633
637
 
634
- this .sidebar .outlineEditor .copyNodes (true);
638
+ this .sidebar .outlineEditor .copyNodes ();
635
639
  return false;
636
640
  }
637
641
 
@@ -36,8 +36,8 @@ module .exports = new class Hierarchy extends Interface
36
36
  }
37
37
 
38
38
  #targetTypes = new Set ([
39
- X3D .X3DConstants .X3DShapeNode,
40
39
  X3D .X3DConstants .Inline,
40
+ X3D .X3DConstants .X3DShapeNode,
41
41
  ]);
42
42
 
43
43
  target (node)
@@ -70,10 +70,17 @@ module .exports = new class Hierarchy extends Interface
70
70
 
71
71
  const node = object .getValue () .valueOf ();
72
72
 
73
- if (!node .getType () .some (type => this .#targetTypes .has (type)))
73
+ if (!node .getType () .some (type => this .#targetTypes .has (type)) &&
74
+ !(node instanceof X3D .X3DImportedNodeProxy))
75
+ {
74
76
  continue;
77
+ }
78
+
79
+ const target = node .getType () .includes (X3D .X3DConstants .X3DShapeNode)
80
+ ? node .getGeometry () ?.valueOf () ?? node
81
+ : node;
75
82
 
76
- targets .push (node .getGeometry ?.() ?.valueOf () ?? node);
83
+ targets .push (target);
77
84
  }
78
85
 
79
86
  for (const hierarchy of this .#find (targets))
@@ -47,9 +47,12 @@ module .exports = class Dialog extends Interface
47
47
  {
48
48
  // Set default config values.
49
49
 
50
+ defaults .minSize ??= defaults .size;
51
+
50
52
  this .config .file .setDefaultValues (Object .assign ({
51
53
  position: undefined,
52
54
  size: [400, 250],
55
+ minSize: [400, 250],
53
56
  },
54
57
  defaults));
55
58
  }
@@ -58,8 +61,8 @@ module .exports = class Dialog extends Interface
58
61
  {
59
62
  this .element .dialog ({
60
63
  position: { ... this .config .file .position, of: $("body") },
61
- minWidth: this .config .file .getDefaultValue ("size") [0],
62
- minHeight: this .config .file .getDefaultValue ("size") [1],
64
+ minWidth: this .config .file .minSize [0],
65
+ minHeight: this .config .file .minSize [1],
63
66
  width: this .config .file .size [0],
64
67
  height: this .config .file .size [1],
65
68
  })
@@ -5,6 +5,7 @@ const
5
5
  $ = require ("jquery"),
6
6
  electron = require ("electron"),
7
7
  Interface = require ("../Application/Interface"),
8
+ util = require ("util"),
8
9
  _ = require ("../Application/GetText");
9
10
 
10
11
  module .exports = class Console extends Interface
@@ -31,34 +32,103 @@ module .exports = class Console extends Interface
31
32
  this .history = [ ];
32
33
  this .addMessageCallback = this .addMessage .bind (this);
33
34
 
34
- this .console = element;
35
- this .left = $("<div></div>") .addClass ("console-left") .appendTo (this .console);
36
- this .toolbar = $("<div></div>") .addClass (["toolbar", "vertical-toolbar", "console-toolbar"]) .appendTo (this .console);
37
- this .output = $("<div></div>") .addClass (["console-output", "output"]) .attr ("tabindex", 0) .appendTo (this .left);
38
- this .input = $("<div></div>") .addClass ("console-input") .appendTo (this .left);
35
+ this .console = element;
36
+ this .left = $("<div></div>") .addClass ("console-left") .appendTo (this .console);
37
+ this .toolbar = $("<div></div>") .addClass (["toolbar", "vertical-toolbar", "console-toolbar"]) .appendTo (this .console);
38
+
39
+ this .output = $("<div></div>")
40
+ .addClass (["console-output", "output"])
41
+ .attr ("tabindex", 0)
42
+ .on ("keydown", event => this .outputKey (event))
43
+ .appendTo (this .left);
44
+
45
+ this .input = $("<div></div>")
46
+ .addClass ("console-input")
47
+ .appendTo (this .left);
48
+
49
+ // Search Widget
50
+
51
+ this .search = $("<div></div>")
52
+ .addClass ("console-search")
53
+ .appendTo (this .left)
54
+ .hide ();
55
+
56
+ this .search .resizable({
57
+ handles: "w",
58
+ minWidth: 285,
59
+ resize: () => this .config .file .searchWidth = this .search .width (),
60
+ });
61
+
62
+ this .searchInputElements = $("<div></div>")
63
+ .addClass ("console-search-input-elements")
64
+ .appendTo (this .search);
65
+
66
+ this .searchInput = $("<input></input>")
67
+ .attr ("type", "text")
68
+ .attr ("placeholder", _("Find"))
69
+ .addClass ("console-search-input")
70
+ .on ("input", () => this .searchString ())
71
+ .on ("keydown", event => this .searchKey (event))
72
+ .appendTo (this .searchInputElements);
73
+
74
+ this .searchCaseSensitiveButton = $("<div></div>")
75
+ .addClass (["codicon", "codicon-case-sensitive", "console-search-case-sensitive"])
76
+ .on ("click", () => this .searchCaseSensitive (!this .config .file .searchCaseSensitive))
77
+ .appendTo (this .searchInputElements);
78
+
79
+ this .searchStatus = $("<div></div>")
80
+ .addClass ("console-search-status")
81
+ .text ("No results")
82
+ .appendTo (this .search);
83
+
84
+ this .searchPreviousButton = $("<div></div>")
85
+ .addClass (["search-previous", "codicon", "codicon-arrow-up", "disabled"])
86
+ .attr ("tabindex", 0)
87
+ .on ("click", () => this .searchPrevious ())
88
+ .appendTo (this .search);
89
+
90
+ this .searchNextButton = $("<div></div>")
91
+ .addClass (["search-next", "codicon", "codicon-arrow-down", "disabled"])
92
+ .attr ("tabindex", 0)
93
+ .on ("click", () => this .searchNext ())
94
+ .appendTo (this .search);
95
+
96
+ // Toolbar
97
+
98
+ this .searchButton = $("<span></span>")
99
+ .addClass ("material-icons")
100
+ .css ("transform", "scale(1.2)")
101
+ .attr ("title", _("Show search widget."))
102
+ .text ("search")
103
+ .on ("click", () => this .toggleSearch (!this .config .file .search))
104
+ .appendTo (this .toolbar);
105
+
106
+ $("<span></span>") .addClass ("separator") .appendTo (this .toolbar);
39
107
 
40
108
  this .suspendButton = $("<span></span>")
41
109
  .addClass ("material-icons")
42
110
  .attr ("title", _("Suspend console output."))
43
- .text ("cancel")
44
- .appendTo (this .toolbar)
45
- .on ("click", () => this .setSuspendConsole (!this .suspendConsole));
111
+ .text ("pause_circle")
112
+ .on ("click", () => this .setSuspendConsole (!this .suspendConsole))
113
+ .appendTo (this .toolbar);
46
114
 
47
115
  this .clearButton = $("<span></span>")
48
116
  .addClass ("material-icons")
49
117
  .attr ("title", _("Clear console."))
50
118
  .text ("delete_forever")
51
- .appendTo (this .toolbar)
52
- .on ("click", () => this .clearConsole ());
119
+ .on ("click", () => this .clearConsole ())
120
+ .appendTo (this .toolbar);
53
121
 
54
122
  $("<span></span>") .addClass ("separator") .appendTo (this .toolbar);
55
123
 
124
+ // Input
125
+
56
126
  this .textarea = $("<textarea></textarea>")
57
127
  .attr ("placeholder", _("Evaluate X3D Script code here, e.g. type `Browser.name`."))
58
128
  .attr ("tabindex", 0)
59
- .appendTo (this .input)
60
129
  .on ("keydown", event => this .onkeydown (event))
61
- .on ("keyup", event => this .onkeyup (event));
130
+ .on ("keyup", event => this .onkeyup (event))
131
+ .appendTo (this .input);
62
132
 
63
133
  if (this .console .attr ("id") !== "console")
64
134
  {
@@ -75,10 +145,21 @@ module .exports = class Console extends Interface
75
145
  {
76
146
  super .configure ();
77
147
 
78
- this .config .file .setDefaultValues ({ history: [ ] });
148
+ this .config .file .setDefaultValues ({
149
+ history: [ ],
150
+ search: false,
151
+ searchWidth: 285,
152
+ searchCaseSensitive: false,
153
+ });
79
154
 
80
155
  this .history = this .config .file .history .slice (-this .HISTORY_MAX);
81
156
  this .historyIndex = this .history .length;
157
+
158
+ this .output .scrollTop (this .output .prop ("scrollHeight"));
159
+
160
+ this .search .width (this .config .file .searchWidth);
161
+ this .toggleSearch (this .config .file .search);
162
+ this .searchCaseSensitive ();
82
163
  }
83
164
 
84
165
  async set_browser_initialized ()
@@ -98,6 +179,8 @@ module .exports = class Console extends Interface
98
179
  excludes = [
99
180
  "The vm module of Node.js is unsupported",
100
181
  "Uncaught TypeError: Cannot read properties of null (reading 'removeChild')",
182
+ "aria-hidden",
183
+ "<line>",
101
184
  // "Invalid asm.js: Invalid member of stdlib",
102
185
  ];
103
186
 
@@ -108,8 +191,14 @@ module .exports = class Console extends Interface
108
191
 
109
192
  const
110
193
  classes = [this .logLevels [level] ?? "log", this .logClasses [level]],
111
- title = sourceId ? `${sourceId}:${line}`: "",
112
- text = $("<p></p>") .addClass (classes) .attr ("title", title) .text (message);
194
+ title = sourceId ? `${sourceId}:${line}`: "";
195
+
196
+ const text = $(message .split ("\n")
197
+ .map (line => $("<p></p>")
198
+ .addClass (classes)
199
+ .attr ("title", title)
200
+ .text (line)
201
+ .get (0)));
113
202
 
114
203
  if (this .messageTime && performance .now () - this .messageTime > 1000)
115
204
  this .output .append ($("<p></p>") .addClass ("splitter"));
@@ -132,6 +221,8 @@ module .exports = class Console extends Interface
132
221
 
133
222
  this .output .append (text);
134
223
  this .output .scrollTop (this .output .prop ("scrollHeight"));
224
+
225
+ this .findElements (text, this .currentElement, false);
135
226
  }
136
227
 
137
228
  setSuspendConsole (value)
@@ -158,6 +249,7 @@ module .exports = class Console extends Interface
158
249
 
159
250
  this .output .empty ();
160
251
  this .addMessage (null, "info", __filename, 0, `Console cleared at ${new Date () .toLocaleTimeString ()}.`);
252
+ this .searchString ();
161
253
  }
162
254
 
163
255
  onkeydown (event)
@@ -244,13 +336,156 @@ module .exports = class Console extends Interface
244
336
 
245
337
  try
246
338
  {
247
- console .debug (String (this .scriptNode .evaluate (text)));
339
+ console .debug (this .scriptNode .evaluate (text));
248
340
  }
249
341
  catch (error)
250
342
  {
251
- console .error (`${error .name}: ${error .message}`);
343
+ console .error (error);
252
344
  }
253
345
 
254
346
  this .textarea .val ("");
255
347
  }
348
+
349
+ toggleSearch (visible)
350
+ {
351
+ this .config .file .search = visible;
352
+
353
+ if (visible)
354
+ {
355
+ this .searchButton .addClass ("active");
356
+ this .search .show ();
357
+ this .searchInput .trigger ("focus");
358
+
359
+ this .searchString ();
360
+ }
361
+ else
362
+ {
363
+ this .searchButton .removeClass ("active");
364
+ this .search .hide ();
365
+ this .output .find (".selected") .removeClass ("selected");
366
+ }
367
+ }
368
+
369
+ searchString ()
370
+ {
371
+ this .foundElements = [ ];
372
+
373
+ this .findElements (this .output .children (), 0, true);
374
+ }
375
+
376
+ findElements (elements, currentElement, scroll)
377
+ {
378
+ if (this .search .is (":hidden"))
379
+ return;
380
+
381
+ const
382
+ toString = this .searchCaseSensitiveButton .hasClass ("active") ? "toString" : "toLowerCase",
383
+ string = this .searchInput .val () [toString] ();
384
+
385
+ if (!string)
386
+ return;
387
+
388
+ this .foundElements = this .foundElements .concat (Array .from (elements, element => $(element))
389
+ .filter (element => element .text () [toString] () .includes (string)));
390
+
391
+ this .updateCurrentElement (currentElement, scroll);
392
+ }
393
+
394
+ searchKey (event)
395
+ {
396
+ switch (event .key)
397
+ {
398
+ case "Enter":
399
+ {
400
+ if (!this .foundElements .length)
401
+ break;
402
+
403
+ if (event .shiftKey)
404
+ this .searchPrevious ();
405
+ else
406
+ this .searchNext ();
407
+
408
+ break;
409
+ }
410
+ }
411
+ }
412
+
413
+ searchCaseSensitive (value = this .config .file .searchCaseSensitive)
414
+ {
415
+ this .config .file .searchCaseSensitive = value;
416
+
417
+ if (this .config .file .searchCaseSensitive)
418
+ this .searchCaseSensitiveButton .addClass ("active");
419
+ else
420
+ this .searchCaseSensitiveButton .removeClass ("active");
421
+
422
+ this .searchInput .trigger ("focus");
423
+
424
+ this .searchString ();
425
+ }
426
+
427
+ searchPrevious ()
428
+ {
429
+ this .updateCurrentElement (this .currentElement - 1);
430
+ }
431
+
432
+ searchNext ()
433
+ {
434
+ this .updateCurrentElement (this .currentElement + 1);
435
+ }
436
+
437
+ updateCurrentElement (value, scroll = true)
438
+ {
439
+ if (value < 0)
440
+ value = this .foundElements .length - 1;
441
+
442
+ if (value >= this .foundElements .length)
443
+ value = 0;
444
+
445
+ this .currentElement = value;
446
+
447
+ this .output .find (".selected") .removeClass ("selected");
448
+
449
+ if (this .foundElements .length)
450
+ {
451
+ const element = this .foundElements [this .currentElement];
452
+
453
+ element .addClass ("selected");
454
+
455
+ if (scroll)
456
+ {
457
+ element .get (0) .scrollIntoView ({ block: "center", inline: "start", behavior: "smooth" });
458
+ $(window) .scrollTop (0);
459
+ }
460
+
461
+ this .searchStatus .text (util .format (_("%d of %d"), this .currentElement + 1, this .foundElements .length));
462
+ this .searchPreviousButton .removeClass ("disabled");
463
+ this .searchNextButton .removeClass ("disabled");
464
+ }
465
+ else
466
+ {
467
+ this .searchStatus .text (`No results`);
468
+ this .searchPreviousButton .addClass ("disabled");
469
+ this .searchNextButton .addClass ("disabled");
470
+ }
471
+ }
472
+
473
+ outputKey (event)
474
+ {
475
+ switch (event .key)
476
+ {
477
+ case "f":
478
+ {
479
+ if (event .ctrlKey || event .metaKey)
480
+ {
481
+ this .searchInput .val (window .getSelection () .toString ());
482
+ this .searchInput .trigger ("select");
483
+
484
+ this .toggleSearch (true);
485
+ }
486
+
487
+ break;
488
+ }
489
+ }
490
+ }
256
491
  };
@@ -27,7 +27,7 @@ module .exports = new class Library extends Dialog
27
27
 
28
28
  configure ()
29
29
  {
30
- super .configure ({ size: [600, 400] });
30
+ super .configure ({ size: [600, 400], minSize: [400, 300] });
31
31
 
32
32
  // Set default config values.
33
33
 
@@ -26,7 +26,7 @@ module .exports = class Materials extends LibraryPane
26
26
 
27
27
  this .#list = $("<ul></ul>")
28
28
  .appendTo (this .output)
29
- .addClass ("library-list");
29
+ .addClass (["library-list", "materials"]);
30
30
 
31
31
  const
32
32
  canvas = $("<x3d-canvas preserveDrawingBuffer='true' xrSessionMode='NONE'></x3d-canvas>"),
@@ -51,9 +51,11 @@ module .exports = class Materials extends LibraryPane
51
51
 
52
52
  nodes .push ($("<li></li>")
53
53
  .addClass (["node", "icon"])
54
- .text (`${group .getNodeName ()} ${c + 1}`)
55
54
  .attr ("group", g)
56
55
  .attr ("child", c)
56
+ .append ($("<span></span>")
57
+ .addClass ("text")
58
+ .text (`${group .getNodeName ()} ${c + 1}`))
57
59
  .appendTo (this .#list)
58
60
  .on ("dblclick", () => this .importX3D (material .getNodeName (), material .toXMLString ())));
59
61
  }
@@ -65,7 +67,7 @@ module .exports = class Materials extends LibraryPane
65
67
  .css ({ "position": "absolute", "visibility": "hidden" })
66
68
  .prependTo ($("body"));
67
69
 
68
- await browser .resize (25, 25);
70
+ await browser .resize (256, 256);
69
71
  await browser .replaceWorld (scene);
70
72
 
71
73
  for (const element of Array .from (this .output .find (".node"), e => $(e)))