@xibosignage/xibo-layout-renderer 1.0.27 → 1.0.28

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.
@@ -20,30 +20,6 @@ function _isNativeReflectConstruct() {
20
20
  return !!t;
21
21
  })();
22
22
  }
23
- function _iterableToArrayLimit(r, l) {
24
- var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
25
- if (null != t) {
26
- var e,
27
- n,
28
- i,
29
- u,
30
- a = [],
31
- f = !0,
32
- o = !1;
33
- try {
34
- if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
35
- } catch (r) {
36
- o = !0, n = r;
37
- } finally {
38
- try {
39
- if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
40
- } finally {
41
- if (o) throw n;
42
- }
43
- }
44
- return a;
45
- }
46
- }
47
23
  function ownKeys(e, r) {
48
24
  var t = Object.keys(e);
49
25
  if (Object.getOwnPropertySymbols) {
@@ -522,18 +498,12 @@ function _possibleConstructorReturn(self, call) {
522
498
  }
523
499
  return _assertThisInitialized(self);
524
500
  }
525
- function _slicedToArray(arr, i) {
526
- return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray$1(arr, i) || _nonIterableRest();
527
- }
528
501
  function _toConsumableArray(arr) {
529
502
  return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray$1(arr) || _nonIterableSpread();
530
503
  }
531
504
  function _arrayWithoutHoles(arr) {
532
505
  if (Array.isArray(arr)) return _arrayLikeToArray$1(arr);
533
506
  }
534
- function _arrayWithHoles(arr) {
535
- if (Array.isArray(arr)) return arr;
536
- }
537
507
  function _iterableToArray(iter) {
538
508
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
539
509
  }
@@ -553,9 +523,6 @@ function _arrayLikeToArray$1(arr, len) {
553
523
  function _nonIterableSpread() {
554
524
  throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
555
525
  }
556
- function _nonIterableRest() {
557
- throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
558
- }
559
526
  function _createForOfIteratorHelper(o, allowArrayLike) {
560
527
  var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
561
528
  if (!it) {
@@ -1062,6 +1029,13 @@ var initialXlr = {
1062
1029
  },
1063
1030
  gotoNextLayout: function gotoNextLayout() {},
1064
1031
  gotoPrevLayout: function gotoPrevLayout() {},
1032
+ gotoLayoutByCode: function gotoLayoutByCode(_layoutCode) {
1033
+ return Promise.resolve();
1034
+ },
1035
+ playInterruptLayout: function playInterruptLayout(_inputLayout) {
1036
+ return Promise.resolve();
1037
+ },
1038
+ triggerAction: function triggerAction(_triggerCode, _widgetId) {},
1065
1039
  init: function init() {
1066
1040
  return Promise.resolve({});
1067
1041
  },
@@ -1100,7 +1074,7 @@ var initialXlr = {
1100
1074
  renderOverlayLayouts: function renderOverlayLayouts() {
1101
1075
  return Promise.resolve();
1102
1076
  },
1103
- uniqueLayouts: {},
1077
+ uniqueLayouts: new Map(),
1104
1078
  updateInputLayout: function updateInputLayout(layoutIndex, layout) {},
1105
1079
  updateLayouts: function updateLayouts(inputLayouts) {},
1106
1080
  updateLoop: function updateLoop(inputLayouts) {
@@ -14020,11 +13994,11 @@ function normalizeLineEndings(input) {
14020
13994
  * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
14021
13995
  * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-parsing-and-serialization
14022
13996
  */
14023
- function DOMParser$1(options){
13997
+ function DOMParser$2(options){
14024
13998
  this.options = options ||{locator:{}};
14025
13999
  }
14026
14000
 
14027
- DOMParser$1.prototype.parseFromString = function(source,mimeType){
14001
+ DOMParser$2.prototype.parseFromString = function(source,mimeType){
14028
14002
  var options = this.options;
14029
14003
  var sax = new XMLReader();
14030
14004
  var domBuilder = options.domBuilder || new DOMHandler();//contentHandler and LexicalHandler
@@ -14271,9 +14245,9 @@ function appendElement (hander,node) {
14271
14245
 
14272
14246
  domParser.__DOMHandler = DOMHandler;
14273
14247
  domParser.normalizeLineEndings = normalizeLineEndings;
14274
- domParser.DOMParser = DOMParser$1;
14248
+ domParser.DOMParser = DOMParser$2;
14275
14249
 
14276
- var DOMParser = domParser.DOMParser;
14250
+ var DOMParser$1 = domParser.DOMParser;
14277
14251
 
14278
14252
  /*! @name mpd-parser @version 1.3.1 @license Apache-2.0 */
14279
14253
 
@@ -16897,7 +16871,7 @@ const stringToMpdXml = manifestString => {
16897
16871
  throw new Error(errors.DASH_EMPTY_MANIFEST);
16898
16872
  }
16899
16873
 
16900
- const parser = new DOMParser();
16874
+ const parser = new DOMParser$1();
16901
16875
  let xml;
16902
16876
  let mpd;
16903
16877
 
@@ -74026,14 +74000,13 @@ var Media = /*#__PURE__*/function () {
74026
74000
  _this.startMediaTimer(media);
74027
74001
  }
74028
74002
  } else if (media.mediaType === 'shellcommand') {
74029
- if (_this.hasCommandExecuted && !_this.loop) {
74030
- return;
74031
- }
74032
- _this.hasCommandExecuted = true;
74033
- _this.emitCommand(media);
74034
- if (media.duration > 0) {
74035
- _this.startMediaTimer(media);
74003
+ // Fire once per cycle unless loop is enabled, in which case re-fire every play.
74004
+ if (!_this.hasCommandExecuted || _this.loop) {
74005
+ _this.hasCommandExecuted = true;
74006
+ _this.emitCommand(media);
74036
74007
  }
74008
+ // Always run the timer so the layout advances and stats are recorded correctly.
74009
+ _this.startMediaTimer(media);
74037
74010
  } else {
74038
74011
  _this.startMediaTimer(media);
74039
74012
  }
@@ -74109,7 +74082,12 @@ var Media = /*#__PURE__*/function () {
74109
74082
  var _this$sspImpressionUr2, _this$sspErrorUrls2;
74110
74083
  _this.xlr.emitter.emit('sspWidgetEnd', (_this$sspImpressionUr2 = _this.sspImpressionUrls) !== null && _this$sspImpressionUr2 !== void 0 ? _this$sspImpressionUr2 : [], (_this$sspErrorUrls2 = _this.sspErrorUrls) !== null && _this$sspErrorUrls2 !== void 0 ? _this$sspErrorUrls2 : [], _this.sspImpressionUrls ? _this.duration : 0);
74111
74084
  }
74112
- media.region.playNextMedia();
74085
+ // Only advance the region if this media is still the active one.
74086
+ // A user-triggered next/prev action may have already moved currMedia
74087
+ // on, in which case the timer firing here would cause a double-advance.
74088
+ if (media === media.region.currMedia) {
74089
+ media.region.playNextMedia();
74090
+ }
74113
74091
  });
74114
74092
  // Initialize Media object
74115
74093
  this.init();
@@ -74342,11 +74320,11 @@ var Media = /*#__PURE__*/function () {
74342
74320
  };
74343
74321
  var getNewMedia = function getNewMedia() {
74344
74322
  var $region = _this3.region.html;
74345
- // This function is for checking whether
74346
- // the region still has to show a media item
74347
- // when another region is not finished yet
74348
- if (_this3.region.complete && !_this3.region.layout.allEnded) {
74349
- // Add currentMedia to the region
74323
+ // Re-insert the element whenever it is missing from the DOM. This covers:
74324
+ // 1. Region completed early but the layout is still running (freeze last frame).
74325
+ // 2. Backward navigation the previous media's element was removed by the
74326
+ // removeOldMedia setTimeout in transitionNodes.
74327
+ if (_this3.html) {
74350
74328
  $region.insertBefore(_this3.html, $region.lastElementChild);
74351
74329
  return _this3.html;
74352
74330
  }
@@ -74612,15 +74590,21 @@ var Region = /*#__PURE__*/function () {
74612
74590
  });
74613
74591
  // Add media to region for targeted actions
74614
74592
  (_this$layout$actionCo = this.layout.actionController) === null || _this$layout$actionCo === void 0 || _this$layout$actionCo.actions.forEach(function (action) {
74593
+ var _ref2, _attributes$actionTyp, _ref3, _attributes$targetId, _ref4, _attributes$widgetId, _attributes$target;
74615
74594
  var attributes = getAllAttributes(action.xml);
74616
- if (attributes.target.value === 'region' && attributes.actionType.value === 'navWidget' && attributes.targetId.value == _this.id) {
74595
+ // getAllAttributes preserves the XML attribute case. Xibo CMS may export
74596
+ // attributes in camelCase (actionType, targetId, widgetId) or lowercase.
74597
+ // Read both variants so we work with either XLF format.
74598
+ var actionType = (_ref2 = (_attributes$actionTyp = attributes['actionType']) !== null && _attributes$actionTyp !== void 0 ? _attributes$actionTyp : attributes['actiontype']) === null || _ref2 === void 0 ? void 0 : _ref2.value;
74599
+ var targetId = (_ref3 = (_attributes$targetId = attributes['targetId']) !== null && _attributes$targetId !== void 0 ? _attributes$targetId : attributes['targetid']) === null || _ref3 === void 0 ? void 0 : _ref3.value;
74600
+ var widgetId = (_ref4 = (_attributes$widgetId = attributes['widgetId']) !== null && _attributes$widgetId !== void 0 ? _attributes$widgetId : attributes['widgetid']) === null || _ref4 === void 0 ? void 0 : _ref4.value;
74601
+ if (((_attributes$target = attributes['target']) === null || _attributes$target === void 0 ? void 0 : _attributes$target.value) === 'region' && actionType === 'navWidget' && targetId == _this.id) {
74617
74602
  var _this$layout$drawer;
74618
74603
  var drawerMediaItems = Array.from(((_this$layout$drawer = _this.layout.drawer) === null || _this$layout$drawer === void 0 ? void 0 : _this$layout$drawer.getElementsByTagName('media')) || []);
74619
74604
  drawerMediaItems.forEach(function (drawerMedia) {
74620
- var _attributes$widgetId;
74621
- if (drawerMedia.id === ((_attributes$widgetId = attributes.widgetId) === null || _attributes$widgetId === void 0 ? void 0 : _attributes$widgetId.value)) {
74605
+ if (drawerMedia.getAttribute('id') === widgetId) {
74622
74606
  // Add drawer media to the region
74623
- _this.mediaObjectsActions.push(new Media(_this, (drawerMedia === null || drawerMedia === void 0 ? void 0 : drawerMedia.getAttribute('id')) || '', drawerMedia, _this.options, _this.xlr));
74607
+ _this.mediaObjectsActions.push(new Media(_this, drawerMedia.getAttribute('id') || '', drawerMedia, _this.options, _this.xlr));
74624
74608
  }
74625
74609
  });
74626
74610
  }
@@ -74652,6 +74636,11 @@ var Region = /*#__PURE__*/function () {
74652
74636
  prepareAudioMedia(media, this);
74653
74637
  } else if ((media.render === 'html' || media.mediaType === 'webpage') && media.iframe && media.checkIframeStatus) {
74654
74638
  prepareHtmlMedia(media, this);
74639
+ } else if (media.mediaType === 'shellcommand') {
74640
+ // Shell command widgets are invisible but must be in the DOM to trigger playback.
74641
+ if (media.html) {
74642
+ this.html.appendChild(media.html);
74643
+ }
74655
74644
  }
74656
74645
  }
74657
74646
  }, {
@@ -74875,7 +74864,17 @@ var Region = /*#__PURE__*/function () {
74875
74864
  }, {
74876
74865
  key: "playNextMedia",
74877
74866
  value: function playNextMedia() {
74878
- var _this$oldMedia3, _this$currMedia2, _this$nxtMedia, _this$currMedia3, _this$currMedia4, _this$currMedia5, _this$currMedia6, _this$oldMedia4, _this$currMedia7, _this$nxtMedia2;
74867
+ var _this$oldMedia3,
74868
+ _this$currMedia2,
74869
+ _this$nxtMedia,
74870
+ _this$currMedia3,
74871
+ _this$currMedia4,
74872
+ _this$currMedia5,
74873
+ _this$currMedia6,
74874
+ _this3 = this,
74875
+ _this$oldMedia4,
74876
+ _this$currMedia7,
74877
+ _this$nxtMedia2;
74879
74878
  console.debug('??? XLR.debug Region playing next media', {
74880
74879
  regionId: this.id,
74881
74880
  currentMediaIndex: this.currentMediaIndex,
@@ -74895,8 +74894,10 @@ var Region = /*#__PURE__*/function () {
74895
74894
  // cycle completion after the skip loop runs.
74896
74895
  var origIndex = this.currentMediaIndex;
74897
74896
  // When the region has completed and when currentMedia is html
74898
- // Then, preserve the currentMedia state
74899
- if (this.complete && ((_this$currMedia3 = this.currMedia) === null || _this$currMedia3 === void 0 ? void 0 : _this$currMedia3.render) === 'html') {
74897
+ // and there is only one media object, preserve the currentMedia state.
74898
+ // Guard is limited to single-media regions so navWidget injections
74899
+ // (which splice a second media in) are not blocked.
74900
+ if (this.complete && ((_this$currMedia3 = this.currMedia) === null || _this$currMedia3 === void 0 ? void 0 : _this$currMedia3.render) === 'html' && this.totalMediaObjects === 1) {
74900
74901
  return;
74901
74902
  }
74902
74903
  // When the region has completed and mediaObjects.length = 1
@@ -74942,6 +74943,25 @@ var Region = /*#__PURE__*/function () {
74942
74943
  }
74943
74944
  });
74944
74945
  }
74946
+ // Remove single-play media injected via navWidget actions at the end of each cycle
74947
+ if (crossedEnd && this.mediaObjects.some(function (m) {
74948
+ return m.singlePlay;
74949
+ })) {
74950
+ this.mediaObjects = this.mediaObjects.filter(function (m) {
74951
+ return !m.singlePlay;
74952
+ });
74953
+ this.totalMediaObjects = this.mediaObjects.length;
74954
+ if (this.totalMediaObjects === 0) {
74955
+ this.finished();
74956
+ return;
74957
+ }
74958
+ var newIndex = this.mediaObjects.findIndex(function (m) {
74959
+ return m === _this3.currMedia;
74960
+ });
74961
+ this.currentMediaIndex = newIndex >= 0 ? newIndex : 0;
74962
+ this.currMedia = this.mediaObjects[this.currentMediaIndex];
74963
+ this.nxtMedia = this.mediaObjects[(this.currentMediaIndex + 1) % this.totalMediaObjects];
74964
+ }
74945
74965
  console.debug('??? XLR.debug >> End Region::playNextMedia > execute transitionNodes', {
74946
74966
  regionId: this.id,
74947
74967
  currentMediaIndex: this.currentMediaIndex,
@@ -74962,14 +74982,15 @@ var Region = /*#__PURE__*/function () {
74962
74982
  }, {
74963
74983
  key: "playPreviousMedia",
74964
74984
  value: function playPreviousMedia() {
74965
- this.currentMediaIndex = this.currentMediaIndex - 1;
74966
- if (this.currentMediaIndex < 0 || this.ended) {
74967
- this.currentMediaIndex = 0;
74985
+ if (this.currentMediaIndex <= 0 || this.ended) {
74968
74986
  return;
74969
74987
  }
74970
- this.prepareMediaObjects();
74988
+ this.oldMedia = this.currMedia;
74989
+ this.currentMediaIndex -= 1;
74990
+ this.currMedia = this.mediaObjects[this.currentMediaIndex];
74991
+ this.nxtMedia = this.mediaObjects[(this.currentMediaIndex + 1) % this.totalMediaObjects];
74992
+ this.complete = false;
74971
74993
  console.debug('region::playPreviousMedia', this);
74972
- /* Do the transition */
74973
74994
  this.transitionNodes(this.oldMedia, this.currMedia);
74974
74995
  }
74975
74996
  }, {
@@ -75168,6 +75189,10 @@ var ActionController = /*#__PURE__*/function () {
75168
75189
  key: "openLayoutInNewTab",
75169
75190
  value: function openLayoutInNewTab(layoutCode, options) {
75170
75191
  var url = options.layoutPreviewUrl.replace('[layoutCode]', layoutCode) + '?findByCode=1';
75192
+ console.debug('[ActionController::openLayoutInNewTab] Navigating to layout in new tab with code', {
75193
+ layoutCode: layoutCode,
75194
+ url: url
75195
+ });
75171
75196
  // Send a postMessage to the parent frame so the CMS can handle the confirmation
75172
75197
  // and navigation (confirm() is blocked in sandboxed iframes without allow-modals).
75173
75198
  window.parent.postMessage({
@@ -75180,26 +75205,40 @@ var ActionController = /*#__PURE__*/function () {
75180
75205
  }
75181
75206
  }, {
75182
75207
  key: "openLayoutInPlayer",
75183
- value: function openLayoutInPlayer(layoutCode, options) {
75184
- // this.parent.xlr.updateLoop([]);
75208
+ value: function openLayoutInPlayer(layoutCode, _options) {
75209
+ console.debug('[ActionController::openLayoutInPlayer] Navigating to layout in player with code', {
75210
+ layoutCode: layoutCode,
75211
+ options: _options
75212
+ });
75213
+ this.parent.xlr.emitter.emit('navLayout', layoutCode, '');
75185
75214
  }
75186
75215
  }, {
75187
75216
  key: "prevOrNextLayout",
75188
75217
  value: function prevOrNextLayout(targetId, actionType) {
75189
75218
  var _this$parent$xlr$curr;
75190
- // Check if currentLayout is the targetId
75191
- if (((_this$parent$xlr$curr = this.parent.xlr.currentLayout) === null || _this$parent$xlr$curr === void 0 ? void 0 : _this$parent$xlr$curr.layoutId) === parseInt(targetId)) {
75192
- if (actionType === 'next') {
75193
- this.parent.xlr.gotoNextLayout();
75194
- } else if (actionType === 'previous') {
75195
- this.parent.xlr.gotoPrevLayout();
75196
- }
75219
+ console.debug('[ActionController::prevOrNextLayout] Changing layout with data', {
75220
+ targetId: targetId,
75221
+ actionType: actionType
75222
+ });
75223
+ // For screen-level actions targetId may be "0" (the screen has no numeric ID).
75224
+ // Guard using this.parent.layoutId instead so the check always works.
75225
+ if (((_this$parent$xlr$curr = this.parent.xlr.currentLayout) === null || _this$parent$xlr$curr === void 0 ? void 0 : _this$parent$xlr$curr.layoutId) !== this.parent.layoutId) {
75226
+ return;
75227
+ }
75228
+ if (actionType === 'next') {
75229
+ this.parent.xlr.gotoNextLayout();
75230
+ } else if (actionType === 'previous') {
75231
+ this.parent.xlr.gotoPrevLayout();
75197
75232
  }
75198
75233
  }
75199
75234
  /** Change media in region (next/previous) */
75200
75235
  }, {
75201
- key: "nextMediaInRegion",
75202
- value: function nextMediaInRegion(regionId, actionType) {
75236
+ key: "gotoMediaInRegion",
75237
+ value: function gotoMediaInRegion(regionId, actionType) {
75238
+ console.debug('[ActionController::gotoMediaInRegion] Changing media in region with data', {
75239
+ regionId: regionId,
75240
+ actionType: actionType
75241
+ });
75203
75242
  // Find target region
75204
75243
  this.parent.regions.forEach(function (regionObj) {
75205
75244
  if (regionObj.id === regionId) {
@@ -75214,7 +75253,11 @@ var ActionController = /*#__PURE__*/function () {
75214
75253
  }, {
75215
75254
  key: "loadMediaInRegion",
75216
75255
  value: function loadMediaInRegion(regionId, widgetId) {
75217
- var _targetRegion, _targetRegion2, _targetRegion3;
75256
+ var _targetRegion, _targetRegion2, _targetRegion3, _targetRegion4;
75257
+ console.debug('[ActionController::loadMediaInRegion] Loading media in region with data', {
75258
+ regionId: regionId,
75259
+ widgetId: widgetId
75260
+ });
75218
75261
  var self = this;
75219
75262
  // Find target region
75220
75263
  var targetRegion;
@@ -75237,27 +75280,70 @@ var ActionController = /*#__PURE__*/function () {
75237
75280
  targetMedia.singlePlay = true;
75238
75281
  }
75239
75282
  // If region is empty, remove the background color and empty message
75240
- if (((_targetRegion = targetRegion) === null || _targetRegion === void 0 ? void 0 : _targetRegion.mediaObjects.length) === 0) {
75283
+ if (((_targetRegion = targetRegion) === null || _targetRegion === void 0 ? void 0 : _targetRegion.totalMediaObjects) === 0) {
75284
+ targetRegion.complete = false;
75285
+ }
75286
+ // Bail out early when the target widget was not found in the drawer
75287
+ if (!targetMedia) {
75288
+ console.debug('[ActionController::loadMediaInRegion] Target media not found in mediaObjectsActions', {
75289
+ regionId: regionId,
75290
+ widgetId: widgetId
75291
+ });
75292
+ return;
75293
+ }
75294
+ // Guard against duplicate insertion if the action fires multiple times before the widget plays
75295
+ if (targetRegion && targetRegion.mediaObjects.some(function (m) {
75296
+ return m.id === targetMedia.id;
75297
+ })) {
75298
+ console.debug('[ActionController::loadMediaInRegion] Target media already queued, skipping duplicate insertion');
75299
+ return;
75300
+ }
75301
+ // Cancel the current media's duration timer so it doesn't fire and interrupt
75302
+ // the target widget mid-playback (e.g. an Interactive Zone timer still ticking).
75303
+ if ((_targetRegion2 = targetRegion) !== null && _targetRegion2 !== void 0 && (_targetRegion2 = _targetRegion2.currMedia) !== null && _targetRegion2 !== void 0 && _targetRegion2.mediaTimer) {
75304
+ clearInterval(targetRegion.currMedia.mediaTimer);
75305
+ targetRegion.currMedia.mediaTimer = undefined;
75306
+ }
75307
+ // Reset complete so the HTML-media guard in playNextMedia() doesn't block
75308
+ // the transition (that guard is for single-media loops, not navWidget injections).
75309
+ if (targetRegion) {
75241
75310
  targetRegion.complete = false;
75242
75311
  }
75243
75312
  // Create media in region and play it next
75244
- (_targetRegion2 = targetRegion) === null || _targetRegion2 === void 0 || _targetRegion2.mediaObjects.splice(targetRegion.currentMediaIndex + 1, 0, targetMedia);
75245
- (_targetRegion3 = targetRegion) === null || _targetRegion3 === void 0 || _targetRegion3.playNextMedia();
75313
+ (_targetRegion3 = targetRegion) === null || _targetRegion3 === void 0 || _targetRegion3.mediaObjects.splice(targetRegion.currentMediaIndex + 1, 0, targetMedia);
75314
+ // Keep totalMediaObjects in sync with the actual array length
75315
+ if (targetRegion) {
75316
+ targetRegion.totalMediaObjects = targetRegion.mediaObjects.length;
75317
+ }
75318
+ // Drawer media items are never run through the normal prepareMedia pipeline,
75319
+ // so their DOM element has no background-image / src set and is not yet in the
75320
+ // region DOM. Prepare it now so Media.run() finds a ready element to show.
75321
+ if (targetRegion) {
75322
+ targetRegion.prepareMedia(targetMedia);
75323
+ }
75324
+ console.debug('[ActionController::loadMediaInRegion] Target media loaded, playing next', {
75325
+ regionId: regionId,
75326
+ widgetId: widgetId
75327
+ });
75328
+ (_targetRegion4 = targetRegion) === null || _targetRegion4 === void 0 || _targetRegion4.playNextMedia();
75246
75329
  }
75247
75330
  /** Run action based on action data */
75248
75331
  }, {
75249
75332
  key: "runAction",
75250
75333
  value: function runAction(actionData, options) {
75334
+ console.debug('[ActionController::runAction] Triggering action', {
75335
+ actionData: actionData
75336
+ });
75251
75337
  if (actionData.actiontype == 'navLayout') {
75252
75338
  if (this.parent.xlr.config.platform === exports.ConsumerPlatform.CMS) {
75253
- // Open layout preview in a new tab
75339
+ // Open layout preview in a new tab (CMS preview only)
75254
75340
  this.openLayoutInNewTab(actionData.layoutcode, options);
75255
- } else if (this.parent.xlr.config.platform === exports.ConsumerPlatform.CHROMEOS) {
75256
- // Set target layout as active layout
75341
+ } else {
75342
+ // All player platforms (Electron, ChromeOS, Android, etc.)
75257
75343
  this.openLayoutInPlayer(actionData.layoutcode, options);
75258
75344
  }
75259
75345
  } else if ((actionData.actiontype == 'previous' || actionData.actiontype == 'next') && actionData.target == 'region') {
75260
- this.nextMediaInRegion(actionData.targetid, actionData.actiontype);
75346
+ this.gotoMediaInRegion(actionData.targetid, actionData.actiontype);
75261
75347
  } else if (actionData.actiontype == 'navWidget' && actionData.target == 'region') {
75262
75348
  this.loadMediaInRegion(actionData.targetid, actionData.widgetid);
75263
75349
  } else if (actionData.target === 'screen') {
@@ -75316,6 +75402,18 @@ var ActionController = /*#__PURE__*/function () {
75316
75402
  }
75317
75403
  });
75318
75404
  }
75405
+ /** Dispatch an incoming webhook trigger to any matching actions on this layout. */
75406
+ }, {
75407
+ key: "handleWebhookTrigger",
75408
+ value: function handleWebhookTrigger(triggerCode, widgetId) {
75409
+ var _this3 = this;
75410
+ this.$actionController.querySelectorAll('.action[triggertype="webhook"]').forEach(function ($el) {
75411
+ var ds = $el.dataset;
75412
+ if (ds.triggercode !== triggerCode) return;
75413
+ if (widgetId && ds.sourceid !== widgetId) return;
75414
+ _this3.runAction(ds, _this3.options);
75415
+ });
75416
+ }
75319
75417
  }, {
75320
75418
  key: "initKeyboardActions",
75321
75419
  value: function initKeyboardActions() {
@@ -76365,6 +76463,13 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76365
76463
  return _ref4.apply(this, arguments);
76366
76464
  };
76367
76465
  }());
76466
+ xlrObject.on('navLayout', function (layoutCode) {
76467
+ // Non-CMS platforms handle navLayout in their renderer via playInterruptLayout.
76468
+ // CMS navLayout is handled by ActionController (opens layout in a new tab).
76469
+ console.debug('[navLayout] XLR::on("navLayout") - received', {
76470
+ layoutCode: layoutCode
76471
+ });
76472
+ });
76368
76473
  xlrObject.emitSync = /*#__PURE__*/function () {
76369
76474
  var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(eventName) {
76370
76475
  var _xlrObject$emitter$ev;
@@ -76544,35 +76649,28 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76544
76649
  }));
76545
76650
  xlrObject.updateScheduleLayouts = /*#__PURE__*/function () {
76546
76651
  var _ref9 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee9(scheduleLayouts) {
76547
- var inputLayoutIds, _iterator, _step, _step$value, layoutIndex, _layout, uniqueLayout, _i, _Object$keys, layoutId;
76652
+ var next;
76548
76653
  return _regeneratorRuntime().wrap(function _callee9$(_context9) {
76549
76654
  while (1) switch (_context9.prev = _context9.next) {
76550
76655
  case 0:
76551
- console.debug('XLR::updateScheduleLayouts > Updating schedule layouts . . .');
76552
- inputLayoutIds = [];
76553
- _iterator = _createForOfIteratorHelper(scheduleLayouts.entries());
76554
- try {
76555
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
76556
- _step$value = _slicedToArray(_step.value, 2), layoutIndex = _step$value[0], _layout = _step$value[1];
76557
- uniqueLayout = _layout;
76558
- uniqueLayout.index = layoutIndex;
76559
- uniqueLayout.id = _layout.layoutId;
76560
- this.uniqueLayouts[_layout.layoutId] = uniqueLayout;
76561
- inputLayoutIds.push(_layout.layoutId);
76562
- }
76563
- // Cross-check if we need to remove non-existing layouts based on inputLayouts
76564
- } catch (err) {
76565
- _iterator.e(err);
76566
- } finally {
76567
- _iterator.f();
76568
- }
76569
- for (_i = 0, _Object$keys = Object.keys(this.uniqueLayouts); _i < _Object$keys.length; _i++) {
76570
- layoutId = _Object$keys[_i];
76571
- if (!inputLayoutIds.includes(parseInt(layoutId))) {
76572
- delete this.uniqueLayouts[layoutId];
76573
- }
76656
+ console.debug('XLR::updateScheduleLayouts > Updating schedule layouts . . .', scheduleLayouts);
76657
+ next = new Map();
76658
+ if (!(scheduleLayouts.length === 0)) {
76659
+ _context9.next = 5;
76660
+ break;
76574
76661
  }
76662
+ this.uniqueLayouts = next;
76663
+ return _context9.abrupt("return");
76575
76664
  case 5:
76665
+ scheduleLayouts.forEach(function (_layout, layoutIndex) {
76666
+ next.set(String(_layout.layoutId), _objectSpread2(_objectSpread2({}, _layout), {}, {
76667
+ index: layoutIndex,
76668
+ id: _layout.layoutId
76669
+ }));
76670
+ });
76671
+ console.debug('XLR::updateScheduleLayouts > next unique layouts', Array.from(next).values());
76672
+ this.uniqueLayouts = next;
76673
+ case 8:
76576
76674
  case "end":
76577
76675
  return _context9.stop();
76578
76676
  }
@@ -76621,6 +76719,36 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76621
76719
  case 0:
76622
76720
  console.debug('>>>> XLR.debug XLR::updateLoop > Updating schedule loop . . .');
76623
76721
  this.inputLayouts = inputLayouts;
76722
+ // Guard against a splash-only update: uniqueLayouts has no entry for layoutId 0,
76723
+ // so parseLayouts() would return undefined current/next and prepareLayoutXlf()
76724
+ // would be called with undefined. Clean up any playing layouts and show splash directly.
76725
+ if (!(inputLayouts.length === 1 && inputLayouts[0].layoutId === 0)) {
76726
+ _context11.next = 14;
76727
+ break;
76728
+ }
76729
+ if (!(this.currentLayout && this.isLayoutInDOM(this.currentLayout.containerName, this.currentLayout.index))) {
76730
+ _context11.next = 8;
76731
+ break;
76732
+ }
76733
+ // Force all regions to complete immediately
76734
+ this.currentLayout.inLoop = false;
76735
+ _context11.next = 7;
76736
+ return this.currentLayout.finishAllRegions();
76737
+ case 7:
76738
+ this.currentLayout.removeLayout();
76739
+ case 8:
76740
+ if (this.nextLayout) {
76741
+ // Discard regardless of DOM presence: nextLayout may be preloaded with
76742
+ // DOM elements and video.js players but not yet attached to the screen container.
76743
+ this.nextLayout.discardLayout(exports.LayoutPlaybackType.NEXT);
76744
+ }
76745
+ this.currentLayout = undefined;
76746
+ this.nextLayout = undefined;
76747
+ _context11.next = 13;
76748
+ return this.playSchedules(this);
76749
+ case 13:
76750
+ return _context11.abrupt("return");
76751
+ case 14:
76624
76752
  playback = this.parseLayouts(true);
76625
76753
  isCurrentLayoutValid = isLayoutValid(this.inputLayouts, (_this$currentLayout = this.currentLayout) === null || _this$currentLayout === void 0 ? void 0 : _this$currentLayout.layoutId);
76626
76754
  if (this.isSspEnabled && this.currentLayoutId === -1) {
@@ -76629,7 +76757,7 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76629
76757
  if (!isCurrentLayoutValid && this.currentLayout) {
76630
76758
  this.currentLayout.emitter.emit('cancelled', this.currentLayout);
76631
76759
  }
76632
- console.debug('>>>>> XLR.debug XLR::updateLoop > uniqueLayouts', this.uniqueLayouts);
76760
+ console.debug('>>>>> XLR.debug XLR::updateLoop > uniqueLayouts', Array.from(this.uniqueLayouts.values()));
76633
76761
  console.debug('>>>>> XLR.debug XLR::updateLoop > inputLayouts', this.inputLayouts);
76634
76762
  console.debug('>>>>> XLR.debug XLR::updateLoop > isCurrentLayoutValid', isCurrentLayoutValid);
76635
76763
  console.debug('>>>>> XLR.debug XLR::updateLoop > currentLayout', this.currentLayout);
@@ -76657,86 +76785,86 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76657
76785
  };
76658
76786
  }();
76659
76787
  if (isCurrentLayoutValid) {
76660
- _context11.next = 55;
76788
+ _context11.next = 67;
76661
76789
  break;
76662
76790
  }
76663
76791
  if (!playback.hasDefaultOnly) {
76664
- _context11.next = 34;
76792
+ _context11.next = 46;
76665
76793
  break;
76666
76794
  }
76667
76795
  if (!(this.currentLayout && playback.currentLayout && this.currentLayout.layoutId !== playback.currentLayout.layoutId)) {
76668
- _context11.next = 20;
76796
+ _context11.next = 32;
76669
76797
  break;
76670
76798
  }
76671
76799
  this.currentLayout.inLoop = false;
76672
- _context11.next = 19;
76800
+ _context11.next = 31;
76673
76801
  return this.currentLayout.finishAllRegions();
76674
- case 19:
76802
+ case 31:
76675
76803
  this.currentLayout.removeLayout();
76676
- case 20:
76804
+ case 32:
76677
76805
  // Discard old nextLayout before replacing it — same as the
76678
76806
  // other two branches do, otherwise the prepared DOM element
76679
76807
  // and any video.js players are orphaned.
76680
76808
  if (this.nextLayout && this.isLayoutInDOM(this.nextLayout.containerName, this.nextLayout.index)) {
76681
76809
  this.nextLayout.discardLayout(exports.LayoutPlaybackType.NEXT);
76682
76810
  }
76683
- _context11.next = 23;
76811
+ _context11.next = 35;
76684
76812
  return this.prepareLayoutXlf(playback.currentLayout);
76685
- case 23:
76813
+ case 35:
76686
76814
  this.currentLayout = _context11.sent;
76687
76815
  this.currentLayoutId = this.currentLayout.layoutId;
76688
76816
  _context11.t0 = this;
76689
- _context11.next = 28;
76817
+ _context11.next = 40;
76690
76818
  return this.prepareLayoutXlf(playback.nextLayout);
76691
- case 28:
76819
+ case 40:
76692
76820
  _context11.t1 = _context11.sent;
76693
- _context11.next = 31;
76821
+ _context11.next = 43;
76694
76822
  return _context11.t0.prepareForSsp.call(_context11.t0, _context11.t1);
76695
- case 31:
76823
+ case 43:
76696
76824
  this.nextLayout = _context11.sent;
76697
- _context11.next = 51;
76825
+ _context11.next = 63;
76698
76826
  break;
76699
- case 34:
76827
+ case 46:
76700
76828
  if (!(this.currentLayout && this.isLayoutInDOM(this.currentLayout.containerName, this.currentLayout.index))) {
76701
- _context11.next = 39;
76829
+ _context11.next = 51;
76702
76830
  break;
76703
76831
  }
76704
76832
  this.currentLayout.inLoop = false;
76705
- _context11.next = 38;
76833
+ _context11.next = 50;
76706
76834
  return this.currentLayout.finishAllRegions();
76707
- case 38:
76835
+ case 50:
76708
76836
  this.currentLayout.removeLayout();
76709
- case 39:
76837
+ case 51:
76710
76838
  if (this.nextLayout && this.isLayoutInDOM(this.nextLayout.containerName, this.nextLayout.index)) {
76711
76839
  this.nextLayout.discardLayout(exports.LayoutPlaybackType.NEXT);
76712
76840
  }
76713
76841
  if (!playback.currentLayout) {
76714
- _context11.next = 43;
76842
+ _context11.next = 55;
76715
76843
  break;
76716
76844
  }
76717
- _context11.next = 43;
76845
+ _context11.next = 55;
76718
76846
  return prepareNewCurrentLayout();
76719
- case 43:
76847
+ case 55:
76720
76848
  if (!playback.nextLayout) {
76721
- _context11.next = 51;
76849
+ _context11.next = 63;
76722
76850
  break;
76723
76851
  }
76724
76852
  _context11.t2 = this;
76725
- _context11.next = 47;
76853
+ _context11.next = 59;
76726
76854
  return this.prepareLayoutXlf(playback.nextLayout);
76727
- case 47:
76855
+ case 59:
76728
76856
  _context11.t3 = _context11.sent;
76729
- _context11.next = 50;
76857
+ _context11.next = 62;
76730
76858
  return _context11.t2.prepareForSsp.call(_context11.t2, _context11.t3);
76731
- case 50:
76859
+ case 62:
76732
76860
  this.nextLayout = _context11.sent;
76733
- case 51:
76734
- _context11.next = 53;
76861
+ case 63:
76862
+ _context11.next = 65;
76735
76863
  return this.playSchedules(this);
76736
- case 53:
76737
- _context11.next = 67;
76864
+ case 65:
76865
+ _context11.next = 79;
76738
76866
  break;
76739
- case 55:
76867
+ case 67:
76740
76868
  // Remove next layout if it is in the DOM
76741
76869
  if (this.nextLayout && this.isLayoutInDOM(this.nextLayout.containerName, this.nextLayout.index)) {
76742
76870
  this.nextLayout.discardLayout(exports.LayoutPlaybackType.NEXT);
@@ -76763,22 +76891,22 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76763
76891
  // nextLayout keeps the cycle in order; the slot after that will be
76764
76892
  // prepared by the normal prepareLayouts() call at transition time.
76765
76893
  if (!playback.currentLayout) {
76766
- _context11.next = 66;
76894
+ _context11.next = 78;
76767
76895
  break;
76768
76896
  }
76769
76897
  this.currentLayoutIndex = playback.currentLayoutIndex;
76770
76898
  _context11.t4 = this;
76771
- _context11.next = 62;
76899
+ _context11.next = 74;
76772
76900
  return this.prepareLayoutXlf(playback.currentLayout);
76773
- case 62:
76901
+ case 74:
76774
76902
  _context11.t5 = _context11.sent;
76775
- _context11.next = 65;
76903
+ _context11.next = 77;
76776
76904
  return _context11.t4.prepareForSsp.call(_context11.t4, _context11.t5);
76777
- case 65:
76905
+ case 77:
76778
76906
  this.nextLayout = _context11.sent;
76779
- case 66:
76907
+ case 78:
76780
76908
  console.debug('>>>> XLR.debug XLR::updateLoop > updated nextLayout', this.nextLayout);
76781
- case 67:
76909
+ case 79:
76782
76910
  case "end":
76783
76911
  return _context11.stop();
76784
76912
  }
@@ -76808,7 +76936,7 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76808
76936
  };
76809
76937
  }();
76810
76938
  xlrObject.parseLayouts = function (hasChanged) {
76811
- var _this$currentLayout2, _this$currentLayout3;
76939
+ var _this$currentLayout2, _this$currentLayout3, _this$currentLayout4, _this$nextLayout, _currentLayout2, _nextLayout2;
76812
76940
  var _currentLayout;
76813
76941
  var _nextLayout;
76814
76942
  var _hasDefaultOnly = hasDefaultOnly(this.inputLayouts);
@@ -76821,17 +76949,28 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76821
76949
  if (this.isSspEnabled && ((_this$currentLayout3 = this.currentLayout) === null || _this$currentLayout3 === void 0 ? void 0 : _this$currentLayout3.layoutId) === -1) {
76822
76950
  isCurrentLayoutValid = true;
76823
76951
  }
76952
+ console.debug('XLR::parseLayouts', {
76953
+ currentLayoutId: (_this$currentLayout4 = this.currentLayout) === null || _this$currentLayout4 === void 0 ? void 0 : _this$currentLayout4.layoutId,
76954
+ currentLayoutIndex: this.currentLayoutIndex,
76955
+ nextLayoutId: (_this$nextLayout = this.nextLayout) === null || _this$nextLayout === void 0 ? void 0 : _this$nextLayout.layoutId,
76956
+ isCurrentLayoutValid: isCurrentLayoutValid,
76957
+ hasChanged: !!hasChanged,
76958
+ inputLayoutsCount: this.inputLayouts.length,
76959
+ inputLayoutIds: this.inputLayouts.map(function (l) {
76960
+ return l.layoutId;
76961
+ }).join(', ')
76962
+ });
76824
76963
  _currentLayout = this.currentLayout;
76825
76964
  if (this.currentLayout && this.nextLayout) {
76826
76965
  // Both currentLayout and nextLayout has values
76827
76966
  if (hasLayout) {
76828
76967
  if (!isCurrentLayoutValid) {
76829
- var _this$nextLayout;
76968
+ var _this$nextLayout2;
76830
76969
  // Check if currentLayout.state is PLAYED,
76831
76970
  // then, validate nextLayout and if valid,
76832
76971
  // proceed to nextLayout as new currentLayout
76833
76972
  // Else, go back to first layout in the loop
76834
- if (this.currentLayout.state === exports.ELayoutState.PLAYED && isLayoutValid(this.inputLayouts, (_this$nextLayout = this.nextLayout) === null || _this$nextLayout === void 0 ? void 0 : _this$nextLayout.layoutId)) {
76973
+ if (this.currentLayout.state === exports.ELayoutState.PLAYED && isLayoutValid(this.inputLayouts, (_this$nextLayout2 = this.nextLayout) === null || _this$nextLayout2 === void 0 ? void 0 : _this$nextLayout2.layoutId)) {
76835
76974
  // Get nextLayout from updated loop
76836
76975
  var tempNextLayoutIndex = getLayoutIndexByLayoutId(this.inputLayouts, this.nextLayout.layoutId);
76837
76976
  _currentLayoutIndex = tempNextLayoutIndex !== null && tempNextLayoutIndex !== void 0 ? tempNextLayoutIndex : 0;
@@ -76875,7 +77014,7 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76875
77014
  _nextLayout = setLayoutIndex(_nextLayout, _nextLayoutIndex);
76876
77015
  }
76877
77016
  } else {
76878
- var _this$currentLayout4, _this$currentLayout5;
77017
+ var _this$currentLayout5, _this$currentLayout6;
76879
77018
  _currentLayout = this.nextLayout;
76880
77019
  _currentLayoutIndex = _currentLayout.index;
76881
77020
  // updateLoop can re-queue the same index that is currently
@@ -76885,7 +77024,7 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76885
77024
  // whether the queued next-to-current is at the same index as the
76886
77025
  // layout that just finished, and advance past it so the following
76887
77026
  // slot (e.g. an SSP that now has an ad) becomes current instead.
76888
- if (this.inputLayouts.length > 1 && (_this$currentLayout4 = this.currentLayout) !== null && _this$currentLayout4 !== void 0 && _this$currentLayout4.done && _currentLayoutIndex === ((_this$currentLayout5 = this.currentLayout) === null || _this$currentLayout5 === void 0 ? void 0 : _this$currentLayout5.index)) {
77027
+ if (this.inputLayouts.length > 1 && (_this$currentLayout5 = this.currentLayout) !== null && _this$currentLayout5 !== void 0 && _this$currentLayout5.done && _currentLayoutIndex === ((_this$currentLayout6 = this.currentLayout) === null || _this$currentLayout6 === void 0 ? void 0 : _this$currentLayout6.index)) {
76889
77028
  _currentLayoutIndex = (_currentLayoutIndex + 1) % this.inputLayouts.length;
76890
77029
  _currentLayout = this.getLayout(this.inputLayouts[_currentLayoutIndex]);
76891
77030
  _currentLayout = setLayoutIndex(_currentLayout, _currentLayoutIndex);
@@ -76922,6 +77061,12 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76922
77061
  _currentLayout.xlr = this;
76923
77062
  _nextLayout.xlr = this;
76924
77063
  }
77064
+ console.debug('XLR::parseLayouts result', {
77065
+ currentLayoutId: (_currentLayout2 = _currentLayout) === null || _currentLayout2 === void 0 ? void 0 : _currentLayout2.layoutId,
77066
+ currentLayoutIndex: _currentLayoutIndex,
77067
+ nextLayoutId: (_nextLayout2 = _nextLayout) === null || _nextLayout2 === void 0 ? void 0 : _nextLayout2.layoutId,
77068
+ nextLayoutIndex: _nextLayoutIndex
77069
+ });
76925
77070
  return {
76926
77071
  currentLayout: _currentLayout,
76927
77072
  nextLayout: _nextLayout,
@@ -76933,7 +77078,7 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76933
77078
  };
76934
77079
  xlrObject.getLayout = function (inputLayout) {
76935
77080
  var isCMS = this.config.platform === exports.ConsumerPlatform.CMS;
76936
- if (!isCMS && Object.keys(this.uniqueLayouts).length === 0) {
77081
+ if (!isCMS && this.uniqueLayouts.size === 0) {
76937
77082
  return;
76938
77083
  }
76939
77084
  var _layout = {};
@@ -76950,7 +77095,13 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76950
77095
  activeLayout.id = activeLayout.layoutId;
76951
77096
  }
76952
77097
  } else {
76953
- activeLayout = _objectSpread2({}, this.uniqueLayouts[inputLayout.layoutId]);
77098
+ var layoutFromUniqueLayouts = this.uniqueLayouts.get(String(inputLayout.layoutId));
77099
+ console.debug('XLR::getLayout > layoutFromUniqueLayouts', {
77100
+ layoutFromUniqueLayouts: layoutFromUniqueLayouts,
77101
+ inputLayout: inputLayout,
77102
+ uniqueLayouts: this.uniqueLayouts
77103
+ });
77104
+ activeLayout = layoutFromUniqueLayouts ? _objectSpread2({}, layoutFromUniqueLayouts) : _objectSpread2({}, inputLayout);
76954
77105
  }
76955
77106
  _layout = _objectSpread2(_objectSpread2({}, _layout), activeLayout);
76956
77107
  console.debug('XLR::getLayout > activeLayout from uniqueLayouts', {
@@ -76967,10 +77118,10 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76967
77118
  return iLayout;
76968
77119
  };
76969
77120
  xlrObject.getLayoutById = function (layoutId, layoutIndex) {
76970
- if (!layoutId || Object.keys(this.uniqueLayouts).length === 0) {
77121
+ if (!layoutId || this.uniqueLayouts.size === 0 || !this.uniqueLayouts.has(String(layoutId))) {
76971
77122
  return undefined;
76972
77123
  }
76973
- var _layout = _objectSpread2(_objectSpread2({}, initialLayout), this.uniqueLayouts[layoutId]);
77124
+ var _layout = _objectSpread2(_objectSpread2({}, initialLayout), this.uniqueLayouts.get(String(layoutId)));
76974
77125
  // Set layout index if available
76975
77126
  if (layoutIndex) {
76976
77127
  _layout.index = layoutIndex;
@@ -76978,71 +77129,79 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
76978
77129
  return _layout;
76979
77130
  };
76980
77131
  xlrObject.prepareLayouts = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee14() {
76981
- var _layoutPlayback$curre, _layoutPlayback$curre2;
77132
+ var _layoutPlayback$curre, _layoutPlayback$nextL, _layoutPlayback$curre2, _layoutPlayback$curre3, _layouts$, _layouts$2, _layouts$3, _layouts$4;
76982
77133
  var self, layoutPlayback, currentLayoutXlf, wasCurrentReused, nextLayoutXlf, layouts;
76983
77134
  return _regeneratorRuntime().wrap(function _callee14$(_context14) {
76984
77135
  while (1) switch (_context14.prev = _context14.next) {
76985
77136
  case 0:
76986
77137
  self = xlrObject;
76987
77138
  if (!this.isUpdatingLoop) {
76988
- _context14.next = 3;
77139
+ _context14.next = 4;
76989
77140
  break;
76990
77141
  }
77142
+ console.debug('XLR::prepareLayouts - skipped (isUpdatingLoop)');
76991
77143
  return _context14.abrupt("return", Promise.resolve(self));
76992
- case 3:
77144
+ case 4:
76993
77145
  layoutPlayback = self.parseLayouts(); // Don't prepare layout if it's just the splash screen
76994
77146
  if (!(self.inputLayouts.length === 1 && self.inputLayouts[0].layoutId === 0)) {
76995
- _context14.next = 6;
77147
+ _context14.next = 8;
76996
77148
  break;
76997
77149
  }
77150
+ console.debug('XLR::prepareLayouts - skipped (splash screen only)');
76998
77151
  return _context14.abrupt("return", Promise.resolve(self));
76999
- case 6:
77000
- console.debug('??? XLR.debug prepareLayouts::playback', {
77001
- layoutPlayback: layoutPlayback,
77002
- shouldParse: false
77152
+ case 8:
77153
+ console.debug('XLR::prepareLayouts', {
77154
+ currentLayoutId: (_layoutPlayback$curre = layoutPlayback.currentLayout) === null || _layoutPlayback$curre === void 0 ? void 0 : _layoutPlayback$curre.layoutId,
77155
+ currentLayoutIndex: layoutPlayback.currentLayoutIndex,
77156
+ nextLayoutId: (_layoutPlayback$nextL = layoutPlayback.nextLayout) === null || _layoutPlayback$nextL === void 0 ? void 0 : _layoutPlayback$nextL.layoutId,
77157
+ nextLayoutIndex: layoutPlayback.nextLayoutIndex
77003
77158
  });
77004
- self.currentLayoutId = (_layoutPlayback$curre = layoutPlayback.currentLayout) === null || _layoutPlayback$curre === void 0 ? void 0 : _layoutPlayback$curre.layoutId;
77159
+ self.currentLayoutId = (_layoutPlayback$curre2 = layoutPlayback.currentLayout) === null || _layoutPlayback$curre2 === void 0 ? void 0 : _layoutPlayback$curre2.layoutId;
77005
77160
  // Only reuse the existing Layout instance if it is fully healthy —
77006
77161
  // a done=true instance was removed from the DOM (e.g. an SSP slot that
77007
77162
  // had no ad), and an empty-XLF instance has no regions so it can never
77008
77163
  // advance the cycle. In either case re-prepare from scratch so we get
77009
77164
  // a fresh request (which may now have a valid ad / XLF).
77010
- if (!((_layoutPlayback$curre2 = layoutPlayback.currentLayout) !== null && _layoutPlayback$curre2 !== void 0 && _layoutPlayback$curre2.layoutNode && !layoutPlayback.currentLayout.done && layoutPlayback.currentLayout.xlfString !== '')) {
77011
- _context14.next = 12;
77165
+ if (!((_layoutPlayback$curre3 = layoutPlayback.currentLayout) !== null && _layoutPlayback$curre3 !== void 0 && _layoutPlayback$curre3.layoutNode && !layoutPlayback.currentLayout.done && layoutPlayback.currentLayout.xlfString !== '')) {
77166
+ _context14.next = 14;
77012
77167
  break;
77013
77168
  }
77014
77169
  _context14.t0 = layoutPlayback.currentLayout;
77015
- _context14.next = 15;
77170
+ _context14.next = 17;
77016
77171
  break;
77017
- case 12:
77018
- _context14.next = 14;
77019
- return self.prepareLayoutXlf(layoutPlayback.currentLayout);
77020
77172
  case 14:
77173
+ _context14.next = 16;
77174
+ return self.prepareLayoutXlf(layoutPlayback.currentLayout);
77175
+ case 16:
77021
77176
  _context14.t0 = _context14.sent;
77022
- case 15:
77177
+ case 17:
77023
77178
  currentLayoutXlf = _context14.t0;
77024
77179
  // True when the same object was returned (reused); false when a fresh
77025
77180
  // Layout was constructed by prepareLayoutXlf above.
77026
77181
  wasCurrentReused = currentLayoutXlf === layoutPlayback.currentLayout;
77027
- _context14.next = 19;
77182
+ _context14.next = 21;
77028
77183
  return self.prepareLayoutXlf(layoutPlayback.nextLayout);
77029
- case 19:
77184
+ case 21:
77030
77185
  nextLayoutXlf = _context14.sent;
77031
77186
  _context14.t1 = Promise;
77032
77187
  _context14.t2 = currentLayoutXlf;
77033
- _context14.next = 24;
77188
+ _context14.next = 26;
77034
77189
  return self.prepareForSsp(nextLayoutXlf);
77035
- case 24:
77190
+ case 26:
77036
77191
  _context14.t3 = _context14.sent;
77037
77192
  _context14.t4 = [_context14.t2, _context14.t3];
77038
- _context14.next = 28;
77193
+ _context14.next = 30;
77039
77194
  return _context14.t1.all.call(_context14.t1, _context14.t4);
77040
- case 28:
77195
+ case 30:
77041
77196
  layouts = _context14.sent;
77042
77197
  if (!(self.isUpdatingLoop || layouts[0].done)) {
77043
- _context14.next = 33;
77198
+ _context14.next = 36;
77044
77199
  break;
77045
77200
  }
77201
+ console.debug('XLR::prepareLayouts - aborted (concurrent updateLoop)', {
77202
+ isUpdatingLoop: self.isUpdatingLoop,
77203
+ currentLayoutDone: layouts[0].done
77204
+ });
77046
77205
  // If currentLayout was freshly prepared (not reused from nextLayout),
77047
77206
  // its DOM element was just appended — discard it now so it does not
77048
77207
  // accumulate in screen_container. Also disposes any video.js players
@@ -77054,8 +77213,14 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
77054
77213
  nextLayoutXlf.discardLayout(exports.LayoutPlaybackType.NEXT);
77055
77214
  }
77056
77215
  return _context14.abrupt("return", Promise.resolve(self));
77057
- case 33:
77058
- console.debug('>>>>> XLR.debug prepared layout XLF', layouts);
77216
+ case 36:
77217
+ console.debug('XLR::prepareLayouts - layouts prepared', {
77218
+ currentLayoutId: (_layouts$ = layouts[0]) === null || _layouts$ === void 0 ? void 0 : _layouts$.layoutId,
77219
+ currentLayoutIndex: (_layouts$2 = layouts[0]) === null || _layouts$2 === void 0 ? void 0 : _layouts$2.index,
77220
+ nextLayoutId: (_layouts$3 = layouts[1]) === null || _layouts$3 === void 0 ? void 0 : _layouts$3.layoutId,
77221
+ nextLayoutIndex: (_layouts$4 = layouts[1]) === null || _layouts$4 === void 0 ? void 0 : _layouts$4.index,
77222
+ currentReused: wasCurrentReused
77223
+ });
77059
77224
  return _context14.abrupt("return", new Promise( /*#__PURE__*/function () {
77060
77225
  var _ref14 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee13(resolve) {
77061
77226
  return _regeneratorRuntime().wrap(function _callee13$(_context13) {
@@ -77089,7 +77254,7 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
77089
77254
  return _ref14.apply(this, arguments);
77090
77255
  };
77091
77256
  }()));
77092
- case 35:
77257
+ case 38:
77093
77258
  case "end":
77094
77259
  return _context14.stop();
77095
77260
  }
@@ -77252,33 +77417,48 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
77252
77417
  return _ref16.apply(this, arguments);
77253
77418
  };
77254
77419
  }();
77420
+ // Shared re-entry guard for all layout navigation methods.
77421
+ // Prevents a double-tap from advancing two layouts at once.
77422
+ var isNavigatingLayout = false;
77255
77423
  xlrObject.gotoPrevLayout = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee18() {
77256
77424
  var _this4 = this;
77257
- var _currentLayoutIndex, _assumedPrevIndex, _this$currentLayout6;
77425
+ var _currentLayoutIndex, _assumedPrevIndex, _this$currentLayout7;
77258
77426
  return _regeneratorRuntime().wrap(function _callee18$(_context18) {
77259
77427
  while (1) switch (_context18.prev = _context18.next) {
77260
77428
  case 0:
77429
+ if (!isNavigatingLayout) {
77430
+ _context18.next = 2;
77431
+ break;
77432
+ }
77433
+ return _context18.abrupt("return");
77434
+ case 2:
77435
+ isNavigatingLayout = true;
77436
+ _context18.prev = 3;
77261
77437
  _currentLayoutIndex = this.currentLayoutIndex;
77262
77438
  _assumedPrevIndex = _currentLayoutIndex - 1; // If previous layout is same as current layout or
77263
77439
  // if there's only one layout, do nothing
77264
77440
  if (!(_assumedPrevIndex < 0)) {
77265
- _context18.next = 4;
77441
+ _context18.next = 8;
77266
77442
  break;
77267
77443
  }
77268
77444
  return _context18.abrupt("return");
77269
- case 4:
77445
+ case 8:
77270
77446
  console.debug('XLR::gotoPrevLayout', {
77271
- previousLayoutIndex: _assumedPrevIndex,
77272
- method: 'XLR::gotoPrevLayout',
77273
- shouldParse: false
77447
+ previousLayoutIndex: _assumedPrevIndex
77274
77448
  });
77275
77449
  if (!Boolean(this.inputLayouts[_assumedPrevIndex])) {
77276
- _context18.next = 10;
77450
+ _context18.next = 15;
77277
77451
  break;
77278
77452
  }
77279
- _context18.next = 8;
77280
- return (_this$currentLayout6 = this.currentLayout) === null || _this$currentLayout6 === void 0 ? void 0 : _this$currentLayout6.finishAllRegions();
77281
- case 8:
77453
+ // Prevent the natural layout-end handler from also calling
77454
+ // prepareLayouts() when finishAllRegions() causes the layout
77455
+ // 'end' event to fire.
77456
+ if (this.currentLayout) {
77457
+ this.currentLayout.inLoop = false;
77458
+ }
77459
+ _context18.next = 13;
77460
+ return (_this$currentLayout7 = this.currentLayout) === null || _this$currentLayout7 === void 0 ? void 0 : _this$currentLayout7.finishAllRegions();
77461
+ case 13:
77282
77462
  // and set the previous layout as current layout
77283
77463
  this.currentLayoutIndex = _assumedPrevIndex;
77284
77464
  this.prepareLayouts().then( /*#__PURE__*/function () {
@@ -77298,30 +77478,366 @@ function XiboLayoutRenderer(inputLayouts, overlays, options) {
77298
77478
  return _ref18.apply(this, arguments);
77299
77479
  };
77300
77480
  }());
77301
- case 10:
77481
+ case 15:
77482
+ _context18.prev = 15;
77483
+ isNavigatingLayout = false;
77484
+ return _context18.finish(15);
77485
+ case 18:
77302
77486
  case "end":
77303
77487
  return _context18.stop();
77304
77488
  }
77305
- }, _callee18, this);
77489
+ }, _callee18, this, [[3,, 15, 18]]);
77306
77490
  }));
77307
- xlrObject.gotoNextLayout = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee19() {
77308
- var _xlrObject$currentLay2;
77309
- return _regeneratorRuntime().wrap(function _callee19$(_context19) {
77310
- while (1) switch (_context19.prev = _context19.next) {
77491
+ xlrObject.gotoNextLayout = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee20() {
77492
+ var _this5 = this;
77493
+ var _this$currentLayout8, nextIndex;
77494
+ return _regeneratorRuntime().wrap(function _callee20$(_context20) {
77495
+ while (1) switch (_context20.prev = _context20.next) {
77311
77496
  case 0:
77497
+ if (!isNavigatingLayout) {
77498
+ _context20.next = 2;
77499
+ break;
77500
+ }
77501
+ return _context20.abrupt("return");
77502
+ case 2:
77503
+ isNavigatingLayout = true;
77504
+ _context20.prev = 3;
77505
+ nextIndex = this.currentLayoutIndex + 1;
77506
+ if (Boolean(this.inputLayouts[nextIndex])) {
77507
+ _context20.next = 7;
77508
+ break;
77509
+ }
77510
+ return _context20.abrupt("return");
77511
+ case 7:
77312
77512
  console.debug('XLR::gotoNextLayout', {
77313
- nextLayoutIndex: this.currentLayoutIndex + 1,
77314
- method: 'XLR::gotoNextLayout',
77315
- shouldParse: false
77513
+ nextLayoutIndex: nextIndex
77316
77514
  });
77317
- _context19.next = 3;
77318
- return (_xlrObject$currentLay2 = xlrObject.currentLayout) === null || _xlrObject$currentLay2 === void 0 ? void 0 : _xlrObject$currentLay2.finishAllRegions();
77319
- case 3:
77515
+ if (this.currentLayout) {
77516
+ this.currentLayout.inLoop = false;
77517
+ }
77518
+ _context20.next = 11;
77519
+ return (_this$currentLayout8 = this.currentLayout) === null || _this$currentLayout8 === void 0 ? void 0 : _this$currentLayout8.finishAllRegions();
77520
+ case 11:
77521
+ this.currentLayoutIndex = nextIndex;
77522
+ this.prepareLayouts().then( /*#__PURE__*/function () {
77523
+ var _ref20 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee19(xlr) {
77524
+ return _regeneratorRuntime().wrap(function _callee19$(_context19) {
77525
+ while (1) switch (_context19.prev = _context19.next) {
77526
+ case 0:
77527
+ _context19.next = 2;
77528
+ return _this5.playSchedules(xlr);
77529
+ case 2:
77530
+ case "end":
77531
+ return _context19.stop();
77532
+ }
77533
+ }, _callee19);
77534
+ }));
77535
+ return function (_x14) {
77536
+ return _ref20.apply(this, arguments);
77537
+ };
77538
+ }());
77539
+ case 13:
77540
+ _context20.prev = 13;
77541
+ isNavigatingLayout = false;
77542
+ return _context20.finish(13);
77543
+ case 16:
77320
77544
  case "end":
77321
- return _context19.stop();
77545
+ return _context20.stop();
77322
77546
  }
77323
- }, _callee19, this);
77547
+ }, _callee20, this, [[3,, 13, 16]]);
77324
77548
  }));
77549
+ xlrObject.gotoLayoutByCode = /*#__PURE__*/function () {
77550
+ var _ref21 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee22(layoutCode) {
77551
+ var _this6 = this;
77552
+ var _this$currentLayout9, targetIndex, parsedLayouts, _loop, _ret, _i, _parsedLayouts, parser, i, _inputLayout$getXlf, _doc$documentElement, inputLayout, xlfString, url, res, doc, foundCode;
77553
+ return _regeneratorRuntime().wrap(function _callee22$(_context23) {
77554
+ while (1) switch (_context23.prev = _context23.next) {
77555
+ case 0:
77556
+ if (!isNavigatingLayout) {
77557
+ _context23.next = 2;
77558
+ break;
77559
+ }
77560
+ return _context23.abrupt("return");
77561
+ case 2:
77562
+ isNavigatingLayout = true;
77563
+ _context23.prev = 3;
77564
+ targetIndex = -1; // 1. Check the two already-parsed layouts first (zero fetch cost)
77565
+ parsedLayouts = [this.layouts['current'], this.layouts['next']];
77566
+ _loop = /*#__PURE__*/_regeneratorRuntime().mark(function _loop() {
77567
+ var _layout$layoutNode;
77568
+ var layout, code;
77569
+ return _regeneratorRuntime().wrap(function _loop$(_context21) {
77570
+ while (1) switch (_context21.prev = _context21.next) {
77571
+ case 0:
77572
+ layout = _parsedLayouts[_i];
77573
+ if (layout) {
77574
+ _context21.next = 3;
77575
+ break;
77576
+ }
77577
+ return _context21.abrupt("return", 0);
77578
+ case 3:
77579
+ code = (_layout$layoutNode = layout.layoutNode) === null || _layout$layoutNode === void 0 || (_layout$layoutNode = _layout$layoutNode.documentElement) === null || _layout$layoutNode === void 0 ? void 0 : _layout$layoutNode.getAttribute('code');
77580
+ if (!(code === layoutCode)) {
77581
+ _context21.next = 7;
77582
+ break;
77583
+ }
77584
+ targetIndex = _this6.inputLayouts.findIndex(function (i) {
77585
+ return i.layoutId === layout.layoutId;
77586
+ });
77587
+ return _context21.abrupt("return", 1);
77588
+ case 7:
77589
+ case "end":
77590
+ return _context21.stop();
77591
+ }
77592
+ }, _loop);
77593
+ });
77594
+ _i = 0, _parsedLayouts = parsedLayouts;
77595
+ case 8:
77596
+ if (!(_i < _parsedLayouts.length)) {
77597
+ _context23.next = 18;
77598
+ break;
77599
+ }
77600
+ return _context23.delegateYield(_loop(), "t0", 10);
77601
+ case 10:
77602
+ _ret = _context23.t0;
77603
+ if (!(_ret === 0)) {
77604
+ _context23.next = 13;
77605
+ break;
77606
+ }
77607
+ return _context23.abrupt("continue", 15);
77608
+ case 13:
77609
+ if (!(_ret === 1)) {
77610
+ _context23.next = 15;
77611
+ break;
77612
+ }
77613
+ return _context23.abrupt("break", 18);
77614
+ case 15:
77615
+ _i++;
77616
+ _context23.next = 8;
77617
+ break;
77618
+ case 18:
77619
+ if (!(targetIndex === -1)) {
77620
+ _context23.next = 60;
77621
+ break;
77622
+ }
77623
+ parser = new DOMParser();
77624
+ i = 0;
77625
+ case 21:
77626
+ if (!(i < this.inputLayouts.length)) {
77627
+ _context23.next = 60;
77628
+ break;
77629
+ }
77630
+ inputLayout = this.inputLayouts[i]; // Fast check: code pre-populated by the player (no fetch needed)
77631
+ if (!(inputLayout.code !== undefined)) {
77632
+ _context23.next = 28;
77633
+ break;
77634
+ }
77635
+ if (!(inputLayout.code === layoutCode)) {
77636
+ _context23.next = 27;
77637
+ break;
77638
+ }
77639
+ targetIndex = i;
77640
+ return _context23.abrupt("break", 60);
77641
+ case 27:
77642
+ return _context23.abrupt("continue", 57);
77643
+ case 28:
77644
+ xlfString = void 0; // Prefer getXlf() when available (e.g. CMS platform)
77645
+ xlfString = (_inputLayout$getXlf = inputLayout.getXlf) === null || _inputLayout$getXlf === void 0 ? void 0 : _inputLayout$getXlf.call(inputLayout);
77646
+ // Otherwise fetch from the local file server (Electron / ChromeOS)
77647
+ if (!(!xlfString && this.config.appHost && inputLayout.path)) {
77648
+ _context23.next = 49;
77649
+ break;
77650
+ }
77651
+ url = this.config.appHost + inputLayout.path;
77652
+ console.debug('[gotoLayoutByCode] Fetching XLF for layoutId', inputLayout.layoutId, url);
77653
+ _context23.prev = 33;
77654
+ _context23.next = 36;
77655
+ return fetch(url);
77656
+ case 36:
77657
+ res = _context23.sent;
77658
+ if (res.ok) {
77659
+ _context23.next = 40;
77660
+ break;
77661
+ }
77662
+ console.debug('[gotoLayoutByCode] Fetch non-OK', res.status, url);
77663
+ return _context23.abrupt("continue", 57);
77664
+ case 40:
77665
+ _context23.next = 42;
77666
+ return res.text();
77667
+ case 42:
77668
+ xlfString = _context23.sent;
77669
+ _context23.next = 49;
77670
+ break;
77671
+ case 45:
77672
+ _context23.prev = 45;
77673
+ _context23.t1 = _context23["catch"](33);
77674
+ console.debug('[gotoLayoutByCode] Fetch error for', url, _context23.t1);
77675
+ return _context23.abrupt("continue", 57);
77676
+ case 49:
77677
+ if (xlfString) {
77678
+ _context23.next = 52;
77679
+ break;
77680
+ }
77681
+ console.debug('[gotoLayoutByCode] No XLF for layoutId', inputLayout.layoutId, 'path:', inputLayout.path);
77682
+ return _context23.abrupt("continue", 57);
77683
+ case 52:
77684
+ doc = parser.parseFromString(xlfString, 'text/xml');
77685
+ foundCode = (_doc$documentElement = doc.documentElement) === null || _doc$documentElement === void 0 ? void 0 : _doc$documentElement.getAttribute('code');
77686
+ if (!(foundCode === layoutCode)) {
77687
+ _context23.next = 57;
77688
+ break;
77689
+ }
77690
+ targetIndex = i;
77691
+ return _context23.abrupt("break", 60);
77692
+ case 57:
77693
+ i++;
77694
+ _context23.next = 21;
77695
+ break;
77696
+ case 60:
77697
+ if (!(targetIndex === -1)) {
77698
+ _context23.next = 63;
77699
+ break;
77700
+ }
77701
+ console.warn('XLR::gotoLayoutByCode - layout not found for code:', layoutCode);
77702
+ return _context23.abrupt("return");
77703
+ case 63:
77704
+ console.debug('XLR::gotoLayoutByCode', {
77705
+ layoutCode: layoutCode,
77706
+ targetIndex: targetIndex
77707
+ });
77708
+ // Prevent the natural layout-end handler from racing with our own
77709
+ // prepareLayouts() call (same pattern as gotoPrevLayout/gotoNextLayout).
77710
+ if (this.currentLayout) {
77711
+ this.currentLayout.inLoop = false;
77712
+ }
77713
+ _context23.next = 67;
77714
+ return (_this$currentLayout9 = this.currentLayout) === null || _this$currentLayout9 === void 0 ? void 0 : _this$currentLayout9.finishAllRegions();
77715
+ case 67:
77716
+ this.currentLayoutIndex = targetIndex;
77717
+ this.prepareLayouts().then( /*#__PURE__*/function () {
77718
+ var _ref22 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee21(xlr) {
77719
+ return _regeneratorRuntime().wrap(function _callee21$(_context22) {
77720
+ while (1) switch (_context22.prev = _context22.next) {
77721
+ case 0:
77722
+ _context22.next = 2;
77723
+ return _this6.playSchedules(xlr);
77724
+ case 2:
77725
+ case "end":
77726
+ return _context22.stop();
77727
+ }
77728
+ }, _callee21);
77729
+ }));
77730
+ return function (_x16) {
77731
+ return _ref22.apply(this, arguments);
77732
+ };
77733
+ }());
77734
+ case 69:
77735
+ _context23.prev = 69;
77736
+ isNavigatingLayout = false;
77737
+ return _context23.finish(69);
77738
+ case 72:
77739
+ case "end":
77740
+ return _context23.stop();
77741
+ }
77742
+ }, _callee22, this, [[3,, 69, 72], [33, 45]]);
77743
+ }));
77744
+ return function (_x15) {
77745
+ return _ref21.apply(this, arguments);
77746
+ };
77747
+ }();
77748
+ xlrObject.playInterruptLayout = /*#__PURE__*/function () {
77749
+ var _ref23 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee23(inputLayout) {
77750
+ var _this7 = this;
77751
+ var _this$currentLayout10, _this$currentLayout11, resumeIndex, savedNextLayout, interruptKey, wasInUniqueLayouts, interruptILayout, cleanup;
77752
+ return _regeneratorRuntime().wrap(function _callee23$(_context24) {
77753
+ while (1) switch (_context24.prev = _context24.next) {
77754
+ case 0:
77755
+ if (!isNavigatingLayout) {
77756
+ _context24.next = 2;
77757
+ break;
77758
+ }
77759
+ return _context24.abrupt("return");
77760
+ case 2:
77761
+ isNavigatingLayout = true;
77762
+ _context24.prev = 3;
77763
+ resumeIndex = this.currentLayoutIndex; // Save B (the layout that was queued to play after A) before stopping A.
77764
+ // After the interrupt ends, parseLayouts() will use this to resume the loop.
77765
+ savedNextLayout = this.nextLayout;
77766
+ console.debug('[navLayout] XLR::playInterruptLayout - Starting interrupt', {
77767
+ interruptLayoutId: inputLayout.layoutId,
77768
+ resumeIndex: resumeIndex,
77769
+ currentLayoutId: (_this$currentLayout10 = this.currentLayout) === null || _this$currentLayout10 === void 0 ? void 0 : _this$currentLayout10.layoutId,
77770
+ resumeNextLayoutId: savedNextLayout === null || savedNextLayout === void 0 ? void 0 : savedNextLayout.layoutId
77771
+ });
77772
+ // Prevent A's end handler from calling prepareLayouts (we take over).
77773
+ if (this.currentLayout) {
77774
+ this.currentLayout.inLoop = false;
77775
+ }
77776
+ _context24.next = 10;
77777
+ return (_this$currentLayout11 = this.currentLayout) === null || _this$currentLayout11 === void 0 ? void 0 : _this$currentLayout11.finishAllRegions();
77778
+ case 10:
77779
+ // Register interrupt in uniqueLayouts so getLayout()/prepareLayoutXlf() resolve it.
77780
+ // Do NOT splice into inputLayouts — keeping the original loop intact means
77781
+ // parseLayouts() will see the interrupt as "not in loop" (isCurrentLayoutValid=false)
77782
+ // after it ends, and will correctly advance to savedNextLayout (B).
77783
+ interruptKey = String(inputLayout.layoutId);
77784
+ wasInUniqueLayouts = this.uniqueLayouts.has(interruptKey);
77785
+ if (!wasInUniqueLayouts) {
77786
+ this.uniqueLayouts.set(interruptKey, _objectSpread2(_objectSpread2({}, inputLayout), {}, {
77787
+ index: resumeIndex,
77788
+ id: inputLayout.layoutId
77789
+ }));
77790
+ }
77791
+ // Prepare the interrupt ILayout (fetches XLF, builds regions).
77792
+ _context24.next = 15;
77793
+ return this.prepareLayoutXlf(this.getLayout(inputLayout));
77794
+ case 15:
77795
+ interruptILayout = _context24.sent;
77796
+ // Wire into XLR so playLayouts picks up the interrupt as current.
77797
+ // inLoop=true lets the interrupt's own end handler call prepareLayouts normally.
77798
+ interruptILayout.inLoop = true;
77799
+ this.layouts.current = interruptILayout;
77800
+ this.currentLayout = interruptILayout;
77801
+ this.currentLayoutId = interruptILayout.layoutId;
77802
+ // Restore nextLayout to B so after the interrupt ends, parseLayouts() resumes
77803
+ // the original loop from B (since interrupt.layoutId is not in inputLayouts,
77804
+ // parseLayouts sees it as invalid and advances to nextLayout).
77805
+ if (savedNextLayout) {
77806
+ this.layouts.next = savedNextLayout;
77807
+ this.nextLayout = savedNextLayout;
77808
+ }
77809
+ // Remove interrupt from uniqueLayouts once it ends.
77810
+ cleanup = this.emitter.on('layoutEnd', function (endedLayout) {
77811
+ if (endedLayout !== interruptILayout) return;
77812
+ cleanup();
77813
+ if (!wasInUniqueLayouts) {
77814
+ _this7.uniqueLayouts["delete"](interruptKey);
77815
+ }
77816
+ console.debug('[navLayout] XLR::playInterruptLayout - Interrupt ended, resuming loop', {
77817
+ interruptLayoutId: inputLayout.layoutId,
77818
+ resumeNextLayoutId: savedNextLayout === null || savedNextLayout === void 0 ? void 0 : savedNextLayout.layoutId
77819
+ });
77820
+ });
77821
+ _context24.next = 24;
77822
+ return this.playSchedules(xlrObject);
77823
+ case 24:
77824
+ _context24.prev = 24;
77825
+ isNavigatingLayout = false;
77826
+ return _context24.finish(24);
77827
+ case 27:
77828
+ case "end":
77829
+ return _context24.stop();
77830
+ }
77831
+ }, _callee23, this, [[3,, 24, 27]]);
77832
+ }));
77833
+ return function (_x17) {
77834
+ return _ref23.apply(this, arguments);
77835
+ };
77836
+ }();
77837
+ xlrObject.triggerAction = function (triggerCode, widgetId) {
77838
+ var _this$currentLayout12;
77839
+ (_this$currentLayout12 = this.currentLayout) === null || _this$currentLayout12 === void 0 || (_this$currentLayout12 = _this$currentLayout12.actionController) === null || _this$currentLayout12 === void 0 || _this$currentLayout12.handleWebhookTrigger(triggerCode, widgetId);
77840
+ };
77325
77841
  xlrObject.updateInputLayout = function (layoutIndex, layout) {
77326
77842
  var xlrInputLayout = this.inputLayouts[layoutIndex];
77327
77843
  if (layout !== null) {