pict-section-flow 0.0.1 → 0.0.2

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 (48) hide show
  1. package/docs/README.md +19 -0
  2. package/{example_application → example_applications/simple_cards}/html/index.html +2 -2
  3. package/example_applications/simple_cards/package.json +43 -0
  4. package/example_applications/simple_cards/source/Pict-Application-FlowExample.js +434 -0
  5. package/example_applications/simple_cards/source/cards/FlowCard-Each.js +36 -0
  6. package/example_applications/simple_cards/source/cards/FlowCard-FileRead.js +54 -0
  7. package/example_applications/simple_cards/source/cards/FlowCard-FileWrite.js +48 -0
  8. package/example_applications/simple_cards/source/cards/FlowCard-GetValue.js +35 -0
  9. package/example_applications/simple_cards/source/cards/FlowCard-IfThenElse.js +47 -0
  10. package/example_applications/simple_cards/source/cards/FlowCard-LogValues.js +53 -0
  11. package/example_applications/simple_cards/source/cards/FlowCard-SetValue.js +95 -0
  12. package/example_applications/simple_cards/source/cards/FlowCard-Switch.js +37 -0
  13. package/example_applications/simple_cards/source/views/PictView-FlowExample-FileWriteInfo.js +59 -0
  14. package/{example_application → example_applications/simple_cards}/source/views/PictView-FlowExample-Layout.js +5 -1
  15. package/example_applications/simple_cards/source/views/PictView-FlowExample-MainWorkspace.js +312 -0
  16. package/package.json +6 -6
  17. package/source/Pict-Section-Flow.js +19 -0
  18. package/source/PictFlowCard.js +207 -0
  19. package/source/PictFlowCardPropertiesPanel.js +105 -0
  20. package/source/panels/FlowCardPropertiesPanel-Form.js +174 -0
  21. package/source/panels/FlowCardPropertiesPanel-Markdown.js +148 -0
  22. package/source/panels/FlowCardPropertiesPanel-Template.js +88 -0
  23. package/source/panels/FlowCardPropertiesPanel-View.js +114 -0
  24. package/source/providers/PictProvider-Flow-EventHandler.js +19 -8
  25. package/source/providers/PictProvider-Flow-Geometry.js +64 -0
  26. package/source/providers/PictProvider-Flow-Layouts.js +284 -0
  27. package/source/providers/PictProvider-Flow-NodeTypes.js +70 -0
  28. package/source/providers/PictProvider-Flow-PanelChrome.js +72 -0
  29. package/source/providers/PictProvider-Flow-SVGHelpers.js +30 -0
  30. package/source/services/PictService-Flow-ConnectionRenderer.js +324 -66
  31. package/source/services/PictService-Flow-InteractionManager.js +399 -75
  32. package/source/services/PictService-Flow-Layout.js +159 -0
  33. package/source/services/PictService-Flow-PathGenerator.js +199 -0
  34. package/source/services/PictService-Flow-Tether.js +544 -0
  35. package/source/views/PictView-Flow-Node.js +95 -18
  36. package/source/views/PictView-Flow-PropertiesPanel.js +435 -0
  37. package/source/views/PictView-Flow-Toolbar.js +491 -5
  38. package/source/views/PictView-Flow.js +830 -8
  39. package/example_application/package.json +0 -41
  40. package/example_application/source/Pict-Application-FlowExample.js +0 -241
  41. package/example_application/source/views/PictView-FlowExample-MainWorkspace.js +0 -191
  42. /package/{example_application → example_applications/simple_cards}/css/flowexample.css +0 -0
  43. /package/{example_application → example_applications/simple_cards}/source/Pict-Application-FlowExample-Configuration.json +0 -0
  44. /package/{example_application → example_applications/simple_cards}/source/providers/PictRouter-FlowExample-Configuration.json +0 -0
  45. /package/{example_application → example_applications/simple_cards}/source/views/PictView-FlowExample-About.js +0 -0
  46. /package/{example_application → example_applications/simple_cards}/source/views/PictView-FlowExample-BottomBar.js +0 -0
  47. /package/{example_application → example_applications/simple_cards}/source/views/PictView-FlowExample-Documentation.js +0 -0
  48. /package/{example_application → example_applications/simple_cards}/source/views/PictView-FlowExample-TopBar.js +0 -0
