linny-r 2.0.8 → 2.0.9

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.
Files changed (31) hide show
  1. package/README.md +3 -40
  2. package/package.json +1 -1
  3. package/server.js +19 -157
  4. package/static/index.html +58 -20
  5. package/static/linny-r.css +20 -16
  6. package/static/scripts/iro.min.js +7 -7
  7. package/static/scripts/linny-r-ctrl.js +50 -72
  8. package/static/scripts/linny-r-gui-actor-manager.js +23 -33
  9. package/static/scripts/linny-r-gui-chart-manager.js +43 -41
  10. package/static/scripts/linny-r-gui-constraint-editor.js +6 -10
  11. package/static/scripts/linny-r-gui-controller.js +254 -230
  12. package/static/scripts/linny-r-gui-dataset-manager.js +17 -36
  13. package/static/scripts/linny-r-gui-documentation-manager.js +11 -17
  14. package/static/scripts/linny-r-gui-equation-manager.js +22 -22
  15. package/static/scripts/linny-r-gui-experiment-manager.js +102 -129
  16. package/static/scripts/linny-r-gui-file-manager.js +42 -48
  17. package/static/scripts/linny-r-gui-finder.js +105 -51
  18. package/static/scripts/linny-r-gui-model-autosaver.js +2 -4
  19. package/static/scripts/linny-r-gui-monitor.js +35 -41
  20. package/static/scripts/linny-r-gui-paper.js +42 -70
  21. package/static/scripts/linny-r-gui-power-grid-manager.js +31 -34
  22. package/static/scripts/linny-r-gui-receiver.js +1 -2
  23. package/static/scripts/linny-r-gui-repository-browser.js +44 -46
  24. package/static/scripts/linny-r-gui-scale-unit-manager.js +32 -32
  25. package/static/scripts/linny-r-gui-sensitivity-analysis.js +61 -67
  26. package/static/scripts/linny-r-gui-undo-redo.js +94 -95
  27. package/static/scripts/linny-r-milp.js +20 -24
  28. package/static/scripts/linny-r-model.js +1832 -2248
  29. package/static/scripts/linny-r-utils.js +27 -27
  30. package/static/scripts/linny-r-vm.js +801 -905
  31. package/static/show-png.html +0 -113
@@ -207,10 +207,9 @@ class GUIDatasetManager extends DatasetManager {
207
207
  }
208
208
 
