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