@@ -11,6 +11,8 @@ const _DefaultConfiguration =
11
11
 
12
12
  FlowViewIdentifier: 'Pict-Flow',
13
13
 
14
+ EnablePalette: true,
15
+
14
16
  CSS: /*css*/`
15
17
  .pict-flow-toolbar {
16
18
  display: flex;
@@ -74,6 +76,113 @@ const _DefaultConfiguration =
74
76
  background-color: #fff;
75
77
  color: #2c3e50;
76
78
  }
79
+ .pict-flow-palette-container {
80
+ border-bottom: 1px solid #e0e0e0;
81
+ background-color: #fafafa;
82
+ }
83
+ .pict-flow-palette-toggle {
84
+ display: flex;
85
+ align-items: center;
86
+ justify-content: space-between;
87
+ padding: 0.4em 0.75em;
88
+ cursor: pointer;
89
+ user-select: none;
90
+ -webkit-user-select: none;
91
+ font-size: 0.8em;
92
+ color: #7f8c8d;
93
+ background-color: #f4f4f5;
94
+ border-bottom: 1px solid #e0e0e0;
95
+ }
96
+ .pict-flow-palette-toggle:hover {
97
+ background-color: #ecf0f1;
98
+ color: #2c3e50;
99
+ }
100
+ .pict-flow-palette-toggle-arrow {
101
+ font-size: 0.7em;
102
+ transition: transform 0.2s;
103
+ }
104
+ .pict-flow-palette-toggle-arrow.open {
105
+ transform: rotate(180deg);
106
+ }
107
+ .pict-flow-palette-body {
108
+ display: none;
109
+ padding: 0.5em 0.75em 0.75em 0.75em;
110
+ max-height: 280px;
111
+ overflow-y: auto;
112
+ }
113
+ .pict-flow-palette-body.open {
114
+ display: block;
115
+ }
116
+ .pict-flow-palette-category {
117
+ margin-bottom: 0.5em;
118
+ }
119
+ .pict-flow-palette-category:last-child {
120
+ margin-bottom: 0;
121
+ }
122
+ .pict-flow-palette-category-label {
123
+ font-size: 0.7em;
124
+ font-weight: 700;
125
+ text-transform: uppercase;
126
+ letter-spacing: 0.05em;
127
+ color: #95a5a6;
128
+ margin-bottom: 0.35em;
129
+ padding-bottom: 0.2em;
130
+ border-bottom: 1px solid #ecf0f1;
131
+ }
132
+ .pict-flow-palette-cards {
133
+ display: flex;
134
+ flex-wrap: wrap;
135
+ gap: 0.35em;
136
+ }
137
+ .pict-flow-palette-card {
138
+ display: inline-flex;
139
+ align-items: center;
140
+ gap: 0.35em;
141
+ padding: 0.35em 0.6em;
142
+ border: 1px solid #d5d8dc;
143
+ border-radius: 4px;
144
+ background-color: #ffffff;
145
+ font-size: 0.8em;
146
+ cursor: pointer;
147
+ transition: background-color 0.15s, border-color 0.15s, box-shadow 0.15s;
148
+ user-select: none;
149
+ -webkit-user-select: none;
150
+ position: relative;
151
+ }
152
+ .pict-flow-palette-card:hover {
153
+ background-color: #eaf2f8;
154
+ border-color: #3498db;
155
+ box-shadow: 0 1px 3px rgba(52, 152, 219, 0.15);
156
+ }
157
+ .pict-flow-palette-card.disabled {
158
+ opacity: 0.45;
159
+ pointer-events: none;
160
+ cursor: default;
161
+ }
162
+ .pict-flow-palette-card-icon {
163
+ font-size: 1.1em;
164
+ line-height: 1;
165
+ }
166
+ .pict-flow-palette-card-swatch {
167
+ width: 10px;
168
+ height: 10px;
169
+ border-radius: 2px;
170
+ flex-shrink: 0;
171
+ }
172
+ .pict-flow-palette-card-title {
173
+ font-weight: 500;
174
+ color: #2c3e50;
175
+ white-space: nowrap;
176
+ }
177
+ .pict-flow-palette-card-code {
178
+ font-size: 0.8em;
179
+ color: #95a5a6;
180
+ font-family: monospace;
181
+ }
182
+ .pict-flow-toolbar-select.layout-select {
183
+ min-width: 120px;
184
+ max-width: 200px;
185
+ }
77
186
  `,
