@xibosignage/xibo-layout-renderer 1.0.24 → 1.0.25

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 CHANGED
@@ -67,3 +67,52 @@ The library supports multiple platforms via `ConsumerPlatform` enum and the `opt
67
67
  | `chromeOS` | Local file path | Fault reporting via Service Worker |
68
68
  | `electron` | App host + URL | Standard playback |
69
69
  | PWA | Proxy/hosted | Service Worker caching |
70
+
71
+ ## CMS Integration — postMessage Protocol
72
+
73
+ When XLR is embedded in a sandboxed `<iframe>` (e.g. in CMS Preview), it communicates with the parent frame via `window.parent.postMessage` instead of using browser dialogs that require `allow-modals`.
74
+
75
+ ### Iframe requirements
76
+
77
+ The iframe must include `allow-scripts` in its `sandbox` attribute. `allow-modals` is **not** required.
78
+
79
+ ```html
80
+ <iframe src="..." sandbox="allow-scripts allow-same-origin"></iframe>
81
+ ```
82
+
83
+ ### Messages sent by XLR
84
+
85
+ #### `xlr:navLayout`
86
+
87
+ Fired when a "Navigate to Layout" touch/webhook action is triggered. The parent frame is responsible for showing a confirmation prompt and opening the layout.
88
+
89
+ ```typescript
90
+ interface XlrNavLayoutMessage {
91
+ type: 'xlr:navLayout';
92
+ layoutCode: string; // The layout code from the action
93
+ url: string; // Pre-constructed preview URL (ready to open)
94
+ }
95
+ ```
96
+
97
+ **CMS listener example:**
98
+
99
+ ```javascript
100
+ window.addEventListener('message', (event) => {
101
+ // In production, validate event.origin against your known CMS origin.
102
+ if (event.data?.type === 'xlr:navLayout') {
103
+ if (confirm(`Navigate to layout with code ${event.data.layoutCode}?`)) {
104
+ window.open(event.data.url, '_blank');
105
+ }
106
+ }
107
+ });
108
+ ```
109
+
110
+ ### Event API (non-iframe consumers)
111
+
112
+ The same action also emits a `navLayout` event via the XLR event system, usable by consumers that have direct access to the `IXlr` object:
113
+
114
+ ```typescript
115
+ xlr.on('navLayout', (layoutCode: string, url: string) => {
116
+ // Show your own confirmation UI and open the URL as needed.
117
+ });
118
+ ```
@@ -62,4 +62,5 @@ export declare function prepareImageMedia(media: IMedia, region: IRegion): void;
62
62
  export declare function prepareAudioMedia(media: IMedia, region: IRegion): void;
63
63
  export declare function prepareHtmlMedia(media: IMedia, region: IRegion): void;
64
64
  export declare function playerReportFault(msg: string, media: IMedia): Promise<void>;
65
+ export declare function setLayoutIndex(layout: ILayout | undefined, layoutIndex: number): ILayout | undefined;
65
66
  export {};
@@ -26,6 +26,7 @@ export type InputLayoutType = {
26
26
  getXlf?(): string;
27
27
  duration?: number;
28
28
  isOverlay?: boolean;
29
+ shareOfVoice?: number;
29
30
  };
30
31
  export type OptionsType = {
31
32
  xlfUrl: string;
@@ -23,6 +23,7 @@ export type IXlrEvents = {
23
23
  overlayEnd: (overlay: ILayout) => void;
24
24
  commandCodeReceived: (commandCode: string) => void;
25
25
  commandStringReceived: (commandString: string) => void;
26
+ navLayout: (layoutCode: string, url: string) => void;
26
27
  };
27
28
  export interface IXlrPlayback {
28
29
  currentLayout: ILayout | undefined;
@@ -835,31 +835,37 @@ var OverlayLayoutManager = /*#__PURE__*/function () {
835
835
  case 0:
836
836
  _context2.next = 2;
837
837
  return Promise.all(list.map( /*#__PURE__*/function () {
838
- var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(item) {
839
- var inputOverlay, overlayLayout, $overlay;
838
+ var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(item, index) {
839
+ var _item$index;
840
+ var inputOverlay, overlayLayout, $overlay, _overlayLayout$zIndex;
840
841
  return _regeneratorRuntime().wrap(function _callee$(_context) {
841
842
  while (1) switch (_context.prev = _context.next) {
842
843
  case 0:
843
844
  inputOverlay = {};
844
845
  inputOverlay = _objectSpread2(_objectSpread2({}, inputOverlay), item);
845
- inputOverlay.index = item.index;
846
+ inputOverlay.index = (_item$index = item.index) !== null && _item$index !== void 0 ? _item$index : index;
846
847
  _context.next = 5;
847
848
  return _this.parent.prepareLayoutXlf(_objectSpread2(_objectSpread2({}, initialLayout), inputOverlay));
848
849
  case 5:
849
850
  overlayLayout = _context.sent;
851
+ console.debug('<> XLR.debug OverlayLayoutManager::parseOverlays prepared overlay layout', {
852
+ overlayLayout: overlayLayout,
853
+ inputOverlay: inputOverlay
854
+ });
850
855
  // Hide all overlays first
851
856
  $overlay = document.querySelector("#".concat(overlayLayout.containerName, "[data-sequence=\"").concat(overlayLayout.index, "\"]"));
852
857
  if ($overlay !== null) {
853
- $overlay.style.setProperty('display', 'none');
858
+ $overlay.style.setProperty('visibility', 'hidden');
859
+ $overlay.style.setProperty('z-index', "".concat((_overlayLayout$zIndex = overlayLayout.zIndex) !== null && _overlayLayout$zIndex !== void 0 ? _overlayLayout$zIndex : -999));
854
860
  }
855
861
  return _context.abrupt("return", overlayLayout);
856
- case 9:
862
+ case 10:
857
863
  case "end":
858
864
  return _context.stop();
859
865
  }
860
866
  }, _callee);
861
867
  }));
862
- return function (_x2) {
868
+ return function (_x2, _x3) {
863
869
  return _ref.apply(this, arguments);
864
870
  };
865
871
  }()));
@@ -988,7 +994,7 @@ var OverlayLayoutManager = /*#__PURE__*/function () {
988
994
  }
989
995
  }, _callee3, this, [[12, 21, 24, 27]]);
990
996
  }));
991
- function prepareOverlayLayouts(_x3, _x4) {
997
+ function prepareOverlayLayouts(_x4, _x5) {
992
998
  return _prepareOverlayLayouts.apply(this, arguments);
993
999
  }
994
1000
  return prepareOverlayLayouts;
@@ -999,7 +1005,8 @@ var OverlayLayoutManager = /*#__PURE__*/function () {
999
1005
  var _this$parent$currentL;
1000
1006
  if (this.overlays.length === 0) return;
1001
1007
  if (this.parent && (_this$parent$currentL = this.parent.currentLayout) !== null && _this$parent$currentL !== void 0 && _this$parent$currentL.isInterrupt()) {
1002
- this.container.style.setProperty('display', 'none');
1008
+ this.container.style.setProperty('visibility', 'hidden');
1009
+ this.container.style.setProperty('z-index', '-999');
1003
1010
  return;
1004
1011
  }
1005
1012
  this.overlays.forEach(function (overlay) {
@@ -1017,21 +1024,25 @@ var OverlayLayoutManager = /*#__PURE__*/function () {
1017
1024
  while (1) switch (_context5.prev = _context5.next) {
1018
1025
  case 0:
1019
1026
  overlayHtml = document.querySelector("#".concat(overlay.containerName, "[data-sequence=\"").concat(overlay.index, "\"]"));
1027
+ console.debug('<> XLR.debug OverlayLayoutManager::stopOverlays', {
1028
+ overlay: overlay,
1029
+ overlayHtml: overlayHtml
1030
+ });
1020
1031
  if (!(overlayHtml !== null)) {
1021
- _context5.next = 5;
1032
+ _context5.next = 6;
1022
1033
  break;
1023
1034
  }
1024
- _context5.next = 4;
1035
+ _context5.next = 5;
1025
1036
  return overlay.finishAllRegions();
1026
- case 4:
1027
- overlay.emitter.emit('end', overlay);
1028
1037
  case 5:
1038
+ overlay.emitter.emit('end', overlay);
1039
+ case 6:
1029
1040
  case "end":
1030
1041
  return _context5.stop();
1031
1042
  }
1032
1043
  }, _callee4);
1033
1044
  }));
1034
- return function (_x5) {
1045
+ return function (_x6) {
1035
1046
  return _ref2.apply(this, arguments);
1036
1047
  };
1037
1048
  }());
@@ -73807,6 +73818,13 @@ function _playerReportFault() {
73807
73818
  }));
73808
73819
  return _playerReportFault.apply(this, arguments);
73809
73820
  }
73821
+ function setLayoutIndex(layout, layoutIndex) {
73822
+ if (!layout || layout.id === null) {
73823
+ return;
73824
+ }
73825
+ layout.index = layoutIndex;
73826
+ return layout;
73827
+ }
73810
73828
 
73811
73829
  const urlAlphabet =
73812
73830
  'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict';
@@ -74982,10 +75000,16 @@ var ActionController = /*#__PURE__*/function () {
74982
75000
  }, {
74983
75001
  key: "openLayoutInNewTab",
74984
75002
  value: function openLayoutInNewTab(layoutCode, options) {
74985
- if (confirm(this.translations.navigateToLayout.replace('[layoutTag]', layoutCode))) {
74986
- var url = options.layoutPreviewUrl.replace('[layoutCode]', layoutCode) + '?findByCode=1';
74987
- window.open(url, '_blank');
74988
- }
75003
+ var url = options.layoutPreviewUrl.replace('[layoutCode]', layoutCode) + '?findByCode=1';
75004
+ // Send a postMessage to the parent frame so the CMS can handle the confirmation
75005
+ // and navigation (confirm() is blocked in sandboxed iframes without allow-modals).
75006
+ window.parent.postMessage({
75007
+ type: 'xlr:navLayout',
75008
+ layoutCode: layoutCode,
75009
+ url: url
75010
+ }, '*');
75011
+ // Also emit via the XLR event system for non-iframe consumers.
75012
+ this.parent.xlr.emitter.emit('navLayout', layoutCode, url);
74989
75013
  }
74990
75014
  }, {
74991
75015
  key: "openLayoutInPlayer",
@@ -75402,8 +75426,11 @@ var Layout = /*#__PURE__*/function () {
75402
75426
  layout.state = exports.ELayoutState.PLAYED;
75403
75427
  }
75404
75428
  layout.done = true;
75405
- console.debug({
75406
- $layout: $layout
75429
+ console.debug('>>> XLR.debug Layout end emitted > Layout ID > ', {
75430
+ $layout: $layout,
75431
+ layoutId: layout.id,
75432
+ isOverlay: layout.isOverlay,
75433
+ isInterrupt: layout.isInterrupt()
75407
75434
  });
75408
75435
  if ($layout !== null) {
75409
75436
  $layout.style.setProperty('visibility', 'hidden');
@@ -76138,12 +76165,12 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76138
76165
  $splashScreen === null || $splashScreen === void 0 || $splashScreen.hide();
76139
76166
  }
76140
76167
  if (!xlr.currentLayout.done) {
76141
- console.log('>>>> XLR.debug XLR::playSchedules > Running currentLayout', xlr.currentLayout);
76142
- xlr.currentLayout.run();
76143
76168
  // Hide overlays when current layout is interrupt
76144
76169
  if (xlr.currentLayout.isInterrupt()) {
76145
76170
  xlrObject.overlayLayoutManager.stopOverlays();
76146
76171
  }
76172
+ console.log('>>>> XLR.debug XLR::playSchedules > Running currentLayout', xlr.currentLayout);
76173
+ xlr.currentLayout.run();
76147
76174
  }
76148
76175
  } else {
76149
76176
  // Show splash screen
@@ -76491,8 +76518,10 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76491
76518
  var tempNextLayoutIndex = getLayoutIndexByLayoutId(this.inputLayouts, this.nextLayout.layoutId);
76492
76519
  _currentLayoutIndex = tempNextLayoutIndex !== null && tempNextLayoutIndex !== void 0 ? tempNextLayoutIndex : 0;
76493
76520
  _currentLayout = this.getLayout(this.inputLayouts[tempNextLayoutIndex !== null && tempNextLayoutIndex !== void 0 ? tempNextLayoutIndex : 0]);
76521
+ _currentLayout = setLayoutIndex(_currentLayout, _currentLayoutIndex);
76494
76522
  } else {
76495
76523
  _currentLayout = this.getLayout(this.inputLayouts[0]);
76524
+ _currentLayout = setLayoutIndex(_currentLayout, 0);
76496
76525
  }
76497
76526
  if (this.inputLayouts.length > 1) {
76498
76527
  if (_currentLayoutIndex + 1 > this.inputLayouts.length - 1) {
@@ -76501,6 +76530,7 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76501
76530
  _nextLayoutIndex = _currentLayoutIndex + 1;
76502
76531
  }
76503
76532
  _nextLayout = this.getLayout(this.inputLayouts[_nextLayoutIndex]);
76533
+ _nextLayout = setLayoutIndex(_nextLayout, _nextLayoutIndex);
76504
76534
  } else {
76505
76535
  _nextLayout = _currentLayout;
76506
76536
  }
@@ -76513,20 +76543,25 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76513
76543
  if (_currentLayout) {
76514
76544
  _currentLayoutIndex = _currentLayout.index;
76515
76545
  }
76546
+ _currentLayout = setLayoutIndex(_currentLayout, _currentLayoutIndex);
76516
76547
  _nextLayoutIndex = 0;
76517
76548
  _nextLayout = this.getLayout(this.inputLayouts[_nextLayoutIndex]);
76549
+ _nextLayout = setLayoutIndex(_nextLayout, _nextLayoutIndex);
76518
76550
  }
76519
76551
  } else {
76520
76552
  _currentLayoutIndex = this.nextLayout.index > this.inputLayouts.length - 1 ? 0 : this.nextLayout.index;
76521
76553
  _currentLayout = this.getLayout(this.inputLayouts[_currentLayoutIndex]);
76554
+ _currentLayout = setLayoutIndex(_currentLayout, _currentLayoutIndex);
76522
76555
  _nextLayoutIndex = _currentLayoutIndex + 1 > this.inputLayouts.length - 1 ? 0 : _currentLayoutIndex + 1;
76523
76556
  _nextLayout = this.getLayout(this.inputLayouts[_nextLayoutIndex]);
76557
+ _nextLayout = setLayoutIndex(_nextLayout, _nextLayoutIndex);
76524
76558
  }
76525
76559
  } else {
76526
76560
  _currentLayout = this.nextLayout;
76527
76561
  _currentLayoutIndex = _currentLayout.index;
76528
76562
  _nextLayoutIndex = (_currentLayoutIndex + 1) % this.inputLayouts.length;
76529
76563
  _nextLayout = this.getLayout(this.inputLayouts[_nextLayoutIndex]);
76564
+ _nextLayout = setLayoutIndex(_nextLayout, _nextLayoutIndex);
76530
76565
  }
76531
76566
  }
76532
76567
  }
@@ -76534,17 +76569,22 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76534
76569
  // Initial run: set both currentLayout and nextLayout
76535
76570
  if (hasLayout) {
76536
76571
  _currentLayout = this.getLayout(this.inputLayouts[_currentLayoutIndex]);
76572
+ _currentLayout = setLayoutIndex(_currentLayout, _currentLayoutIndex);
76537
76573
  if (this.inputLayouts.length > 1) {
76538
76574
  _nextLayout = this.getLayout(this.inputLayouts[_nextLayoutIndex]);
76575
+ _nextLayout = setLayoutIndex(_nextLayout, _nextLayoutIndex);
76539
76576
  } else {
76540
76577
  _nextLayout = this.getLayout(this.inputLayouts[0]);
76578
+ _nextLayout = setLayoutIndex(_nextLayout, 0);
76541
76579
  }
76542
76580
  }
76543
76581
  }
76544
76582
  if (_currentLayout === undefined && _nextLayout === undefined) {
76545
76583
  if (_hasDefaultOnly) {
76546
76584
  _currentLayout = this.getLayout(this.inputLayouts[0]);
76585
+ _currentLayout = setLayoutIndex(_currentLayout, 0);
76547
76586
  _nextLayout = this.getLayout(this.inputLayouts[0]);
76587
+ _nextLayout = setLayoutIndex(_nextLayout, 0);
76548
76588
  }
76549
76589
  }
76550
76590
  if (_currentLayout !== undefined && _nextLayout !== undefined) {
@@ -76578,6 +76618,11 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76578
76618
  activeLayout = _objectSpread2({}, this.uniqueLayouts[inputLayout.layoutId]);
76579
76619
  }
76580
76620
  _layout = _objectSpread2(_objectSpread2({}, _layout), activeLayout);
76621
+ console.debug('XLR::getLayout > activeLayout from uniqueLayouts', {
76622
+ activeLayout: activeLayout,
76623
+ inputLayout: inputLayout,
76624
+ uniqueLayouts: this.uniqueLayouts
76625
+ });
76581
76626
  // Must set index/sequence from schedule loop
76582
76627
  _layout.index = activeLayout.index;
76583
76628
  }
@@ -76790,7 +76835,7 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76790
76835
  _nextLayout = nextLayout;
76791
76836
  case 2:
76792
76837
  if (!(_nextLayout && _nextLayout.xlfString === '')) {
76793
- _context16.next = 16;
76838
+ _context16.next = 17;
76794
76839
  break;
76795
76840
  }
76796
76841
  // Remove skipped layout
@@ -76802,25 +76847,26 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76802
76847
  _context16.next = 7;
76803
76848
  break;
76804
76849
  }
76805
- return _context16.abrupt("break", 16);
76850
+ return _context16.abrupt("break", 17);
76806
76851
  case 7:
76807
76852
  inputLayout = self.inputLayouts[nextIndex];
76808
76853
  if (inputLayout) {
76809
76854
  _context16.next = 10;
76810
76855
  break;
76811
76856
  }
76812
- return _context16.abrupt("break", 16);
76857
+ return _context16.abrupt("break", 17);
76813
76858
  case 10:
76814
76859
  nextLayoutObj = self.getLayout(inputLayout);
76815
- _context16.next = 13;
76860
+ nextLayoutObj = setLayoutIndex(nextLayoutObj, nextIndex);
76861
+ _context16.next = 14;
76816
76862
  return self.prepareLayoutXlf(nextLayoutObj);
76817
- case 13:
76863
+ case 14:
76818
76864
  _nextLayout = _context16.sent;
76819
76865
  _context16.next = 2;
76820
76866
  break;
76821
- case 16:
76822
- return _context16.abrupt("return", _nextLayout);
76823
76867
  case 17:
76868
+ return _context16.abrupt("return", _nextLayout);
76869
+ case 18:
76824
76870
  case "end":
76825
76871
  return _context16.stop();
76826
76872
  }