linny-r 2.0.8 → 2.0.10
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/README.md +3 -40
- package/package.json +6 -2
- package/server.js +19 -157
- package/static/images/solve-not-same-changed.png +0 -0
- package/static/images/solve-not-same-not-changed.png +0 -0
- package/static/images/solve-same-changed.png +0 -0
- package/static/images/solve-same-not-changed.png +0 -0
- package/static/index.html +137 -20
- package/static/linny-r.css +260 -23
- package/static/scripts/iro.min.js +7 -7
- package/static/scripts/linny-r-ctrl.js +126 -85
- package/static/scripts/linny-r-gui-actor-manager.js +23 -33
- package/static/scripts/linny-r-gui-chart-manager.js +56 -53
- package/static/scripts/linny-r-gui-constraint-editor.js +10 -14
- package/static/scripts/linny-r-gui-controller.js +644 -260
- package/static/scripts/linny-r-gui-dataset-manager.js +64 -66
- package/static/scripts/linny-r-gui-documentation-manager.js +11 -17
- package/static/scripts/linny-r-gui-equation-manager.js +22 -22
- package/static/scripts/linny-r-gui-experiment-manager.js +124 -141
- package/static/scripts/linny-r-gui-expression-editor.js +26 -12
- package/static/scripts/linny-r-gui-file-manager.js +42 -48
- package/static/scripts/linny-r-gui-finder.js +294 -55
- package/static/scripts/linny-r-gui-model-autosaver.js +2 -4
- package/static/scripts/linny-r-gui-monitor.js +35 -41
- package/static/scripts/linny-r-gui-paper.js +42 -70
- package/static/scripts/linny-r-gui-power-grid-manager.js +31 -34
- package/static/scripts/linny-r-gui-receiver.js +1 -2
- package/static/scripts/linny-r-gui-repository-browser.js +44 -46
- package/static/scripts/linny-r-gui-scale-unit-manager.js +32 -32
- package/static/scripts/linny-r-gui-sensitivity-analysis.js +61 -67
- package/static/scripts/linny-r-gui-undo-redo.js +94 -95
- package/static/scripts/linny-r-milp.js +20 -24
- package/static/scripts/linny-r-model.js +1932 -2274
- package/static/scripts/linny-r-utils.js +27 -27
- package/static/scripts/linny-r-vm.js +900 -998
- package/static/show-png.html +0 -113
@@ -342,7 +342,7 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
342
342
|
}
|
343
343
|
|
344
344
|
getRepositories() {
|
345
|
-
// Gets the list of repository names from the server
|
345
|
+
// Gets the list of repository names from the server.
|
346
346
|
this.repositories.length = 0;
|
347
347
|
fetch('repo/', postData({action: 'list'}))
|
348
348
|
.then((response) => {
|
@@ -353,14 +353,13 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
353
353
|
})
|
354
354
|
.then((data) => {
|
355
355
|
if(UI.postResponseOK(data)) {
|
356
|
-
// NOTE:
|
357
|
-
const
|
358
|
-
|
359
|
-
this.addRepository(rl[i].trim());
|
356
|
+
// NOTE: Trim to prevent empty name strings.
|
357
|
+
for(const r of data.trim().split('\n')) {
|
358
|
+
this.addRepository(r.trim());
|
360
359
|
}
|
361
360
|
}
|
362
|
-
// NOTE:
|
363
|
-
// unless the list is empty
|
361
|
+
// NOTE: Set index to first repository on list (typically local host)
|
362
|
+
// unless the list is empty.
|
364
363
|
this.repository_index = Math.min(0, this.repositories.length - 1);
|
365
364
|
this.updateDialog();
|
366
365
|
})
|
@@ -545,7 +544,7 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
545
544
|
}
|
546
545
|
|
547
546
|
updateModulesTable() {
|
548
|
-
// Refresh the module table
|
547
|
+
// Refresh the module table.
|
549
548
|
let mcount = 0;
|
550
549
|
const trl = [];
|
551
550
|
if(this.repository_index >= 0) {
|
@@ -565,7 +564,7 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
565
564
|
this.modules_count.innerHTML = pluralS(mcount, 'module');
|
566
565
|
if(this.module_index >= 0) {
|
567
566
|
UI.enableButtons('repo-load repo-include');
|
568
|
-
// NOTE:
|
567
|
+
// NOTE: Only allow deletion from local host repository.
|
569
568
|
if(this.repository_index === 0 && this.isLocalHost) {
|
570
569
|
UI.enableButtons(' repo-delete');
|
571
570
|
} else {
|
@@ -577,7 +576,7 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
577
576
|
}
|
578
577
|
|
579
578
|
updateDialog() {
|
580
|
-
//
|
579
|
+
// Refreshe all dialog elements.
|
581
580
|
const ol = [];
|
582
581
|
for(let i = 0; i < this.repositories.length; i++) {
|
583
582
|
ol.push('<option value="', i,
|
@@ -586,7 +585,7 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
586
585
|
}
|
587
586
|
this.repository_selector.innerHTML = ol.join('');
|
588
587
|
UI.disableButtons('repo-access repo-remove repo-store');
|
589
|
-
// NOTE:
|
588
|
+
// NOTE: On remote installation, do not allow add/remove/store.
|
590
589
|
if(!this.isLocalHost) {
|
591
590
|
UI.disableButtons('repo-add');
|
592
591
|
} else if(this.repository_index >= 0) {
|
@@ -597,7 +596,7 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
597
596
|
UI.enableButtons('repo-access');
|
598
597
|
}
|
599
598
|
if(r.name !== 'local host') {
|
600
|
-
// NOTE:
|
599
|
+
// NOTE: Cannot remove 'local host'.
|
601
600
|
UI.enableButtons('repo-remove');
|
602
601
|
}
|
603
602
|
}
|
@@ -605,7 +604,7 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
605
604
|
}
|
606
605
|
|
607
606
|
promptForInclusion(repo, file, node) {
|
608
|
-
// Add entities defined in the parsed XML tree with root `node
|
607
|
+
// Add entities defined in the parsed XML tree with root `node`.
|
609
608
|
IO_CONTEXT = new IOContext(repo, file, node);
|
610
609
|
const md = this.include_modal;
|
611
610
|
md.element('name').innerHTML = IO_CONTEXT.file_name;
|
@@ -616,8 +615,8 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
616
615
|
}
|
617
616
|
|
618
617
|
updateActors() {
|
619
|
-
//
|
620
|
-
// for each actor binding selector
|
618
|
+
// Add actor (if specified) to model, and then updates the selector options
|
619
|
+
// for each actor binding selector.
|
621
620
|
if(!IO_CONTEXT) return;
|
622
621
|
const
|
623
622
|
aname = this.include_modal.element('actor').value.trim(),
|
@@ -637,25 +636,24 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
637
636
|
}
|
638
637
|
|
639
638
|
parameterBinding(name) {
|
640
|
-
//
|
641
|
-
// selector identified by its element name (!) in the Include modal
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
e = lst[i];
|
639
|
+
// Return the selected option (as DOM element) of the the parameter
|
640
|
+
// selector identified by its element name (!) in the Include modal.
|
641
|
+
let sel = null;
|
642
|
+
for(const e of document.getElementsByName(name)) {
|
643
|
+
if(e.type.indexOf('select') === 0) {
|
644
|
+
sel = e;
|
647
645
|
break;
|
648
646
|
}
|
649
647
|
}
|
650
|
-
if(!
|
651
|
-
return
|
648
|
+
if(!sel) UI.alert(`Parameter selector "${name}" not found`);
|
649
|
+
return sel;
|
652
650
|
}
|
653
651
|
|
654
652
|
performInclusion() {
|
655
|
-
//
|
656
|
-
//
|
653
|
+
// Include the selected model as "module" cluster in the model.
|
654
|
+
// This is effectuated by "re-initializing" the current model using
|
657
655
|
// the XML of the model-to-be-included with the contextualization as
|
658
|
-
// indicated by the modeler
|
656
|
+
// indicated by the modeler.
|
659
657
|
if(!IO_CONTEXT) {
|
660
658
|
UI.alert('Cannot include module without context');
|
661
659
|
return;
|
@@ -667,7 +665,7 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
667
665
|
pref.focus();
|
668
666
|
return;
|
669
667
|
}
|
670
|
-
// NOTE:
|
668
|
+
// NOTE: Prefix must not already be in use as entity name.
|
671
669
|
let obj = MODEL.objectByName(IO_CONTEXT.prefix);
|
672
670
|
if(obj) {
|
673
671
|
UI.warningEntityExists(obj, IO_CONTEXT.prefix);
|
@@ -678,10 +676,10 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
678
676
|
IO_CONTEXT.actor_name = this.include_modal.element('actor').value.trim();
|
679
677
|
MODEL.clearSelection();
|
680
678
|
IO_CONTEXT.bindParameters();
|
681
|
-
// NOTE:
|
679
|
+
// NOTE: Including may affect focal cluster, so store it...
|
682
680
|
const fc = MODEL.focal_cluster;
|
683
681
|
MODEL.initFromXML(IO_CONTEXT.xml);
|
684
|
-
// ... and restore it afterwards
|
682
|
+
// ... and restore it afterwards.
|
685
683
|
MODEL.focal_cluster = fc;
|
686
684
|
let counts = `: ${pluralS(IO_CONTEXT.added_nodes.length, 'node')}, ` +
|
687
685
|
pluralS(IO_CONTEXT.added_links.length, 'link');
|
@@ -691,9 +689,9 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
691
689
|
}
|
692
690
|
UI.notify(`Model <tt>${IO_CONTEXT.file_name}</tt> included from ` +
|
693
691
|
`<strong>${IO_CONTEXT.repo_name}</strong>${counts}`);
|
694
|
-
// Get the containing cluster
|
692
|
+
// Get the containing cluster.
|
695
693
|
obj = MODEL.objectByName(IO_CONTEXT.clusterName);
|
696
|
-
// Position it in the focal cluster
|
694
|
+
// Position it in the focal cluster.
|
697
695
|
if(obj instanceof Cluster) {
|
698
696
|
obj.x = IO_CONTEXT.centroid_x;
|
699
697
|
obj.y = IO_CONTEXT.centroid_y;
|
@@ -701,20 +699,20 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
701
699
|
} else {
|
702
700
|
UI.alert('Include failed to create a cluster');
|
703
701
|
}
|
704
|
-
// Reset the IO context
|
702
|
+
// Reset the IO context.
|
705
703
|
IO_CONTEXT = null;
|
706
704
|
this.include_modal.hide();
|
707
705
|
MODEL.cleanUpActors();
|
708
706
|
MODEL.focal_cluster.clearAllProcesses();
|
709
707
|
UI.drawDiagram(MODEL);
|
710
|
-
// Select the newly added cluster
|
708
|
+
// Select the newly added cluster.
|
711
709
|
if(obj) MODEL.select(obj);
|
712
|
-
// Update dataset manager if shown (as new datasets may have been added)
|
710
|
+
// Update dataset manager if shown (as new datasets may have been added).
|
713
711
|
if(DATASET_MANAGER.visible) DATASET_MANAGER.updateDialog();
|
714
712
|
}
|
715
713
|
|
716
714
|
cancelInclusion() {
|
717
|
-
//
|
715
|
+
// Clear the IO context and closes the inclusion dialog.
|
718
716
|
IO_CONTEXT = null;
|
719
717
|
this.include_modal.hide();
|
720
718
|
}
|
@@ -724,7 +722,7 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
724
722
|
this.store_modal.element('name').innerText =
|
725
723
|
this.repositories[this.repository_index].name;
|
726
724
|
this.store_modal.element('model-name').value =
|
727
|
-
|
725
|
+
asFileName(MODEL.name);
|
728
726
|
this.store_modal.show('model-name');
|
729
727
|
}
|
730
728
|
}
|
@@ -746,7 +744,7 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
746
744
|
this.store_bb_modal.element('name').innerText =
|
747
745
|
this.repositories[this.repository_index].name;
|
748
746
|
this.store_bb_modal.element('model-name').value =
|
749
|
-
|
747
|
+
asFileName(MODEL.name);
|
750
748
|
this.store_bb_modal.show('model-name');
|
751
749
|
}
|
752
750
|
}
|
@@ -757,7 +755,7 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
757
755
|
mn = this.store_bb_modal.element('model-name').value.trim(),
|
758
756
|
r = this.repositories[this.repository_index];
|
759
757
|
if(mn.length > 1) {
|
760
|
-
// NOTE:
|
758
|
+
// NOTE: Second parameter indicates: store with "black box XML".
|
761
759
|
r.storeModelAsModule(mn, true);
|
762
760
|
this.store_bb_modal.hide();
|
763
761
|
}
|
@@ -765,19 +763,19 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
765
763
|
}
|
766
764
|
|
767
765
|
loadModuleAsModel() {
|
768
|
-
//
|
766
|
+
// Load selected module as model.
|
769
767
|
this.confirm_load_modal.hide();
|
770
768
|
if(this.repository_index >= 0 && this.module_index >= 0) {
|
771
|
-
// NOTE:
|
769
|
+
// NOTE: When loading new model, the stay-on-top dialogs must be reset.
|
772
770
|
UI.hideStayOnTopDialogs();
|
773
771
|
const r = this.repositories[this.repository_index];
|
774
|
-
// NOTE:
|
772
|
+
// NOTE: Pass FALSE to indicate "no inclusion; load XML as model".
|
775
773
|
r.loadModule(this.module_index, false);
|
776
774
|
}
|
777
775
|
}
|
778
776
|
|
779
777
|
includeModule() {
|
780
|
-
//
|
778
|
+
// Include selected module into the current model.
|
781
779
|
if(this.repository_index >= 0 && this.module_index >= 0) {
|
782
780
|
const r = this.repositories[this.repository_index];
|
783
781
|
r.loadModule(this.module_index, true);
|
@@ -785,7 +783,7 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
785
783
|
}
|
786
784
|
|
787
785
|
confirmLoadModuleAsModel() {
|
788
|
-
//
|
786
|
+
// Prompt modeler to confirm loading the selected module as model.
|
789
787
|
if(this.repository_index >= 0 && this.module_index >= 0 &&
|
790
788
|
document.getElementById('repo-load-btn').classList.contains('enab')) {
|
791
789
|
const r = this.repositories[this.repository_index];
|
@@ -796,7 +794,7 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
796
794
|
}
|
797
795
|
|
798
796
|
confirmDeleteFromRepository() {
|
799
|
-
//
|
797
|
+
// Prompt modeler to confirm deletion of the selected module.
|
800
798
|
if(this.repository_index >= 0 && this.module_index >= 0 &&
|
801
799
|
document.getElementById('repo-delete-btn').classList.contains('enab')) {
|
802
800
|
const r = this.repositories[this.repository_index];
|
@@ -808,7 +806,7 @@ class GUIRepositoryBrowser extends RepositoryBrowser {
|
|
808
806
|
}
|
809
807
|
|
810
808
|
deleteFromRepository() {
|
811
|
-
//
|
809
|
+
// Delete the selected modulle from the current repository.
|
812
810
|
if(this.repository_index >= 0 && this.module_index >= 0) {
|
813
811
|
const r = this.repositories[this.repository_index];
|
814
812
|
if(r) r.deleteModule(this.module_index);
|
@@ -35,18 +35,18 @@ SOFTWARE.
|
|
35
35
|
// CLASS ScaleUnitManager (modal dialog!)
|
36
36
|
class ScaleUnitManager {
|
37
37
|
constructor() {
|
38
|
-
// Add the scale units modal
|
38
|
+
// Add the scale units modal.
|
39
39
|
this.dialog = new ModalDialog('scale-units');
|
40
40
|
this.dialog.close.addEventListener('click',
|
41
41
|
() => SCALE_UNIT_MANAGER.dialog.hide());
|
42
|
-
// Make the add, edit and delete buttons of this modal responsive
|
42
|
+
// Make the add, edit and delete buttons of this modal responsive.
|
43
43
|
this.dialog.element('new-btn').addEventListener('click',
|
44
44
|
() => SCALE_UNIT_MANAGER.promptForScaleUnit());
|
45
45
|
this.dialog.element('edit-btn').addEventListener('click',
|
46
46
|
() => SCALE_UNIT_MANAGER.editScaleUnit());
|
47
47
|
this.dialog.element('delete-btn').addEventListener('click',
|
48
48
|
() => SCALE_UNIT_MANAGER.deleteScaleUnit());
|
49
|
-
// Add the scale unit definition modal
|
49
|
+
// Add the scale unit definition modal.
|
50
50
|
this.new_scale_unit_modal = new ModalDialog('new-scale-unit');
|
51
51
|
this.new_scale_unit_modal.ok.addEventListener(
|
52
52
|
'click', () => SCALE_UNIT_MANAGER.addNewScaleUnit());
|
@@ -57,19 +57,19 @@ class ScaleUnitManager {
|
|
57
57
|
}
|
58
58
|
|
59
59
|
get selectedUnitIsBaseUnit() {
|
60
|
-
//
|
61
|
-
for(let
|
62
|
-
if(this.scale_units[
|
60
|
+
// Return TRUE iff selected unit is used as base unit for some unit.
|
61
|
+
for(let k in this.scale_units) if(this.scale_units.hasOwnProperty(k)) {
|
62
|
+
if(this.scale_units[k].base_unit === this.selected_unit) return true;
|
63
63
|
}
|
64
64
|
return false;
|
65
65
|
}
|
66
66
|
|
67
67
|
show() {
|
68
|
-
// Show the user-defined scale units for the current model
|
69
|
-
// NOTE:
|
70
|
-
// take immediate effect
|
68
|
+
// Show the user-defined scale units for the current model.
|
69
|
+
// NOTE: Add/edit/delete actions operate on this list, so changes
|
70
|
+
// take immediate effect.
|
71
71
|
MODEL.cleanUpScaleUnits();
|
72
|
-
// NOTE:
|
72
|
+
// NOTE: Unit name is key in the scale units object.
|
73
73
|
this.selected_unit = '';
|
74
74
|
this.last_time_selected = 0;
|
75
75
|
this.updateDialog();
|
@@ -78,7 +78,7 @@ class ScaleUnitManager {
|
|
78
78
|
|
79
79
|
updateDialog() {
|
80
80
|
// Create the HTML for the scale units table and update the state
|
81
|
-
// of the action buttons
|
81
|
+
// of the action buttons.
|
82
82
|
if(!MODEL.scale_units.hasOwnProperty(this.selected_unit)) {
|
83
83
|
this.selected_unit = '';
|
84
84
|
}
|
@@ -88,7 +88,7 @@ class ScaleUnitManager {
|
|
88
88
|
ss = this.selected_unit;
|
89
89
|
let ssid = 'scntr';
|
90
90
|
if(keys.length <= 1) {
|
91
|
-
// Only one key => must be the default '1'
|
91
|
+
// Only one key => must be the default '1'.
|
92
92
|
sl.push('<tr><td><em>No units defined</em></td></tr>');
|
93
93
|
} else {
|
94
94
|
for(let i = 1; i < keys.length; i++) {
|
@@ -118,14 +118,14 @@ class ScaleUnitManager {
|
|
118
118
|
}
|
119
119
|
|
120
120
|
selectScaleUnit(event, symbol, focus) {
|
121
|
-
// Select scale unit, and when double-clicked, allow to edit it
|
121
|
+
// Select scale unit, and when double-clicked, allow to edit it.
|
122
122
|
const
|
123
123
|
ss = this.selected_unit,
|
124
124
|
now = Date.now(),
|
125
125
|
dt = now - this.last_time_selected,
|
126
|
-
// NOTE: Alt-click and double-click indicate: edit
|
126
|
+
// NOTE: Alt-click and double-click indicate: edit.
|
127
127
|
// Consider click to be "double" if the same modifier was clicked
|
128
|
-
// less than 300 ms ago
|
128
|
+
// less than 300 ms ago.
|
129
129
|
edit = event.altKey || (symbol === ss && dt < 300);
|
130
130
|
this.selected_unit = symbol;
|
131
131
|
this.last_time_selected = now;
|
@@ -138,9 +138,9 @@ class ScaleUnitManager {
|
|
138
138
|
}
|
139
139
|
|
140
140
|
promptForScaleUnit(action='Define new', focus='name') {
|
141
|
-
// Show the Add/Edit scale unit dialog for the indicated action
|
141
|
+
// Show the Add/Edit scale unit dialog for the indicated action.
|
142
142
|
const md = this.new_scale_unit_modal;
|
143
|
-
// NOTE:
|
143
|
+
// NOTE: By default, let name and base unit be empty strings, not '1'.
|
144
144
|
let sv = {name: '', scalar: '1', base_unit: '' };
|
145
145
|
if(action === 'Edit' && this.selected_unit) {
|
146
146
|
sv = MODEL.scale_units[this.selected_unit];
|
@@ -154,23 +154,23 @@ class ScaleUnitManager {
|
|
154
154
|
}
|
155
155
|
|
156
156
|
addNewScaleUnit() {
|
157
|
-
// Add the new scale unit or update the one being edited
|
157
|
+
// Add the new scale unit or update the one being edited.
|
158
158
|
const
|
159
159
|
md = this.new_scale_unit_modal,
|
160
160
|
edited = md.element('action').innerText === 'Edit',
|
161
|
-
// NOTE:
|
161
|
+
// NOTE: Unit name cannot contain single quotes.
|
162
162
|
s = UI.cleanName(md.element('name').value).replace("'", ''),
|
163
163
|
v = md.element('scalar').value.trim(),
|
164
|
-
// NOTE:
|
164
|
+
// NOTE: Accept empty base unit to denote '1'.
|
165
165
|
b = md.element('base').value.trim() || '1';
|
166
166
|
if(!s) {
|
167
|
-
// Do not accept empty string as name
|
167
|
+
// Do not accept empty string as name.
|
168
168
|
UI.warn('Scale unit must have a name');
|
169
169
|
md.element('name').focus();
|
170
170
|
return;
|
171
171
|
}
|
172
172
|
if(MODEL.scale_units.hasOwnProperty(s) && !edited) {
|
173
|
-
// Do not accept existing unit as name for new unit
|
173
|
+
// Do not accept existing unit as name for new unit.
|
174
174
|
UI.warn(`Scale unit "${s}" is already defined`);
|
175
175
|
md.element('name').focus();
|
176
176
|
return;
|
@@ -194,7 +194,7 @@ class ScaleUnitManager {
|
|
194
194
|
}
|
195
195
|
const selu = this.selected_unit;
|
196
196
|
if(edited && b !== s) {
|
197
|
-
// Prevent inconsistencies across scalars
|
197
|
+
// Prevent inconsistencies across scalars.
|
198
198
|
const cr = MODEL.scale_units[b].conversionRates();
|
199
199
|
if(cr.hasOwnProperty(s)) {
|
200
200
|
UI.warn(`Defining ${s} in terms of ${b} introduces a circular reference`);
|
@@ -203,13 +203,13 @@ class ScaleUnitManager {
|
|
203
203
|
}
|
204
204
|
}
|
205
205
|
if(edited && s !== selu) {
|
206
|
-
// First rename base units
|
207
|
-
for(let
|
208
|
-
if(MODEL.scale_units[
|
209
|
-
MODEL.scale_units[
|
206
|
+
// First rename base units.
|
207
|
+
for(let k in MODEL.scale_units) if(MODEL.scale_units.hasOwnProperty(k)) {
|
208
|
+
if(MODEL.scale_units[k].base_unit === selu) {
|
209
|
+
MODEL.scale_units[k].base_unit = s;
|
210
210
|
}
|
211
211
|
}
|
212
|
-
// NOTE: renameScaleUnit replaces references to `s`, not the entry
|
212
|
+
// NOTE: renameScaleUnit replaces references to `s`, not the entry.
|
213
213
|
MODEL.renameScaleUnit(selu, s);
|
214
214
|
delete MODEL.scale_units[this.selected_unit];
|
215
215
|
}
|
@@ -222,13 +222,13 @@ class ScaleUnitManager {
|
|
222
222
|
}
|
223
223
|
|
224
224
|
editScaleUnit() {
|
225
|
-
// Allow user to edit name and/or value
|
225
|
+
// Allow user to edit name and/or value.
|
226
226
|
if(this.selected_unit) this.promptForScaleUnit('Edit', 'scalar');
|
227
227
|
}
|
228
228
|
|
229
229
|
deleteScaleUnit() {
|
230
|
-
// Allow user to delete
|
231
|
-
// @@@TO DO:
|
230
|
+
// Allow user to delete.
|
231
|
+
// @@@TO DO: Check whether scale unit is used in the model.
|
232
232
|
if(this.selected_unit && !this.selectedUnitIsBaseUnit) {
|
233
233
|
delete MODEL.scale_units[this.selected_unit];
|
234
234
|
this.updateDialog();
|
@@ -236,7 +236,7 @@ class ScaleUnitManager {
|
|
236
236
|
}
|
237
237
|
|
238
238
|
updateScaleUnits() {
|
239
|
-
// Replace scale unit definitions of model by the new definitions
|
239
|
+
// Replace scale unit definitions of model by the new definitions.
|
240
240
|
UI.updateScaleUnitList();
|
241
241
|
this.dialog.hide();
|
242
242
|
}
|