78
187
 
79
188
  Templates:
@@ -85,10 +194,6 @@ const _DefaultConfiguration =
85
194
  <div class="pict-flow-toolbar-group">
86
195
  <span class="pict-flow-toolbar-label">Node:</span>
87
196
  <select class="pict-flow-toolbar-select" id="Flow-Toolbar-NodeType-{~D:Record.FlowViewIdentifier~}">
88
- <option value="default">Default</option>
89
- <option value="start">Start</option>
90
- <option value="end">End</option>
91
- <option value="decision">Decision</option>
92
197
  </select>
93
198
  <button class="pict-flow-toolbar-btn" data-flow-action="add-node">+ Add Node</button>
94
199
  </div>
@@ -97,12 +202,33 @@ const _DefaultConfiguration =
97
202
  </div>
98
203
  <div class="pict-flow-toolbar-group">
99
204
  <button class="pict-flow-toolbar-btn" data-flow-action="zoom-in">Zoom +</button>
100
- <button class="pict-flow-toolbar-btn" data-flow-action="zoom-out">Zoom −</button>
205
+ <button class="pict-flow-toolbar-btn" data-flow-action="zoom-out">Zoom -</button>
101
206
  <button class="pict-flow-toolbar-btn" data-flow-action="zoom-fit">Fit</button>
102
207
  </div>
103
208
  <div class="pict-flow-toolbar-group">
104
209
  <button class="pict-flow-toolbar-btn" data-flow-action="auto-layout">Auto Layout</button>
105
210
  </div>
211
+ <div class="pict-flow-toolbar-group">
212
+ <span class="pict-flow-toolbar-label">Layouts:</span>
213
+ <select class="pict-flow-toolbar-select layout-select"
214
+ id="Flow-Toolbar-LayoutSelect-{~D:Record.FlowViewIdentifier~}">
215
+ <option value="">-- select layout --</option>
216
+ </select>
217
+ <button class="pict-flow-toolbar-btn" data-flow-action="save-layout" title="Save the current node positions as a named layout">Save</button>
218
+ <button class="pict-flow-toolbar-btn" data-flow-action="restore-layout" title="Restore the selected layout">Restore</button>
219
+ <button class="pict-flow-toolbar-btn danger" data-flow-action="delete-layout" title="Delete the selected saved layout">Delete</button>
220
+ </div>
221
+ <div class="pict-flow-toolbar-group">
222
+ <button class="pict-flow-toolbar-btn" data-flow-action="fullscreen" id="Flow-Toolbar-Fullscreen-{~D:Record.FlowViewIdentifier~}" title="Toggle Fullscreen">&#x26F6; Fullscreen</button>
223
+ </div>
224
+ </div>
225
+ <div class="pict-flow-palette-container" id="Flow-Palette-{~D:Record.FlowViewIdentifier~}">
226
+ <div class="pict-flow-palette-toggle" data-flow-action="toggle-palette">
227
+ <span>Card Palette</span>
228
+ <span class="pict-flow-palette-toggle-arrow" id="Flow-Palette-Arrow-{~D:Record.FlowViewIdentifier~}">&#9660;</span>
229
+ </div>
230
+ <div class="pict-flow-palette-body" id="Flow-Palette-Body-{~D:Record.FlowViewIdentifier~}">
231
+ </div>
106
232
  </div>
