sunrize 1.7.42 → 1.7.44

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.7.42",
4
+ "version": "1.7.44",
5
5
  "description": "A Multi-Platform X3D Editor",
6
6
  "main": "src/main.js",
7
7
  "bin": {
@@ -58,16 +58,17 @@ module .exports = class Application
58
58
  };
59
59
 
60
60
  this .config .setDefaultValues ({
61
- position: [undefined, undefined],
62
- size: [1100, 680],
63
- maximized: false,
64
- fullscreen: false,
65
61
  autoSave: true,
62
+ browserUpdate: false,
66
63
  expandExternProtoDeclarations: true,
67
- expandPrototypeInstances: true,
68
64
  expandInlineNodes: true,
65
+ expandPrototypeInstances: true,
66
+ fullscreen: false,
67
+ maximized: false,
68
+ position: [undefined, undefined],
69
69
  recentDocuments: [ ],
70
70
  recentLocations: [ ],
71
+ size: [1100, 680],
71
72
  });
72
73
 
73
74
  Template .create (path .join (__dirname, "../assets/html/application-template.html"));
@@ -286,6 +287,17 @@ module .exports = class Application
286
287
  click: () => this .mainWindow .webContents .send ("reload"),
287
288
  },
288
289
  { type: "separator" },
290
+ {
291
+ label: _("Default Play Button State"),
292
+ type: "checkbox",
293
+ checked: this .config .browserUpdate,
294
+ click: () =>
295
+ {
296
+ this .config .browserUpdate = !this .config .browserUpdate;
297
+ this .mainWindow .webContents .send ("browser-update", this .config .browserUpdate);
298
+ },
299
+ },
300
+ { type: "separator" },
289
301
  {
290
302
  label: _("Save"),
291
303
  accelerator: "CmdOrCtrl+S",
@@ -2,6 +2,7 @@
2
2
 
3
3
  const
4
4
  $ = require ("jquery"),
5
+ electron = require ("electron"),
5
6
  Interface = require ("./Interface"),
6
7
  Editor = require("../Undo/Editor"),
7
8
  _ = require ("./GetText");
@@ -65,18 +66,20 @@ module .exports = class Dashboard extends Interface
65
66
  .text ("edit_note")
66
67
  .appendTo (this .toolbar)
67
68
  .on ("click", () => this .togglePanel (!this .config .file .panel));
69
+
70
+ electron .ipcRenderer .on ("browser-update", (event, value) => this .config .global .play = value);
68
71
  }
69
72
 
70
73
  configure ()
