(function() {
/**
* @typedef {Help4.control2.bubble.content.BubbleContent.Params} Help4.control2.bubble.content.Html.Params
* @property {string} [content = ''] - the HTML content
*/
/**
* Control to show HTML content.
* @augments Help4.control2.bubble.content.BubbleContent
* @property {string} content - the HTML content
*/
Help4.control2.bubble.content.Html = class extends Help4.control2.bubble.content.BubbleContent {
/**
* @override
* @param {Help4.control2.bubble.content.Html.Params} [params]
*/
constructor(params) {
const {
TYPES: T,
TEXT_TYPES: TT
} = Help4.jscore.ControlBase;
super(params, {
params: {
tag: {init: 'article'},
// all defaults are handled by bubble; do not handle here!
// keep in sync with bubble!
content: {type: T.string}
},
config: {
css: 'control-bubble-content-html'
},
texts: {
content: TT.innerHTML
}
});
}
/**
* @override
* @param {Object} event - the received event
*/
onEvent(event) {
if (event.type === 'click' || event.type === 'touchend') {
_handleLinkClick.call(this, event);
this._fireEvent({type: 'click', data: event});
} else {
super.onEvent(event);
}
}
/**
* @override
* @param {Help4.jscore.ControlBase.PropertyChangeEvent} event - the change event
*/
_applyPropertyToDom({name, value, oldValue}) {
if (name === 'content') {
const dom = this.getDom();
dom.innerHTML = value; // XXX: security?
this._applyTextAttribute(dom, 'content', !!value);
} else {
super._applyPropertyToDom({name, value, oldValue});
}
}
}
/**
* @memberof Help4.control2.bubble.content.Html#
* @param {Object} event
* @returns {?boolean}
* @private
*/
function _handleLinkClick(event) {
// XRAY-1883: removed all "javascript:" links because of CSP
// see Help4.control.input.HtmlEditor.transformForPlayback
// XRAY-2019: clicked item might be inside of link
// e.g. <a><span>text</span></a>
const target = event.target.closest('A');
const {cmd, docuLink} = target?.dataset || {};
// XRAY-4837: special handling for DOCU_LINK
// docuLink needs to be sent with actual href/cmd to show link underline, ignore cmd in this case
if (docuLink) {
const {__bubble} = this;
const controller = __bubble && Help4.getController();
const urEngine = controller?.getEngine('urHarmonization');
// when ML translations are enabled - content language res_langu EN > language en-US conversion?
// until then res_langu is not used
const {content, short_text/*, res_langu*/} = urEngine?.getDocuLinkContent(docuLink) || {};
if (content) {
// update bubble texts
const newTexts = {};
const {HtmlEditor} = Help4.control.input;
for (const tid in __bubble.getTexts(true)) {
if (tid.endsWith('caption')) {
// 1 - short_text from backend, not available for glossary links
// 2 - innerText, some link texts are not capitalized, either solve here or wait for query to be extended to also return the caption/label
// capitalize first letter of each word (non-whitespace following whitespace/start)
// 3 - command, DOCU_LINK id as fallback
newTexts[tid] = short_text || target.innerText.replace(/(^|\s)\S/g, c => c.toUpperCase()) || docuLink;
} else if (tid.endsWith('content')) {
newTexts[tid] = HtmlEditor.transformForPlayback({text: content, controller});
}
}
__bubble.setTexts(newTexts);
// re-align bubble
let connectionPoints;
let params;
const tileId = __bubble.getMetadata('tileId');
const handler = controller.getHandler();
if (tileId && handler) { // CMP3
// cache not always available, get connectionPoints from hotspot
const hotspots = handler.getHotspots();
const hotspot = hotspots.get({byMetadata: {tileId}});
connectionPoints = hotspot?.getConnectionPoints({useMidPoint: true});
} else { // CMP4
// re-use previously cached values
const {conditions} = __bubble.__alignmentCache || {};
connectionPoints = conditions?.connectionPoints;
params = {ignoreArea: true, orientation: conditions?.orientation || 'auto'};
}
__bubble.align(connectionPoints, params);
}
return Help4.Event.cancel(event); // suppress link execution
}
let command = cmd;
if (command && (command = command.match(/^Help4\.CtxWPB\.show\((.*?)\)$/)) && command.length > 1) {
command = command[1].split(/\,\s?(?![^\(]*\))/); // split by commas, ignore text between the parentheses
const data = {};
for (const key of ['id', 'url', 'win']) {
data[key] = command.shift().trim().replace(/^["']|["']$/g, '');
}
// XRAY-4259: by default the free links in bubble should be opened in new window (ignore newWindow setting)
data.win = true;
command = command.join().replace(/^["']|["']$/g, '').trim();
data.params = command && command !== 'null' ? command : null;
setTimeout(() => {
Help4.WM.trackExternalLink(data);
Help4.CtxWPB.show(data.id, data.url, data.win, data.params)
}, 1);
return Help4.Event.cancel(event); // suppress link execution
}
}
})();