107
233
  `
108
234
  }
@@ -129,6 +255,14 @@ class PictViewFlowToolbar extends libPictView
129
255
  this.serviceType = 'PictViewFlowToolbar';
130
256
 
131
257
  this._FlowView = null;
258
+ this._PaletteOpen = false;
259
+ }
260
+
261
+ render(pRenderableHash, pRenderDestinationAddress, pTemplateRecordAddress)
262
+ {
263
+ // Pass this.options as the template record so {~D:Record.FlowViewIdentifier~}
264
+ // resolves correctly in the toolbar template.
265
+ return super.render(pRenderableHash, pRenderDestinationAddress, this.options);
132
266
  }
133
267
 
134
268
  onAfterRender(pRenderable, pRenderDestinationAddress, pRecord, pContent)
@@ -152,9 +286,306 @@ class PictViewFlowToolbar extends libPictView
152
286
  });
153
287
  }
154
288
 
289
+ // Bind palette toggle and card click events
290
+ let tmpFlowViewIdentifier = this.options.FlowViewIdentifier;
291
+ let tmpPaletteContainer = this.pict.ContentAssignment.getElement(`#Flow-Palette-${tmpFlowViewIdentifier}`);
292
+ if (tmpPaletteContainer.length > 0)
293
+ {
294
+ tmpPaletteContainer[0].addEventListener('click', (pEvent) =>
295
+ {
296
+ let tmpTarget = pEvent.target;
297
+ if (!tmpTarget) return;
298
+
299
+ // Check for toggle
300
+ let tmpToggle = tmpTarget.closest('[data-flow-action="toggle-palette"]');
301
+ if (tmpToggle)
302
+ {
303
+ this._togglePalette();
304
+ return;
305
+ }
306
+
307
+ // Check for card click
308
+ let tmpCard = tmpTarget.closest('[data-card-type]');
309
+ if (tmpCard)
310
+ {
311
+ let tmpCardType = tmpCard.getAttribute('data-card-type');
312
+ this._addCardFromPalette(tmpCardType);
313
+ }
314
+ });
315
+ }
316
+
317
+ // Populate the node type dropdown, palette, and layout dropdown
318
+ this._populateNodeTypeDropdown();
319
+ this._renderPalette();
320
+ this._populateLayoutDropdown();
321
+
155
322
  return super.onAfterRender(pRenderable, pRenderDestinationAddress, pRecord, pContent);
156
323
  }
157
324
 
