(function() {
/**
* @typedef {Object} Help4.widget.tour.Observer.Status
* @property {?string} [id]
* @property {?boolean} [visible]
*/
/**
* @typedef {Object} Help4.widget.tour.Observer.ElementEvent
* @property {MouseEvent|KeyboardEvent|FocusEvent|Object} event
* @property {string} [id]
* @property {Object} [params]
* @property {Object} params.value
* @property {*} params.value.old
* @property {*} params.value.cur
*/
/**
* Element event observation for tour playback
* @augments Help4.jscore.Base
* @property {Help4.widget.tour.View} _view
* @property {Object} _observed
* @property {Function} _onElementEvent
* @property {boolean} _blocked
*/
Help4.widget.tour.Observer = class extends Help4.jscore.Base {
/**
* @override
* @param {Help4.widget.tour.View} view
*/
constructor(view) {
super({
statics: {
_view: {init: view, destroy: false},
_observed: {init: {}, destroy: false}, /** {@link Help4.widget.tour.Observer.Status} */
_onElementEvent: {init: event => this.onElementEvent(event), destroy: false},
_blocked: {init: false, destroy: false}
}
});
_startStop.call(this, 'start');
}
/** destroy instance */
destroy() {
_startStop.call(this, 'stop');
this.disconnect();
super.destroy();
}
/**
* see {@link Help4.engine.hotspotManager.HotspotManagerEngine.prototype.observe}
* @param {Help4.data.TileData} tileData
* @returns {Help4.widget.tour.Observer}
*/
observe(tileData) {
const {/** @type {Help4.widget.tour.View} */ _view} = this;
const {/** @type {Help4.service.recording.PlaybackService} */ playbackService} = _view.getContext().service;
const {/** @type {Help4.widget.tour.Observer.Status} */ _observed} = this;
const {status} = tileData.hotspot;
const {/** @type {boolean} */ visible} = status;
const {
/** @type {string} */ id,
/** @type {Help4.data.HotspotData} */ hotspot
} = tileData;
if (_observed.id !== id) { // not yet observed
// disconnect previous observation
this.disconnect();
// save status
_observed.id = id;
_observed.visible = visible;
// only start observation in case new element is visible
visible && playbackService.observe(id, hotspot);
} else if (_observed.visible !== visible) { // update same observation
// already observed; but visibility has changed
(_observed.visible = visible)
? playbackService.observe(id, hotspot)
: playbackService.disconnect(id);
}
return this;
}
/**
* stop observation
* @returns {Help4.widget.tour.Observer}
*/
disconnect() {
const {
/** @type {Help4.widget.tour.View} */ _view,
/** @type {Help4.widget.tour.Observer.Status} */ _observed
} = this;
const {/** @type {Help4.service.recording.PlaybackService} */ playbackService} = _view.getContext().service;
_observed.id && playbackService.disconnect(_observed.id);
delete _observed.id;
delete _observed.visible;
return this;
}
/** @param {Help4.widget.tour.Observer.ElementEvent} event */
onElementEvent(event) {
const {/** @type {Help4.widget.tour.View} */ _view} = this;
let {type} = event.event;
const {params: {value = null} = {}} = event;
if (type === 'keyup' && value && value.old === value.cur) {
// only accept keys in case they change the input field value
type = null;
}
const {/** @type {string[]} */ autoProgress} = /** @type {?Help4.widget.help.ProjectTile} */ _view.getCurrentTile();
// XRAY-5411: some UI5 controls block click events from reaching CMP.
// added mouseup as an alternative for click event
if (Help4.includes(autoProgress, 'click')) autoProgress.push('mouseup');
if (!Help4.includes(autoProgress, type)) {
// XRAY-1903
if (!Help4.Platform.iPad ||
type !== 'click' ||
!Help4.includes(autoProgress, 'mouseover'))
{
return;
}
}
if (!this._blocked) {
// XRAY-5422: make sure not to handle this very event again
this._blocked = true;
// XRAY-5373: allow screen to update itself before navigating to next step
setTimeout(async () => {
this._blocked = false;
// XRAY-6392: rely on navigation to progress to next step, only call if next step is on the same screen
if (_view.isNextStepSameScreen()) {
await _view.nextStep(true);
}
}, Help4.widget.tour.Widget.NAVIGATE_WAIT_TIME);
}
}
}
/**
* @memberof Help4.widget.tour.Observer#
* @private
* @param {'start'|'stop'} mode
*/
function _startStop(mode) {
const {_onElementEvent, _view} = this;
const {
engine: {
/** @type {Help4.engine.crossorigin.CoreEngine} */ crossOriginEngine: {onElementEvent: coe}
},
service: {
/** @type {Help4.service.recording.PlaybackService} */ playbackService: {onElementEvent: ps},
/** @type {Help4.service.CrossOriginMessageService} */ crossOriginService: {onElementEvent: cos}
}
} = _view.getContext();
const fun = mode === 'start' ? 'addListener' : 'removeListener';
ps[fun](_onElementEvent);
coe[fun](_onElementEvent);
cos[fun](_onElementEvent);
}
})();