71
74
  {
72
75
  this .config .file .setDefaultValues ({
73
76
  pointer: "arrow",
74
- play: false,
77
+ play: this .config .global .play,
75
78
  panel: false,
76
79
  });
77
80
 
78
81
  this [this .config .file .pointer] ();
79
- this .play (this .config .file .play && !this .isInitialScene);
82
+ this .play ((this .config .file .play) && !this .isInitialScene);
80
83
  this .straighten (this .browser .getBrowserOption ("StraightenHorizon"));
81
84
 
82
85
  if (this .config .file .panel)
@@ -62,7 +62,8 @@ module .exports = new class Tabs
62
62
  $(window) .on ("beforeunload", () => this .close ());
63
63
 
64
64
  // Forward Actions
65
-
65
+
66
+ this .forwardToAllTabs ("browser-update");
66
67
  this .forwardToAllTabs ("auto-save");
67
68
  this .forwardToActiveTab ("export-as");
68
69
 
@@ -46,7 +46,7 @@ $.fn.addPrototypePopover = function (executionContext, type)
46
46
  events: {
47
47
  show (event, api)
48
48
  {
49
- nameInput .validate (Editor .Id, () =>
49
+ nameInput .off () .validate (Editor .Id, () =>
50
50
  {
51
51
  electron .shell .beep ();
52
52
  nameInput .highlight ();
@@ -135,7 +135,7 @@ $.fn.editUserDefinedFieldPopover = function (executionContext, node, field = -1)
135
135
  events: {
136
136
  show (event, api)
137
137
  {
138
- nameInput .validate (Editor .Id, () =>
138
+ nameInput .off () .validate (Editor .Id, () =>
139
139
  {
140
140
  electron .shell .beep ();
141
141
  nameInput .highlight ();
@@ -26,7 +26,7 @@ $.fn.exportNodePopover = function (node, oldExportedName)
26
26
  events: {
27
27
  show: (event, api) =>
28
28
  {
29
- nameInput .validate (Editor .Id, () =>
29
+ nameInput .off () .validate (Editor .Id, () =>
30
30
  {
31
31
  electron .shell .beep ();
32
32
  nameInput .highlight ();
@@ -26,7 +26,7 @@ $.fn.importNodePopover = function (inlineNode, exportedName, oldImportedName)
26
26
  events: {
27
27
  show: (event, api) =>
28
28
  {
29
- nameInput .validate (Editor .Id, () =>
29
+ nameInput .off () .validate (Editor .Id, () =>
30
30
  {
31
31
  electron .shell .beep ();
32
32
  nameInput .highlight ();
@@ -1,11 +1,11 @@
1
- "use strict"
1
+ "use strict";
2
2
 
3
3
  const
4
4
  $ = require ("jquery"),
5
- _ = require ("../Application/GetText")
5
+ _ = require ("../Application/GetText");
6
6
 
7
- require ("./Popover")
8
- require ("./RenameNodeInput")
7
+ require ("./Popover");
8
+ require ("./RenameNodeInput");
9
9
 
10
10
  $.fn.renameNodePopover = function (node)
11
11
  {
@@ -13,7 +13,7 @@ $.fn.renameNodePopover = function (node)
13
13
 
14
14
  const nameInput = $("<input></input>")
15
15
  .attr ("placeholder", _("Enter name"))
16
- .renameNodeInput (node)
16
+ .renameNodeInput (node);
17
17
 
18
18
  // Create tooltip.
19
19
 
@@ -22,19 +22,19 @@ $.fn.renameNodePopover = function (node)
22
22
  events: {
23
23
  show: (event, api) =>
24
24
  {
25
- nameInput .on ("keydown.renameNodePopover", (event) =>
25
+ nameInput .off (".renameNodePopover") .on ("keydown.renameNodePopover", (event) =>
26
26
  {
27
27
  if (event .key !== "Enter")
28
- return
28
+ return;
29
29
 
30
- api .toggle (false)
30
+ api .toggle (false);
31
31
  })
32
32
 
33
- setTimeout (() => nameInput .trigger ("select"), 1)
33
+ setTimeout (() => nameInput .trigger ("select"), 1);
34
34
  },
35
35
  },
36
- })
36
+ });
37
37
 
38
- return this
39
- }
38
+ return this;
39
+ };
40
40
 
@@ -97,7 +97,9 @@ module .exports = new class Library extends Dialog
97
97
 
98
98
  this .button ($(button ?? this .buttons .children () [0]));
99
99
 
100
+ this .input .val ("");
100
101
  this .input .trigger ("focus");
102
+ this .filter ();
101
103
  }
102
104
 
103
105
  button (button)
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- module .exports = class LibraryPanel
3
+ module .exports = class LibraryPane
4
4
  {
5
5
  #library;
6
6
 
@@ -9,6 +9,11 @@ module .exports = class LibraryPanel
9
9
  this .#library = library;
10
10
  }
11
11
 
12
+ get config ()
13
+ {
14
+ return this .#library .config;
15
+ }
16
+
12
17
  get browser ()
13
18
  {
14
19
  return this .#library .browser;
@@ -17,6 +17,14 @@ module .exports = class NodesLibrary extends LibraryPane
17
17
 
18
18
  open ()
19
19
  {
20
+ // Set default config values.
21
+
22
+ this .config .global .setDefaultValues ({
23
+ recentNodes: [ ],
24
+ });
25
+
26
+ // Clear output.
27
+
20
28
  this .#list ?.remove ();
21
29
  this .#list = undefined;
22
30
  }
@@ -48,7 +56,32 @@ module .exports = class NodesLibrary extends LibraryPane
48
56
  .sort ((a, b) => a .typeName .localeCompare (b .typeName))
49
57
  .sort ((a, b) => a .componentInfo .name .localeCompare (b .componentInfo .name));
50
58
 
51
- // Create list for proto elements
59
+ // Get recently used elements.
60
+
61
+ const recentNodes = this .config .global .recentNodes .map (typeName => this .browser .getConcreteNode (typeName));
62
+
63
+ // Create list for recently used elements.
64
+
65
+ if (recentNodes .length)
66
+ {
67
+ $("<li></li>")
68
+ .addClass ("component")
69
+ .attr ("name", "recent")
70
+ .text ("Recently Used Nodes")
71
+ .appendTo (this .#list);
72
+
73
+ for (const node of recentNodes)
74
+ {
75
+ $("<li></li>")
76
+ .addClass ("node")
77
+ .text (node .typeName)
78
+ .attr ("componentName", node .componentInfo .name)
79
+ .appendTo (this .#list)
80
+ .on ("dblclick", () => this .createNode (node .typeName, node .componentInfo .name));
81
+ }
82
+ }
83
+
84
+ // Create list for proto elements.
52
85
 
53
86
  if (protos .length)
54
87
  {
@@ -129,6 +162,13 @@ module .exports = class NodesLibrary extends LibraryPane
129
162
 
130
163
  async createNode (typeName, componentName)
131
164
  {
165
+ const recentNodes = this .config .global .recentNodes .filter (name => name !== typeName);
166
+
167
+ recentNodes .unshift (typeName);
168
+ recentNodes .splice (10);
169
+
170
+ this .config .global .recentNodes = recentNodes;
171
+
132
172
  UndoManager .shared .beginUndo (_("Create Node %s"), typeName);
133
173
 
134
174
  await Editor .addComponent (this .executionContext, componentName);
@@ -1909,7 +1909,7 @@ module .exports = class OutlineEditor extends OutlineRouteGraph
1909
1909
 
1910
1910
  const
1911
1911
  target = $(event .target),
1912
- element = target .closest (".node, .exported-node", this .sceneGraph),
1912
+ element = target .closest (".node, .imported-node, .exported-node", this .sceneGraph),
1913
1913
  layerNode = this .getNode (element),
1914
1914
  layerSet = this .browser .getWorld () .getLayerSet (),
1915
1915
  index = layerSet ._layers .findIndex (node => node ?.getValue () .valueOf () === layerNode);
@@ -1927,7 +1927,7 @@ module .exports = class OutlineEditor extends OutlineRouteGraph
1927
1927
  {
1928
1928
  const
1929
1929
  target = $(event .target),
1930
- element = target .closest (".node, .exported-node", this .sceneGraph),
1930
+ element = target .closest (".node, .imported-node, .exported-node", this .sceneGraph),
1931
1931
  node = this .getNode (element);
1932
1932
 
1933
1933
  event .preventDefault ();
@@ -1952,7 +1952,7 @@ module .exports = class OutlineEditor extends OutlineRouteGraph
1952
1952
  {
1953
1953
  const
1954
1954
  target = $(event .target),
1955
- element = target .closest (".node, .exported-node", this .sceneGraph),
1955
+ element = target .closest (".node, .imported-node, .exported-node", this .sceneGraph),
1956
1956
  node = this .getNode (element);
1957
1957
 
1958
1958
  event .preventDefault ();
@@ -1965,7 +1965,7 @@ module .exports = class OutlineEditor extends OutlineRouteGraph
1965
1965
  {
1966
1966
  const
1967
1967
  target = $(event .target),
1968
- element = target .closest (".node, .exported-node", this .sceneGraph),
1968
+ element = target .closest (".node, .imported-node, .exported-node", this .sceneGraph),
1969
1969
  node = this .getNode (element);
1970
1970
 
1971
1971
  event .preventDefault ();
@@ -1092,6 +1092,9 @@ module .exports = class OutlineView extends Interface
1092
1092
  {
1093
1093
  case X3D .X3DConstants .X3DLayerNode:
1094
1094
  {
1095
+ if (node .getExecutionContext () !== this .executionContext)
1096
+ continue;
1097
+
1095
1098
  buttons .push ($("<span></span>")
1096
1099
  .attr ("order", "2")
1097
1100
  .attr ("title", _("Activate layer."))
@@ -1247,7 +1250,9 @@ module .exports = class OutlineView extends Interface
1247
1250
  if (!this .browser .getActiveLayer ())
1248
1251
  return;
1249
1252
 
1250
- this .sceneGraph .find (`.node[node-id=${this .browser .getActiveLayer () .getId ()}], .exported-node[node-id=${this .browser .getActiveLayer () .getId ()}]`)
1253
+ this .sceneGraph .find (`.node[node-id=${this .browser .getActiveLayer () .getId ()}],
1254
+ .imported-node[node-id=${this .browser .getActiveLayer () .getId ()}],
1255
+ .exported-node[node-id=${this .browser .getActiveLayer () .getId ()}]`)
1251
1256
  .find ("> .item .activate-layer")
1252
1257
  .removeClass ("off")
1253
1258
  .addClass ("green");
@@ -1256,7 +1261,9 @@ module .exports = class OutlineView extends Interface
1256
1261
  updateNodeBound (node)
1257
1262
  {
1258
1263
  this .sceneGraph
1259
- .find (`.node[node-id=${node .getId ()}], .exported-node[node-id=${node .getId ()}]`)
1264
+ .find (`.node[node-id=${node .getId ()}],
1265
+ .imported-node[node-id=${node .getId ()}],
1266
+ .exported-node[node-id=${node .getId ()}]`)
1260
1267
  .find ("> .item .bind-node")
1261
1268
  .removeClass (["on", "off"])
1262
1269
  .addClass (node ._isBound .getValue () ? "on" : "off")
@@ -1268,7 +1275,10 @@ module .exports = class OutlineView extends Interface
1268
1275
  const [className] = this .getLoadState (node .checkLoadState (), node .getTypeName ());
1269
1276
 
1270
1277
  this .sceneGraph
1271
- .find (`.node[node-id=${node .getId ()}], .exported-node[node-id=${node .getId ()}], .externproto[node-id=${node .getId ()}]`)
1278
+ .find (`.node[node-id=${node .getId ()}],
1279
+ .imported-node[node-id=${node .getId ()}],
1280
+ .exported-node[node-id=${node .getId ()}],
1281
+ .externproto[node-id=${node .getId ()}]`)
1272
1282
  .find ("> .item .reload-node")
1273
1283
  .removeClass (["not-started-state", "in-progress-state", "complete-state", "failed-state"])
1274
1284
  .addClass (className);
@@ -1279,7 +1289,9 @@ module .exports = class OutlineView extends Interface
1279
1289
  const buttons = [ ];
1280
1290
 
1281
1291
  buttons .push (this .sceneGraph
1282
- .find (`.node[node-id=${node .getId ()}], .exported-node[node-id=${node .getId ()}]`)
1292
+ .find (`.node[node-id=${node .getId ()}],
1293
+ .imported-node[node-id=${node .getId ()}],
1294
+ .exported-node[node-id=${node .getId ()}]`)
1283
1295
  .find ("> .item .play-node")
1284
1296
  .removeClass (["on", "off"])
1285
1297
  .addClass (node ._isPaused .getValue () ? "on" : "off")
@@ -1287,13 +1299,17 @@ module .exports = class OutlineView extends Interface
1287
1299
  .text (node ._isActive .getValue () ? "pause" : "play_arrow"));
1288
1300
 
1289
1301
  buttons .push (this .sceneGraph
1290
- .find (`.node[node-id=${node .getId ()}], .exported-node[node-id=${node .getId ()}]`)
1302
+ .find (`.node[node-id=${node .getId ()}],
1303
+ .imported-node[node-id=${node .getId ()}],
1304
+ .exported-node[node-id=${node .getId ()}]`)
1291
1305
  .find ("> .item .stop-node")
1292
1306
  .removeClass (["on", "off"])
1293
1307
  .addClass (node ._isActive .getValue () ? "on" : "off"));
1294
1308
 
1295
1309
  buttons .push (this .sceneGraph
1296
- .find (`.node[node-id=${node .getId ()}], .exported-node[node-id=${node .getId ()}]`)
1310
+ .find (`.node[node-id=${node .getId ()}],
1311
+ .imported-node[node-id=${node .getId ()}],
1312
+ .exported-node[node-id=${node .getId ()}]`)
1297
1313
  .find ("> .item .loop-node")
1298
1314
  .removeClass (["on", "off"])
1299
1315
  .addClass (node ._loop .getValue () ? "on" : "off"));
@@ -1309,7 +1325,7 @@ module .exports = class OutlineView extends Interface
1309
1325
 
1310
1326
  isInParents (parent, node)
1311
1327
  {
1312
- return parent .closest (".node[node-id=" + node .getId () + "]", this .sceneGraph) .length;
1328
+ return parent .closest (`.node[node-id=${node .getId ()}]`, this .sceneGraph) .length;
1313
1329
  }
1314
1330
 
1315
1331
  #importedNodeSymbol = Symbol ();
@@ -2710,7 +2726,9 @@ module .exports = class OutlineView extends Interface
2710
2726
 
2711
2727
  nodeCloseClones (element)
2712
2728
  {
2713
- const opened = this .sceneGraph .find (`.node[node-id=${element .attr ("node-id")}], .imported-node[node-id=${element .attr ("node-id")}], .exported-node[node-id=${element .attr ("node-id")}]`);
2729
+ const opened = this .sceneGraph .find (`.node[node-id=${element .attr ("node-id")}],
2730
+ .imported-node[node-id=${element .attr ("node-id")}],
2731
+ .exported-node[node-id=${element .attr ("node-id")}]`);
2714
2732
 
2715
2733
  opened .each (function (key, value)
2716
2734
  {
@@ -2852,8 +2870,8 @@ module .exports = class OutlineView extends Interface
2852
2870
  element .find (".scene") .addBack (".scene") .each ((i, e) =>
2853
2871
  {
2854
2872
  const
2855
- element = $(e),
2856
- scene = this .getNode (element);
2873
+ child = $(e),
2874
+ scene = this .getNode (child);
2857
2875
 
2858
2876
  scene .externprotos .removeInterest ("updateSceneSubtree", this);
2859
2877
  scene .protos .removeInterest ("updateSceneSubtree", this);
@@ -2874,8 +2892,8 @@ module .exports = class OutlineView extends Interface
2874
2892
  element .find (".externproto") .addBack (".externproto") .each ((i, e) =>
2875
2893
  {
2876
2894
  const
2877
- element = $(e),
2878
- node = this .getNode (element);
2895
+ child = $(e),
2896
+ node = this .getNode (child);
2879
2897
 
2880
2898
  node .getLoadState () .removeFieldCallback (this .#updateNodeSymbol);
2881
2899
  });
@@ -2885,12 +2903,12 @@ module .exports = class OutlineView extends Interface
2885
2903
  element .find (".node:not([node-id=NULL]), .exported-node")
2886
2904
  .addBack (".node:not([node-id=NULL]), .exported-node") .each ((i, e) =>
2887
2905
  {
2888
- const element = $(e);
2906
+ const child = $(e);
2889
2907
 
2890
- if (!element .jstree ("is_open", element))
2908
+ if (!child .jstree ("is_open", child))
2891
2909
  return;
2892
2910
 
2893
- const node = this .getNode (element);
2911
+ const node = this .getNode (child);
2894
2912
 
2895
2913
  node .getPredefinedFields () .removeInterest ("updateNode", this);
2896
2914
  node .getUserDefinedFields () .removeInterest ("updateNode", this);
@@ -2911,8 +2929,17 @@ module .exports = class OutlineView extends Interface
2911
2929
  element .find (".node:not([node-id=NULL])") .each ((i, e) =>
2912
2930
  {
2913
2931
  const
2914
- element = $(e),
2915
- node = this .getNode (element);
2932
+ child = $(e),
2933
+ node = this .getNode (child);
2934
+
2935
+ // If node is somewhere else, don't disconnect.
2936
+ if (Array .from (this .sceneGraph .find (`.node[node-id="${node .getId ()}"],
2937
+ .imported-node[node-id="${node .getId ()}"],
2938
+ .exported-node[node-id="${node .getId ()}"]`))
2939
+ .some (s => !$(s) .closest (element) .length))
2940
+ {
2941
+ return;
2942
+ }
2916
2943
 
2917
2944
  node .typeName_changed .removeFieldCallback (this .#nodeSymbol);
2918
2945
  node .name_changed .removeFieldCallback (this .#nodeSymbol);
@@ -2947,8 +2974,8 @@ module .exports = class OutlineView extends Interface
2947
2974
  element .find (".exported-node") .each ((i, e) =>
2948
2975
  {
2949
2976
  const
2950
- element = $(e),
2951
- node = this .getNode (element);
2977
+ child = $(e),
2978
+ node = this .getNode (child);
2952
2979
 
2953
2980
  node .typeName_changed .removeFieldCallback (this .#exportedNodeSymbol);
2954
2981
  node .name_changed .removeFieldCallback (this .#exportedNodeSymbol);
@@ -2957,8 +2984,8 @@ module .exports = class OutlineView extends Interface
2957
2984
  element .find (".field, .special") .each ((i, e) =>
2958
2985
  {
2959
2986
  const
2960
- element = $(e),
2961
- field = this .getField (element);
2987
+ child = $(e),
2988
+ field = this .getField (child);
2962
2989
 
2963
2990
  field .removeReferencesCallback (this .#fieldSymbol);
2964
2991
  field .removeRouteCallback (this .#fieldSymbol);
@@ -2974,8 +3001,8 @@ module .exports = class OutlineView extends Interface
2974
3001
  element .each ((i, e) =>
2975
3002
  {
2976
3003
  const
2977
- element = $(e),
2978
- field = this .getField (element);
3004
+ child = $(e),
3005
+ field = this .getField (child);
2979
3006
 
2980
3007
  field .removeRouteCallback (this .#routesFullSymbol);
2981
3008
  field .removeFieldCallback (this .#fieldValueSymbol);
@@ -3013,7 +3040,7 @@ module .exports = class OutlineView extends Interface
3013
3040
  const
3014
3041
  icon = $(event .currentTarget) ,
3015
3042
  item = icon .closest (".item", this .sceneGraph),
3016
- element = icon .closest (".node, .exported-node", this .sceneGraph),
3043
+ element = icon .closest (".node, .imported-node, .exported-node", this .sceneGraph),
3017
3044
  node = this .objects .get (parseInt (element .attr ("node-id"))),
3018
3045
  on = !!item .attr ("data-hasqtip");
3019
3046
 
@@ -3084,7 +3111,7 @@ module .exports = class OutlineView extends Interface
3084
3111
  {
3085
3112
  const
3086
3113
  target = $(event .target),
3087
- element = target .closest (".node, .exported-node", this .sceneGraph),
3114
+ element = target .closest (".node, .imported-node, .exported-node", this .sceneGraph),
3088
3115
  node = this .getNode (element),
3089
3116
  hidden = !node .isHidden ();
3090
3117
 
@@ -3093,7 +3120,9 @@ module .exports = class OutlineView extends Interface
3093
3120
 
3094
3121
  node .setHidden (hidden);
3095
3122
 
3096
- this .sceneGraph .find (`.node[node-id=${node .getId ()}], .exported-node[node-id=${node .getId ()}]`)
3123
+ this .sceneGraph .find (`.node[node-id=${node .getId ()}],
3124
+ .imported-node[node-id=${node .getId ()}],
3125
+ .exported-node[node-id=${node .getId ()}]`)
3097
3126
  .find ("> .item .toggle-visibility")
3098
3127
  .removeClass (["on", "off"])
3099
3128
  .addClass (hidden ? "off" : "on")
@@ -3104,7 +3133,7 @@ module .exports = class OutlineView extends Interface
3104
3133
  {
3105
3134
  const
3106
3135
  target = $(event .target),
3107
- element = target .closest (".node, .exported-node", this .sceneGraph),
3136
+ element = target .closest (".node, .imported-node, .exported-node", this .sceneGraph),
3108
3137
  node = this .getNode (element),
3109
3138
  tool = node .getTool ();
3110
3139
 
@@ -3123,7 +3152,9 @@ module .exports = class OutlineView extends Interface
3123
3152
 
3124
3153
  node .setUserData (_changing, true);
3125
3154
 
3126
- this .sceneGraph .find (`.node[node-id=${node .getId ()}] > .item .toggle-tool, .exported-node[node-id=${node .getId ()}] > .item .toggle-tool`)
3155
+ this .sceneGraph .find (`.node[node-id=${node .getId ()}] > .item .toggle-tool,
3156
+ .imported-node[node-id=${node .getId ()}] > .item .toggle-tool,
3157
+ .exported-node[node-id=${node .getId ()}] > .item .toggle-tool`)
3127
3158
  .removeClass (["on", "off"])
3128
3159
  .addClass (tool ? "off" : "on");
3129
3160
  }
@@ -3134,7 +3165,7 @@ module .exports = class OutlineView extends Interface
3134
3165
  {
3135
3166
  const
3136
3167
  target = $(event .target),
3137
- element = target .closest (".node, .exported-node", this .sceneGraph),
3168
+ element = target .closest (".node, .imported-node, .exported-node", this .sceneGraph),
3138
3169
  node = this .getNode (element);
3139
3170
 
3140
3171
  event .preventDefault ();
@@ -3153,7 +3184,7 @@ module .exports = class OutlineView extends Interface
3153
3184
  {
3154
3185
  const
3155
3186
  target = $(event .target),
3156
- element = target .closest (".node, .exported-node, .externproto", this .sceneGraph),
3187
+ element = target .closest (".node, .imported-node, .exported-node, .externproto", this .sceneGraph),
3157
3188
  item = target .closest (".item"),
3158
3189
  node = this .getNode (element);
3159
3190
 
@@ -3188,7 +3219,9 @@ module .exports = class OutlineView extends Interface
3188
3219
 
3189
3220
  node .setHidden (node .getType () .includes (X3D .X3DConstants .X3DShapeNode));
3190
3221
 
3191
- this .sceneGraph .find (`.node[node-id=${node .getId ()}], .exported-node[node-id=${node .getId ()}]`)
3222
+ this .sceneGraph .find (`.node[node-id=${node .getId ()}],
3223
+ .imported-node[node-id=${node .getId ()}],
3224
+ .exported-node[node-id=${node .getId ()}]`)
3192
3225
  .find ("> .item .toggle-visibility")
3193
3226
  .removeClass (["on", "off"])
3194
3227
  .addClass (node .isHidden () ? "off" : "on")
@@ -3214,7 +3247,9 @@ module .exports = class OutlineView extends Interface
3214
3247
 
3215
3248
  node .setHidden (false);
3216
3249
 
3217
- this .sceneGraph .find (`.node[node-id=${node .getId ()}], .exported-node[node-id=${node .getId ()}]`)
3250
+ this .sceneGraph .find (`.node[node-id=${node .getId ()}],
3251
+ .imported-node[node-id=${node .getId ()}],
3252
+ .exported-node[node-id=${node .getId ()}]`)
3218
3253
  .find ("> .item .toggle-visibility")
3219
3254
  .removeClass ("off")
3220
3255
  .addClass ("on")
@@ -3238,7 +3273,9 @@ module .exports = class OutlineView extends Interface
3238
3273
 
3239
3274
  node .setHidden (false);
3240
3275
 
3241
- this .sceneGraph .find (`.node[node-id=${node .getId ()}], .exported-node[node-id=${node .getId ()}]`)
3276
+ this .sceneGraph .find (`.node[node-id=${node .getId ()}],
3277
+ .imported-node[node-id=${node .getId ()}],
3278
+ .exported-node[node-id=${node .getId ()}]`)
3242
3279
  .find ("> .item .toggle-visibility")
3243
3280
  .removeClass ("off")
3244
3281
  .addClass ("on")
@@ -3260,7 +3297,9 @@ module .exports = class OutlineView extends Interface
3260
3297
 
3261
3298
  node .setHidden (false);
3262
3299
 
3263
- this .sceneGraph .find (`.node[node-id=${node .getId ()}], .exported-node[node-id=${node .getId ()}]`)
3300
+ this .sceneGraph .find (`.node[node-id=${node .getId ()}],
3301
+ .imported-node[node-id=${node .getId ()}],
3302
+ .exported-node[node-id=${node .getId ()}]`)
3264
3303
  .find ("> .item .toggle-visibility")
3265
3304
  .removeClass ("off")
3266
3305
  .addClass ("on")
@@ -11,6 +11,20 @@ module .exports = class PrimitivesLibrary extends LibraryPane
11
11
 
12
12
  #list;
13
13
 
14
+ open ()
15
+ {
16
+ // Set default config values.
17
+
18
+ this .config .global .setDefaultValues ({
19
+ recentPrimitives: [ ],
20
+ });
21
+
22
+ // Clear output.
23
+
24
+ this .#list ?.remove ();
25
+ this .#list = undefined;
26
+ }
27
+
14
28
  update ()
15
29
  {
16
30
  // Fill output.
@@ -33,6 +47,30 @@ module .exports = class PrimitivesLibrary extends LibraryPane
33
47
  .sort ((a, b) => a .typeName .localeCompare (b .typeName))
34
48
  .sort ((a, b) => a .componentInfo .name .localeCompare (b .componentInfo .name));
35
49
 
50
+ // Get recently used primitives.
51
+
52
+ const recentPrimitives = this .config .global .recentPrimitives;
53
+
54
+ // Create list for recently used elements.
55
+
56
+ if (recentPrimitives .length)
57
+ {
58
+ $("<li></li>")
59
+ .addClass ("component")
60
+ .attr ("name", "recent")
61
+ .text ("Recently Used Primitives")
62
+ .appendTo (this .#list);
63
+
64
+ for (const typeName of recentPrimitives)
65
+ {
66
+ $("<li></li>")
67
+ .addClass ("node")
68
+ .text (typeName)
69
+ .appendTo (this .#list)
70
+ .on ("dblclick", () => this .createRecentNode (nodes, typeName));
71
+ }
72
+ }
73
+
36
74
  // Create list elements.
37
75
 
38
76
  let componentName = "";
@@ -52,9 +90,27 @@ module .exports = class PrimitivesLibrary extends LibraryPane
52
90
  $("<li></li>")
53
91
  .addClass ("node")
54
92
  .text (node .typeName)
55
- .attr ("x3dSyntax", node .x3dSyntax)
56
93
  .appendTo (this .#list)
57
- .on ("dblclick", () => this .importX3D (node .typeName, node .x3dSyntax));
94
+ .on ("dblclick", () => this .createNode (node));
58
95
  }
59
96
  }
97
+
98
+ createRecentNode (nodes, typeName)
99
+ {
100
+ const node = nodes .find (node => node .typeName === typeName);
101
+
102
+ this .createNode (node);
103
+ }
104
+
105
+ createNode ({ typeName, x3dSyntax})
106
+ {
107
+ const recentPrimitives = this .config .global .recentPrimitives .filter (name => name !== typeName);
108
+
109
+ recentPrimitives .unshift (typeName);
110
+ recentPrimitives .splice (10);
111
+
112
+ this .config .global .recentPrimitives = recentPrimitives;
113
+
114
+ this .importX3D (typeName, x3dSyntax);
115
+ }
60
116
  };
@@ -680,7 +680,7 @@ ${scene .toXMLString ({ html: true, indent: " " .repeat (6) }) .trimEnd () }
680
680
 
681
681
  // Remove imported nodes if node is an Inline node.
682
682
 
683
- for (const importedNode of executionContext .getImportedNodes ())
683
+ for (const importedNode of Array .from (executionContext .getImportedNodes ()))
684
684
  {
685
685
  if (importedNode .getInlineNode () .valueOf () === node)
686
686
  this .removeImportedNode (executionContext, importedNode .getImportedName (), undoManager);
@@ -690,7 +690,7 @@ ${scene .toXMLString ({ html: true, indent: " " .repeat (6) }) .trimEnd () }
690
690
 
691
691
  if (executionContext instanceof X3D .X3DScene)
692
692
  {
693
- for (const exportedNode of executionContext .getExportedNodes ())
693
+ for (const exportedNode of Array .from (executionContext .getExportedNodes ()))
694
694
  {
695
695
  if (exportedNode .getLocalNode () .valueOf () === node)
696
696
  this .removeExportedNode (executionContext, exportedNode .getExportedName (), undoManager);
@@ -2996,12 +2996,12 @@ ${scene .toXMLString ({ html: true, indent: " " .repeat (6) }) .trimEnd () }
2996
2996
  const
2997
2997
  instance = node .getType () .includes (X3D .X3DConstants .X3DPrototypeInstance),
2998
2998
  name = field .getName (),
2999
- auxillary = field .create ();
2999
+ auxiliary = field .create ();
3000
3000
 
3001
- auxillary .setUnit (field .getUnit ());
3002
- auxillary .fromString (string, executionContext);
3001
+ auxiliary .setUnit (field .getUnit ());
3002
+ auxiliary .fromString (string, executionContext);
3003
3003
 
3004
- if (auxillary .equals (field))
3004
+ if (auxiliary .equals (field))
3005
3005
  {
3006
3006
  field .addEvent ();
3007
3007
  return;
@@ -3014,7 +3014,7 @@ ${scene .toXMLString ({ html: true, indent: " " .repeat (6) }) .trimEnd () }
3014
3014
  else
3015
3015
  undoManager .beginUndo (_("Change Field »%s« of Node %s"), field .getName (), node .getTypeName ());
3016
3016
 
3017
- field .assign (auxillary);
3017
+ field .assign (auxiliary);
3018
3018
 
3019
3019
  if (node .isDefaultValue (field))
3020
3020
  field .setModificationTime (0);
@@ -3045,11 +3045,11 @@ ${scene .toXMLString ({ html: true, indent: " " .repeat (6) }) .trimEnd () }
3045
3045
  const
3046
3046
  instance = node .getType () .includes (X3D .X3DConstants .X3DPrototypeInstance),
3047
3047
  name = field .getName (),
3048
- auxillary = field .create ();
3048
+ auxiliary = field .create ();
3049
3049
 
3050
- auxillary .setValue (value);
3050
+ auxiliary .setValue (value);
3051
3051
 
3052
- if (auxillary .equals (field))
3052
+ if (auxiliary .equals (field))
3053
3053
  {
3054
3054
  field .addEvent ();
3055
3055
  return;
@@ -3062,7 +3062,7 @@ ${scene .toXMLString ({ html: true, indent: " " .repeat (6) }) .trimEnd () }
3062
3062
  else
3063
3063
  undoManager .beginUndo (_("Change Field »%s« of Node %s"), field .getName (), node .getTypeName ());
3064
3064
 
3065
- field .assign (auxillary);
3065
+ field .assign (auxiliary);
3066
3066
 
3067
3067
  if (node .isDefaultValue (field))
3068
3068
  field .setModificationTime (0);