325
+ /**
326
+ * Populate the node type dropdown from the registered node types.
327
+ */
328
+ _populateNodeTypeDropdown()
329
+ {
330
+ if (!this._FlowView || !this._FlowView._NodeTypeProvider)
331
+ {
332
+ return;
333
+ }
334
+
335
+ let tmpFlowViewIdentifier = this.options.FlowViewIdentifier;
336
+ let tmpSelectElements = this.pict.ContentAssignment.getElement(`#Flow-Toolbar-NodeType-${tmpFlowViewIdentifier}`);
337
+ if (tmpSelectElements.length < 1)
338
+ {
339
+ return;
340
+ }
341
+
342
+ let tmpSelect = tmpSelectElements[0];
343
+
344
+ // Clear existing options
345
+ while (tmpSelect.firstChild)
346
+ {
347
+ tmpSelect.removeChild(tmpSelect.firstChild);
348
+ }
349
+
350
+ let tmpTypes = this._FlowView._NodeTypeProvider.getNodeTypes();
351
+ let tmpTypeKeys = Object.keys(tmpTypes);
352
+
353
+ for (let i = 0; i < tmpTypeKeys.length; i++)
354
+ {
355
+ let tmpTypeConfig = tmpTypes[tmpTypeKeys[i]];
356
+
357
+ // Skip disabled cards
358
+ if (tmpTypeConfig.CardMetadata && tmpTypeConfig.CardMetadata.Enabled === false)
359
+ {
360
+ continue;
361
+ }
362
+
363
+ let tmpOption = document.createElement('option');
364
+ tmpOption.value = tmpTypeKeys[i];
365
+
366
+ if (tmpTypeConfig.CardMetadata && tmpTypeConfig.CardMetadata.Icon)
367
+ {
368
+ tmpOption.textContent = tmpTypeConfig.CardMetadata.Icon + ' ' + tmpTypeConfig.Label;
369
+ }
370
+ else
371
+ {
372
+ tmpOption.textContent = tmpTypeConfig.Label;
373
+ }
374
+
375
+ tmpSelect.appendChild(tmpOption);
376
+ }
377
+ }
378
+
379
+ /**
380
+ * Populate the layout dropdown from saved layouts in the flow data.
381
+ */
382
+ _populateLayoutDropdown()
383
+ {
384
+ if (!this._FlowView || !this._FlowView._LayoutProvider)
385
+ {
386
+ return;
387
+ }
388
+
389
+ let tmpFlowViewIdentifier = this.options.FlowViewIdentifier;
390
+ let tmpSelectElements = this.pict.ContentAssignment.getElement(
391
+ `#Flow-Toolbar-LayoutSelect-${tmpFlowViewIdentifier}`
392
+ );
393
+ if (tmpSelectElements.length < 1)
394
+ {
395
+ return;
396
+ }
397
+
398
+ let tmpSelect = tmpSelectElements[0];
399
+
400
+ // Clear existing options
401
+ while (tmpSelect.firstChild)
402
+ {
403
+ tmpSelect.removeChild(tmpSelect.firstChild);
404
+ }
405
+
406
+ // Add placeholder option
407
+ let tmpPlaceholder = document.createElement('option');
408
+ tmpPlaceholder.value = '';
409
+ tmpPlaceholder.textContent = '-- select layout --';
410
+ tmpSelect.appendChild(tmpPlaceholder);
411
+
412
+ let tmpLayouts = this._FlowView._LayoutProvider.getLayouts();
413
+ for (let i = 0; i < tmpLayouts.length; i++)
414
+ {
415
+ let tmpLayout = tmpLayouts[i];
416
+ let tmpOption = document.createElement('option');
417
+ tmpOption.value = tmpLayout.Hash;
418
+ tmpOption.textContent = tmpLayout.Name;
419
+ tmpSelect.appendChild(tmpOption);
420
+ }
421
+ }
422
+
423
+ /**
424
+ * Render the card palette with categories and card chips.
425
+ */
426
+ _renderPalette()
427
+ {
428
+ if (!this._FlowView || !this._FlowView._NodeTypeProvider) return;
429
+
430
+ let tmpFlowViewIdentifier = this.options.FlowViewIdentifier;
431
+ let tmpPaletteBody = this.pict.ContentAssignment.getElement(`#Flow-Palette-Body-${tmpFlowViewIdentifier}`);
432
+ if (tmpPaletteBody.length < 1) return;
433
+
434
+ let tmpBody = tmpPaletteBody[0];
435
+
436
+ // Clear existing palette content
437
+ while (tmpBody.firstChild)
438
+ {
439
+ tmpBody.removeChild(tmpBody.firstChild);
440
+ }
441
+
442
+ let tmpCategories = this._FlowView._NodeTypeProvider.getCardsByCategory();
443
+ let tmpCategoryKeys = Object.keys(tmpCategories);
444
+
445
+ if (tmpCategoryKeys.length === 0)
446
+ {
447
+ // No FlowCards registered - hide the palette
448
+ let tmpPaletteContainer = this.pict.ContentAssignment.getElement(`#Flow-Palette-${tmpFlowViewIdentifier}`);
449
+ if (tmpPaletteContainer.length > 0)
450
+ {
451
+ tmpPaletteContainer[0].style.display = 'none';
452
+ }
453
+ return;
454
+ }
455
+
456
+ for (let i = 0; i < tmpCategoryKeys.length; i++)
457
+ {
458
+ let tmpCategoryName = tmpCategoryKeys[i];
459
+ let tmpCards = tmpCategories[tmpCategoryName];
460
+
461
+ let tmpCategoryDiv = document.createElement('div');
462
+ tmpCategoryDiv.className = 'pict-flow-palette-category';
463
+
464
+ let tmpCategoryLabel = document.createElement('div');
465
+ tmpCategoryLabel.className = 'pict-flow-palette-category-label';
466
+ tmpCategoryLabel.textContent = tmpCategoryName;
467
+ tmpCategoryDiv.appendChild(tmpCategoryLabel);
468
+
469
+ let tmpCardsDiv = document.createElement('div');
470
+ tmpCardsDiv.className = 'pict-flow-palette-cards';
471
+
472
+ for (let j = 0; j < tmpCards.length; j++)
473
+ {
474
+ let tmpCardConfig = tmpCards[j];
475
+ let tmpMeta = tmpCardConfig.CardMetadata || {};
476
+
477
+ let tmpCardEl = document.createElement('div');
478
+ tmpCardEl.className = 'pict-flow-palette-card';
479
+ if (tmpMeta.Enabled === false)
480
+ {
481
+ tmpCardEl.classList.add('disabled');
482
+ }
483
+ tmpCardEl.setAttribute('data-card-type', tmpCardConfig.Hash);
484
+
485
+ if (tmpMeta.Tooltip)
486
+ {
487
+ tmpCardEl.setAttribute('title', tmpMeta.Tooltip);
488
+ }
489
+ else if (tmpMeta.Description)
490
+ {
491
+ tmpCardEl.setAttribute('title', tmpMeta.Description);
492
+ }
493
+
494
+ // Icon or color swatch
495
+ if (tmpMeta.Icon)
496
+ {
497
+ let tmpIconSpan = document.createElement('span');
498
+ tmpIconSpan.className = 'pict-flow-palette-card-icon';
499
+ tmpIconSpan.textContent = tmpMeta.Icon;
500
+ tmpCardEl.appendChild(tmpIconSpan);
501
+ }
502
+ else if (tmpCardConfig.TitleBarColor)
503
+ {
504
+ let tmpSwatch = document.createElement('span');
505
+ tmpSwatch.className = 'pict-flow-palette-card-swatch';
506
+ tmpSwatch.style.backgroundColor = tmpCardConfig.TitleBarColor;
507
+ tmpCardEl.appendChild(tmpSwatch);
508
+ }
509
+
510
+ // Title
511
+ let tmpTitleSpan = document.createElement('span');
512
+ tmpTitleSpan.className = 'pict-flow-palette-card-title';
513
+ tmpTitleSpan.textContent = tmpCardConfig.Label;
514
+ tmpCardEl.appendChild(tmpTitleSpan);
515
+
516
+ // Code badge
517
+ if (tmpMeta.Code)
518
+ {
519
+ let tmpCodeSpan = document.createElement('span');
520
+ tmpCodeSpan.className = 'pict-flow-palette-card-code';
521
+ tmpCodeSpan.textContent = tmpMeta.Code;
522
+ tmpCardEl.appendChild(tmpCodeSpan);
523
+ }
524
+
525
+ tmpCardsDiv.appendChild(tmpCardEl);
526
+ }
527
+
528
+ tmpCategoryDiv.appendChild(tmpCardsDiv);
529
+ tmpBody.appendChild(tmpCategoryDiv);
530
+ }
531
+ }
532
+
533
+ /**
534
+ * Toggle the palette open/closed.
535
+ */
536
+ _togglePalette()
537
+ {
538
+ this._PaletteOpen = !this._PaletteOpen;
539
+
540
+ let tmpFlowViewIdentifier = this.options.FlowViewIdentifier;
541
+
542
+ let tmpBody = this.pict.ContentAssignment.getElement(`#Flow-Palette-Body-${tmpFlowViewIdentifier}`);
543
+ if (tmpBody.length > 0)
544
+ {
545
+ if (this._PaletteOpen)
546
+ {
547
+ tmpBody[0].classList.add('open');
548
+ }
549
+ else
550
+ {
551
+ tmpBody[0].classList.remove('open');
552
+ }
553
+ }
554
+
555
+ let tmpArrow = this.pict.ContentAssignment.getElement(`#Flow-Palette-Arrow-${tmpFlowViewIdentifier}`);
556
+ if (tmpArrow.length > 0)
557
+ {
558
+ if (this._PaletteOpen)
559
+ {
560
+ tmpArrow[0].classList.add('open');
561
+ }
562
+ else
563
+ {
564
+ tmpArrow[0].classList.remove('open');
565
+ }
566
+ }
567
+ }
568
+
569
+ /**
570
+ * Add a node from a palette card click.
571
+ * @param {string} pCardType - The card type hash
572
+ */
573
+ _addCardFromPalette(pCardType)
574
+ {
575
+ if (!this._FlowView) return;
576
+
577
+ let tmpVS = this._FlowView.viewState;
578
+ let tmpX = (-tmpVS.PanX + 200) / tmpVS.Zoom;
579
+ let tmpY = (-tmpVS.PanY + 200) / tmpVS.Zoom;
580
+
581
+ // Offset to avoid overlap
582
+ let tmpNodeCount = this._FlowView.flowData.Nodes.length;
583
+ tmpX += (tmpNodeCount % 5) * 40;
584
+ tmpY += (tmpNodeCount % 5) * 40;
585
+
586
+ this._FlowView.addNode(pCardType, tmpX, tmpY);
587
+ }
588
+
158
589
  /**
159
590
  * Handle a toolbar action
160
591
  * @param {string} pAction
@@ -211,6 +642,61 @@ class PictViewFlowToolbar extends libPictView
211
642
  this._FlowView.autoLayout();
212
643
  break;
213
644
 
645
+ case 'save-layout':
646
+ {
647
+ let tmpName = window.prompt('Enter a name for this layout:');
648
+ if (tmpName !== null && tmpName.trim() !== '')
649
+ {
650
+ this._FlowView._LayoutProvider.saveLayout(tmpName.trim());
651
+ this._populateLayoutDropdown();
652
+ }
653
+ }
654
+ break;
655
+
656
+ case 'restore-layout':
657
+ {
658
+ let tmpSelectElements = this.pict.ContentAssignment.getElement(
659
+ `#Flow-Toolbar-LayoutSelect-${tmpFlowViewIdentifier}`
660
+ );
661
+ if (tmpSelectElements.length > 0)
662
+ {
663
+ let tmpLayoutHash = tmpSelectElements[0].value;
664
+ if (tmpLayoutHash)
665
+ {
666
+ this._FlowView._LayoutProvider.restoreLayout(tmpLayoutHash);
667
+ }
668
+ }
669
+ }
670
+ break;
671
+
672
+ case 'delete-layout':
673
+ {
674
+ let tmpSelectElements = this.pict.ContentAssignment.getElement(
675
+ `#Flow-Toolbar-LayoutSelect-${tmpFlowViewIdentifier}`
676
+ );
677
+ if (tmpSelectElements.length > 0)
678
+ {
679
+ let tmpLayoutHash = tmpSelectElements[0].value;
680
+ if (tmpLayoutHash)
681
+ {
682
+ this._FlowView._LayoutProvider.deleteLayout(tmpLayoutHash);
683
+ this._populateLayoutDropdown();
684
+ }
685
+ }
686
+ }
687
+ break;
688
+
689
+ case 'fullscreen':
690
+ {
691
+ let tmpIsFullscreen = this._FlowView.toggleFullscreen();
692
+ let tmpBtnElements = this.pict.ContentAssignment.getElement(`#Flow-Toolbar-Fullscreen-${tmpFlowViewIdentifier}`);
693
+ if (tmpBtnElements.length > 0)
694
+ {
695
+ tmpBtnElements[0].innerHTML = tmpIsFullscreen ? '&#x2716; Exit Fullscreen' : '&#x26F6; Fullscreen';
696
+ }
697
+ }
698
+ break;
699
+
214
700
  default:
215
701
  this.log.warn(`PictViewFlowToolbar: unknown action '${pAction}'`);
216
702
  break;