209
209
  hideCollapsedRows() {
210
- // Hides all rows except top level and immediate children of expanded
211
- for(let i = 0; i < this.dataset_table.rows.length; i++) {
210
+ // Hides all rows except top level and immediate children of expanded.
211
+ for(const row of this.dataset_table.rows) {
212
212
  const
213
- row = this.dataset_table.rows[i],
214
213
  // Get the first DIV in the first TD of this row
215
214
  first_div = row.firstChild.firstElementChild,
216
215
  btn = first_div.dataset.prefix === 'x';
@@ -274,10 +273,7 @@ class GUIDatasetManager extends DatasetManager {
274
273
  pl.pop();
275
274
  }
276
275
  this.hideCollapsedRows();
277
- for(let i = 0; i < this.dataset_table.rows.length; i++) {
278
- const r = this.dataset_table.rows[i];
279
- if(r.dataset.prefix === lcp) return r;
280
- }
276
+ for(const r of this.dataset_table.rows) if(r.dataset.prefix === lcp) return r;
281
277
  return null;
282
278
  }
283
279
 
@@ -328,8 +324,8 @@ class GUIDatasetManager extends DatasetManager {
328
324
  names = [],
329
325
  pref_names = {},
330
326
  xids = [];
331
- for(let i = 0; i < dnl.length; i++) {
332
- const pref = UI.prefixesAndName(MODEL.datasets[dnl[i]].name);
327
+ for(const dn of dnl) {
328
+ const pref = UI.prefixesAndName(MODEL.datasets[dn].name);
333
329
  // NOTE: only the name part (so no prefixes at all) will be shown
334
330
  names.push(pref.pop());
335
331
  indent.push(pref.length);
@@ -851,8 +847,7 @@ class GUIDatasetManager extends DatasetManager {
851
847
  // Update all chartvariables referencing this dataset + old selector.
852
848
  const vl = MODEL.datasetVariables;
853
849
  let cv_cnt = 0;
854
- for(let i = 0; i < vl.length; i++) {
855
- const v = vl[i];
850
+ for(const v of vl) {
856
851
  if(v.object === this.selected_dataset && v.attribute === oldm.selector) {
857
852
  v.attribute = m.selector;
858
853
  cv_cnt++;
@@ -949,16 +944,10 @@ class GUIDatasetManager extends DatasetManager {
949
944
  return;
950
945
  }
951
946
  prefix += UI.PREFIXER;
952
- const
953
- dsn = ds.displayName,
954
- pml = ds.inferPrefixableModifiers,
955
- xl = MODEL.allExpressions,
956
- vl = MODEL.datasetVariables,
957
- nl = MODEL.notesWithTags;
958
- for(let i = 0; i < pml.length; i++) {
947
+ const dsn = ds.displayName;
948
+ for(const m of ds.inferPrefixableModifiers) {
959
949
  // Create prefixed dataset with correct default value
960
950
  const
961
- m = pml[i],
962
951
  sel = m.selector,
963
952
  newds = MODEL.addDataset(prefix + sel);
964
953
  if(newds) {
@@ -976,17 +965,16 @@ class GUIDatasetManager extends DatasetManager {
976
965
  const
977
966
  from = dsn + UI.OA_SEPARATOR + sel,
978
967
  to = newds.displayName;
979
- for(let j = 0; j < vl.length; j++) {
980
- const v = vl[j];
981
- // NOTE: variable should match original dataset + selector
968
+ for(const v of MODEL.datasetVariables) {
969
+ // NOTE: variable should match original dataset + selector.
982
970
  if(v.displayName === from) {
983
- // Change to new dataset WITHOUT selector
971
+ // Change to new dataset WITHOUT selector.
984
972
  v.object = newds;
985
973
  v.attribute = '';
986
974
  vcount++;
987
975
  }
988
976
  }
989
- // Rename variable in the Sensitivity Analysis
977
+ // Rename variable in the Sensitivity Analysis.
990
978
  for(let j = 0; j < MODEL.sensitivity_parameters.length; j++) {
991
979
  if(MODEL.sensitivity_parameters[j] === from) {
992
980
  MODEL.sensitivity_parameters[j] = to;
@@ -1008,10 +996,8 @@ class GUIDatasetManager extends DatasetManager {
1008
996
  // Pattern ends at any character that is invalid for a
1009
997
  // dataset modifier selector (unlike equation names)
1010
998
  '\\s*[^a-zA-Z0-9\\+\\-\\%\\_]', 'gi');
1011
- for(let j = 0; j < xl.length; j++) {
1012
- const
1013
- x = xl[j],
1014
- matches = x.text.match(re);
999
+ for(const x of MODEL.allExpressions) {
1000
+ const matches = x.text.match(re);
1015
1001
  if(matches) {
1016
1002
  for(let k = 0; k < matches.length; k++) {
1017
1003
  // NOTE: each match will start with the opening bracket,
@@ -1025,10 +1011,8 @@ class GUIDatasetManager extends DatasetManager {
1025
1011
  x.code = null;
1026
1012
  }
1027
1013
  }
1028
- for(let j = 0; j < nl.length; j++) {
1029
- const
1030
- n = nl[j],
1031
- matches = n.contents.match(re);
1014
+ for(const n of MODEL.notesWithTags) {
1015
+ const matches = n.contents.match(re);
1032
1016
  if(matches) {
1033
1017
  for(let k = 0; k < matches.length; k++) {
1034
1018
  // See NOTE above for the use of `slice` here
@@ -1181,9 +1165,8 @@ class GUIDatasetManager extends DatasetManager {
1181
1165
  parts = lines[0].split(sep),
1182
1166
  dsn = [];
1183
1167
  let quoted = false;
1184
- for(let i = 0; i < parts.length; i++) {
1168
+ for(const p of parts) {
1185
1169
  const
1186
- p = parts[i],
1187
1170
  swq = /^\"(\"\")*($|[^\"])/.test(p),
1188
1171
  ewq = p.endsWith('"');
1189
1172
  if(!quoted && swq && !ewq) {
@@ -1236,8 +1219,6 @@ class GUIDatasetManager extends DatasetManager {
1236
1219
  if(sf === '' && v !== '') {
1237
1220
  UI.warn(`Invalid numerical value "${v}" for <strong>${dsn[j]}</strong> on line ${i}`);
1238
1221
  return false;
1239
- } else {
1240
- dsa[j].push(sf);
1241
1222
  }
1242
1223
  }
1243
1224
  }
@@ -280,10 +280,10 @@ class DocumentationManager {
280
280
 
281
281
  clearEntity(list) {
282
282
  // To be called when entities are deleted
283
- if(list.indexOf(this.entity) >= 0) {
283
+ if(list === true || list.indexOf(this.entity) >= 0) {
284
284
  this.stopEditing();
285
285
  this.entity = null;
286
- this.title.innerHTML = 'Information and documentation';
286
+ this.title.innerHTML = 'About Linny-R';
287
287
  this.viewer.innerHTML = this.about_linny_r;
288
288
  }
289
289
  }
@@ -540,18 +540,17 @@ class DocumentationManager {
540
540
 
541
541
  showArrowLinks(arrow) {
542
542
  // Show list of links represented by a composite arrow.
543
- const
544
- n = arrow.links.length,
545
- msg = 'Arrow represents ' + pluralS(n, 'link');
543
+ const msg = 'Arrow represents ' + pluralS(arrow.links.length, 'link');
546
544
  UI.setMessage(msg);
547
545
  if(this.visible && !this.editing) {
548
546
  // Set the dialog title.
549
547
  this.title.innerHTML = msg;
550
548
  // Show list.
551
549
  const lis = [];
552
- let l, dn, c, af;
553
- for(let i = 0; i < n; i++) {
554
- l = arrow.links[i];
550
+ let dn,
551
+ c,
552
+ af;
553
+ for(const l of arrow.links) {
555
554
  dn = l.displayName;
556
555
  if(l.from_node instanceof Process) {
557
556
  c = UI.color.produced;
@@ -600,9 +599,7 @@ class DocumentationManager {
600
599
  this.title.innerHTML = msg;
601
600
  // Show list.
602
601
  const lis = [];
603
- for(let i = 0; i < iol.length; i++) {
604
- lis.push(`<li>${iol[i].displayName}</li>`);
605
- }
602
+ for(const io of iol) lis.push(`<li>${io.displayName}</li>`);
606
603
  lis.sort(ciCompare);
607
604
  this.viewer.innerHTML = `<ul>${lis.join('')}</ul>`;
608
605
  }
@@ -714,9 +711,8 @@ class DocumentationManager {
714
711
  this.differenceAsTable(d.settings));
715
712
  if('units' in d) html.push('<h2>Units</h2>',
716
713
  this.differenceAsTable(d.units));
717
- for(let i = 0; i < UI.MC.ENTITY_PROPS.length; i++) {
718
- const e = UI.MC.ENTITY_PROPS[i];
719
- if(e in d) html.push('<h2>' + this.propertyName(e) + '</h2>',
714
+ for(const e of UI.MC.ENTITY_PROPS) if(e in d) {
715
+ html.push('<h2>' + this.propertyName(e) + '</h2>',
720
716
  this.differenceAsTable(d[e]));
721
717
  }
722
718
  if('charts' in d) html.push('<h2><em>Charts</em></h2>',
@@ -759,9 +755,7 @@ class DocumentationManager {
759
755
  const
760
756
  html = ['<table>'],
761
757
  keys = Object.keys(d).sort();
762
- for(let i = 0; i < keys.length; i++) {
763
- html.push(this.differenceAsTableRow(d, keys[i]));
764
- }
758
+ for(const k of keys) html.push(this.differenceAsTableRow(d, k));
765
759
  html.push('</table>');
766
760
  return html.join('\n');
767
761
  }
@@ -148,7 +148,7 @@ class EquationManager {
148
148
  }
149
149
 
150
150
  updateDialog() {
151
- // Updates equation list, highlighting selected equation (if any)
151
+ // Updates equation list, highlighting selected equation (if any).
152
152
  const
153
153
  ed = MODEL.equations_dataset,
154
154
  ml = [],
@@ -160,34 +160,36 @@ class EquationManager {
160
160
  this.outcome_btn.classList.add('not-selected');
161
161
  }
162
162
  let smid = 'eqmtr';
163
+ // NOTE> Selector list `msl` contains names, not IDs.
163
164
  for(let i = 0; i < msl.length; i++) {
164
165
  const
165
- m = ed.modifiers[UI.nameToID(msl[i])],
166
- wild = (m.selector.indexOf('??') >= 0),
167
- method = m.selector.startsWith(':'),
166
+ id = UI.nameToID(msl[i]),
167
+ m = ed.modifiers[id],
168
+ sel = safeDoubleQuotes(m.selector),
169
+ expr = m.expression,
170
+ wild = (sel.indexOf('??') >= 0),
171
+ method = sel.startsWith(':'),
168
172
  multi = (this.multi_line ? '-multi' : ''),
169
- issue = (m.expression.compile_issue ? ' compile-issue' :
170
- (m.expression.compute_issue ? ' compute-issue' : '')),
171
- clk = '" onclick="EQUATION_MANAGER.selectModifier(event, \'' +
172
- escapedSingleQuotes(m.selector) + '\'',
173
- mover = (method ? ' onmouseover="EQUATION_MANAGER.showInfo(\'' +
174
- m.identifier + '\', event.shiftKey);"' : '');
173
+ issue = (expr.compile_issue ? ' compile-issue' :
174
+ (expr.compute_issue ? ' compute-issue' : '')),
175
+ clk = `" onclick="EQUATION_MANAGER.selectModifier(event, '${id}'`,
176
+ mover = (!method ? '' :
177
+ `onmouseover="EQUATION_MANAGER.showInfo('${id}', event.shiftKey);"`);
175
178
  if(m === sm) smid += i;
176
179
  ml.push(['<tr id="eqmtr', i, '" class="dataset-modif',
177
180
  (m === sm ? ' sel-set' : ''),
178
181
  '"><td class="equation-selector',
179
182
  (method ? ' method' : ''),
180
183
  // Display in gray when method cannot be applied.
181
- (m.expression.noMethodObject ? ' no-object' : ''),
182
- (m.expression.isStatic ? '' : ' it'), issue,
184
+ (expr.noMethodObject ? ' no-object' : ''),
185
+ (expr.isStatic ? '' : ' it'), issue,
183
186
  (wild ? ' wildcard' : ''), clk, ', false);"', mover, '>',
184
187
  (m.outcome_equation ? '<span class="outcome"></span>' : ''),
185
- (wild ? wildcardFormat(m.selector) : m.selector),
188
+ (wild ? wildcardFormat(sel) : sel),
186
189
  '</td><td class="equation-expression', multi, issue,
187
190
  (issue ? '"title="' +
188
- safeDoubleQuotes(m.expression.compile_issue ||
189
- m.expression.compute_issue) : ''),
190
- clk, ');">', m.expression.text, '</td></tr>'].join(''));
191
+ safeDoubleQuotes(expr.compile_issue || expr.compute_issue) : ''),
192
+ clk, ');">', expr.text, '</td></tr>'].join(''));
191
193
  }
192
194
  this.table.innerHTML = ml.join('');
193
195
  this.scroll_area.style.display = 'block';
@@ -208,10 +210,10 @@ class EquationManager {
208
210
 
209
211
  selectModifier(event, id, x=true) {
210
212
  // Select modifier, or when Alt- or double-clicked, edit its expression
211
- // or the equation name (= name of the modifier)
213
+ // or the equation name (= name of the modifier).
212
214
  if(MODEL.equations_dataset) {
213
215
  const
214
- m = MODEL.equations_dataset.modifiers[UI.nameToID(id)] || null,
216
+ m = MODEL.equations_dataset.modifiers[id] || null,
215
217
  edit = event.altKey || this.doubleClicked(m);
216
218
  this.selected_modifier = m;
217
219
  if(m && edit) {
@@ -327,10 +329,8 @@ class EquationManager {
327
329
  }
328
330
  // Update all chartvariables referencing this dataset + old selector
329
331
  let cv_cnt = 0;
330
- for(let i = 0; i < MODEL.charts.length; i++) {
331
- const c = MODEL.charts[i];
332
- for(let j = 0; j < c.variables.length; j++) {
333
- const v = c.variables[j];
332
+ for(const c of MODEL.charts) {
333
+ for(const v of c.variables) {
334
334
  if(v.object === MODEL.equations_dataset && v.attribute === olds) {
335
335
  v.attribute = m.selector;
336
336
  cv_cnt++;