(function() {
/** Mock handling for UR harmonization */
Help4.engine.ur.Mock = class {
static MOCK_FRAME_ID = 'help4-ur-mock';
static MOCK_ELEMENTS = /** @type {Help4.engine.ur.UrHarmonizationEngine.UrElement[]} */ [];
static MOCK_ELEMENTS_V2 = /** @type {Help4.engine.ur.UrHarmonizationEngine.UrHotspot[]} */ [];
static MOCK_TEXTS = /** @type Help4.engine.ur.UrHarmonizationEngine.UrTextResponse[] */ [{
label_text: 'UR MOCK: No Long Text',
long_text: '',
short_text: 'I have no long text',
res_langu: 'EN'
}, {
label_text: 'UR MOCK: User',
long_text: '<HTML> <HEAD> <META http-equiv="Content-Type" content="text/html; charset=utf-16le"> <TITLE>CDUSERNAME</TITLE> </HEAD> <BODY> <H3>Definition</H3> <P>USER name for which change documents should be displayed.</P> </BODY> </HTML>',
short_text: 'Demo content 1',
res_langu: 'EN'
}, {
label_text: 'UR MOCK: No Long Text',
long_text: '',
short_text: 'I have no long text',
res_langu: 'EN'
}, {
label_text: 'LIMITED_FORMAT_KATJA', // this format includes docu links and icons as svgs with icon ids
short_text: 'LIMITED_FORMAT_KATJA',
res_langu: 'EN',
long_text: `
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=utf-16le">
<TITLE>ZTEST_JENS_NEU</TITLE>
</HEAD>
<BODY>
<h1>H1 title</h1>
<h2>H2 title</h2>
<h3>H3 title</h3>
<h4>H4 title</h4>
<h5>H5 title</h5>
<h6>H6 title</h6>
<p></p>
<h2>Formats</h2>
<P>P - paragraph</P>
<P>P with BR<BR>New Line?</P>
<P>Now we will see a pretty long text which will have plenty of inline formatting and extends over a couple of lines,
for example let us start with <B>B - bold</B>, which should actually be bold, continuing with
<U>U - underline</U> and there shouldn't be anyhting after this: <SPAN STYLE='display:none'>⚠️ inline style hidden</SPAN>.<NOBR> NOBR </NOBR>, <PRE>PRE - no formatting</PRE>
<STRONG>STRONG - bold</STRONG><center>CENTER - ignore centering</center>
</P>
<h3>Italic</h3>
<p><samp>samp - should be span italic</samp></p>
<p><I>I - italic</I></p>
<p><B><I>I in B - bold italic</I></B>, <EM>EM - italic</EM></p>
<h3>Monospace</h3>
<p><TT>TT (deprecated) - monospace</TT>, <code>CODE - monospace</code></p>
<P></P>
<h2>Icons</h2>
<P>Big icon 1: <svg id="M_CRIT"> </svg> - ICON_MESSAGE_CRITICAL</P>
<P>Big icon 2: <svg id="M_INFO"></svg> - ICON_MESSAGE_QUESTION</P>
<P>Wide icon 3: <svg id="S_TL_G"></svg> - ICON_traffic</P>
<P><svg id="M_INFO"></svg> - ICON_MESSAGE_QUESTION</P>
<p></p>
<h3>Normal icons</h3>
<P>Bitmap Image <svg id="X__BMP"></svg> BMP <svg id="M_CRIT"></svg> CRIT </P>
<P>Gif Image <svg id="X__GIF"></svg> GIF </P>
<P>Extended icon<svg id="S_OKAY"></svg> OKAY </P>
<P></P>
<h2>Lists</h2>
<OL>OL - should have no numbering</OL>
<OL>New OL - should have no numbering<BR>New Line</OL>
<OL>
<OL>a) OL in empty OL with just a leading a)</OL>
</OL>
<ol>
<li>OL item 1</li>
<li>OL item 2</li>
<ol>
<li>OL in OL item 1</li>
</ol>
</ol>
<UL>UL</UL>
<p></p>
<UL>
<LI>UL item 1</LI>
<LI>UL item 2</LI>
</UL>
<UL>
<UL>
<LI>UL in empty UL - item 1</LI>
</UL>
</UL>
<p></p>
<h2>Links</h2>
<h3>SAP Event docu links (XRAY-4837)</h3>
<P><A HREF="SAPEVENT:DOCU_LINK(GLOS.3526B1A2AFAB52B9E10000009B38F974)"><B>GLOS.3526B1A2AFAB52B9E10000009B38F974</B></A></P>
<P><A HREF="SAPEVENT:DOCU_LINK(TX.ZTEST_JENS)"><B>TX.ZTEST_JENS</B></A></P>
<P><A HREF="SAPEVENT:DOCU_LINK(DE.ABTEI)"><B>DE.ABTEI</B></A></P>
<P><A HREF="SAPEVENT:DOCU_LINK(GL.ABAP)"><B>GL.ABAP</B></A></P>
<P><A HREF="SAPEVENT:DOCU_LINK(GLOS.ABAP)"><B>GLOS.ABAP</B></A></P>
<P><A HREF="SAPEVENT:DOCU_LINK(SIMG.ALV_CRYSTAL)"><B>SIMG.ALV_CRYSTAL</B></A></P>
<h3>Normal links</h3>
<P>Regular link <A HREF=https://help.sap.com/http.svc/ahp2/DRAFT/SAP_S4HANA_ON-PREMISE/2023.latest/EN/49/255a2d29ac16b7e10000000a42189d/frameset.htm?profile=20000388><B>KENO</B></A></P>
<P>HTML link <A HREF=https://help.sap.com><B>SAP</B></A></P>
<P></P>
<h2>Tables</h2>
<p>should be shown as BorderTable</p>
<TABLE>
<TR> <TH ALIGN=LEFT>K1-heading1</TH> <TH ALIGN=LEFT> Heading2</TH> </TR>
<TR> <TD>T1-Column1</TD> <TD> Column2</TD> </TR>
<TR> <TD>T1-next row</TD> <TD> next row</TD> </TR>
<TR> <TD>T1-next row</TD> <TD> next row</TD> </TR>
<TR> <TH>K2-heading1</TH> <TH> heading2</TH> <TH> heading3</TH> </TR>
<TR> <TD>T2-Col1</TD> <TD> col2</TD> <TD> col3</TD> </TR>
<TR> <TH>K3-heading1</TH> <TH> heading2</TH> <TH> heading3</TH> <TH> heading4</TH> <TH> heading5</TH> </TR>
<TR> <TD>T3 col1</TD> <TD> col2</TD> <TD> col3</TD> <TD> col4</TD> <TD> col5</TD> </TR>
</TABLE>
</BODY>
</HTML>`
}];
static MOCK_DOCU_LINK_TEXTS = { // XRAY-4837 - some of these contain links to other DOCU_LINK texts; leaving some links broken, to simulate missing texts
"GLOS.3526B1A2AFAB52B9E10000009B38F974": {
"id_name": "GLOS.3526B1A2AFAB52B9E10000009B38F974",
"short_text": "",
"long_text": "<HTML> <HEAD> <META http-equiv=\"Content-Type\" content=\"text/html; charset=utf-16le\"> <TITLE>3526B1A2AFAB52B9E10000009B38F974</TITLE> </HEAD> <BODY> <H4>ABAP Runtime Environment (BC-ABA)</H4> <P><I>A</I>dvanced <I>B</I>usiness <I>A</I>pplication <I>P</I>rogramming</P> <P>The SAP programming language.</P> <P></P> </BODY> </HTML>",
"res_langu": ""
},
"TX.ZTEST_JENS": {
"id_name": "TX.ZTEST_JENS",
"short_text": "",
"long_text": "<HTML> <HEAD> <META http-equiv=\"Content-Type\" content=\"text/html; charset=utf-16le\"> <TITLE>ZTEST_JENS</TITLE> </HEAD> <BODY> <H3>Definition</H3> <P>Textblock after definition</P> <H3>Use</H3> <P>The text after the use keyblock</P> <H3>Dependencies</H3> <P>Text with dependencies</P> <H3>Example</H3> <P>Lots of wonderful examples</P> <P>Note (AM)</P> <P><STRONG>Glossary Term (GB)</STRONG></P> <P></P> <samp>Programming example (pe)</samp> <samp>Coding line 1</samp> <samp>coding line 2</samp> <samp>end coding</samp> <P>Icons</P> <P>Big icon 1: <svg id=\"M_CRIT\"></svg> - ICON_MESSAGE_CRITICAL</P> <P>Big icon 2: <svg id=\"M_INFO\"></svg> - ICON_MESSAGE_QUESTION</P> <P>Wide icon 3: <svg id=\"S_TL_G\"></svg> - ICON_traffic</P> <P><svg id=\"M_INFO\"></svg> - ICON_MESSAGE_QUESTION -> direct display</P> <P>Normal icons:</P> <P>Bitmap Image <svg id=\"X__BMP\"></svg> <svg id=\"M_CRIT\"></svg> - Bitmap Image</P> <P>Gif Imag <svg id=\"X__GIF\"></svg> - Gif Image</P> <P>Extended icon: <svg id=\"S_OKAY\"></svg>\\Qtooltip_text@</P> <P></P> <P>Standard paragraph (AS)</P> <P>Standard paragraph (*)<BR>Continue h (/)</P> <OL>1. Numbered list (N1)</OL> <OL>2. next number<BR>Follow on to number 2</OL> <OL><OL>a) Numbered list (N2)</OL></OL> <UL>Follow on line (AL)</UL> <OL><OL>b) Next number (n3)<BR>Follown on to N2</OL></OL> <OL>3. Next numbe N1</OL> <UL>Follow on line (AL)</UL> <OL>1. new list (n1)</OL> <OL>2. Nex number (n1)</OL> <UL><LI>Bullet List 1 (b1)</LI></UL> <UL><LI>Bullet List 1, second(b1)</LI></UL> <UL><UL><LI>Bullet List 2 (B2)</LI></UL></UL> <UL><UL><LI>Bullet List 2 (B2)</LI></UL></UL> <UL><LI>Bullet List 1, third (b1)</LI></UL> <P>Next line is 'include' of other texts from links:</P> <P>Link tests</P> <P>Glossary link <A HREF=\"SAPEVENT:DOCU_LINK(GLOS.3526B1A2AFAB52B9E10000009B38F974)\"><B>ABAP</B></A></P> <P>Keno link <A HREF=\"https://help.sap.com/http.svc/ahp2/DRAFT/SAP_S4HANA_ON-PREMISE/2023.latest/EN/49/255a2d29ac16b7e10000000a42189d/frameset.htm\"> <B>KENO</B></A></P> <P>System link <A HREF=\"SAPEVENT:DOCU_LINK(TX.ZTEST_JENS)\"><B>Link to other system object</B></A></P> <P>HTML link <A HREF=\"https://help.sap.com\"><B>Link to HTML </B></A></P> <P></P> <P>Tables</P> <TABLE><TR><TH ALIGN=LEFT>K1 heading1</TH><TH ALIGN=LEFT> Heading2</TH></TR> <TR><TD>T1 Column1</TD><TD> Column2</TD></TR> <TR><TD>T1 next row</TD><TD> next row</TD></TR> <TR><TD>T1 next row</TD><TD> next row</TD></TR> <TR><TH>K2 heading1</TH><TH> heading2</TH><TH> heading3</TH></TR> <TR><TD>T2 Col1</TD><TD> col2</TD><TD> col3</TD></TR> <TR><TH>K3 heading1</TH><TH> heading2</TH><TH> heading3</TH><TH> heading4</TH><TH> heading5</TH></TR> <TR><TD>T3 col1</TD><TD> col2</TD><TD> col3</TD><TD> col4</TD><TD> col5</TD></TR> </TABLE> <P>Now we will see a pretty long text which will have plenty of inline formatting and extends over a couple of lines, for example let us start with <B>highlighted</B>, which should actually be bold, or <I>italics</I>, continuing with <U>underline</U> and <SPAN STYLE='display:none'>hidden</SPAN>. <B>Glossary reference</B>, <B><I>Function Key</I></B>, <TT>ABAP Keyword</TT>, <EM>Field label and menu option</EM></P> <H3>Heading level 1 (U1)</H3> <H3>Heading level 2 (U2)</H3> <H4>Heading level 3 (U3)</H4> <H5>Heading level 4 (U4)</H5> <H5>Heading level 5 (U5)</H5> <P><STRONG>Heading UT</STRONG></P> <P><text valid for S4H on-premise></P> <P><text valid not for S4H cloud></P> <P>Links:</P> <P><A HREF=\"SAPEVENT:DOCU_LINK(DE.ABTEI)\"><B>DE ABTEI</B></A></P> <P><A HREF=\"SAPEVENT:DOCU_LINK(GL.ABAP)\"><B>GL ABAP</B></A></P> <P><A HREF=\"SAPEVENT:DOCU_LINK(GLOS.ABAP)\"><B>GLOS ABAP</B></A></P> <P><B>www.google.com</B></P> <P><A HREF=\"https://help.sap.com/http.svc/ahp2/DRAFT/SAP_S4HANA_ON-PREMISE/2023.latest/EN/d7/6c1a509bd84be4b403fea5e50cb59f/frameset.htm\"> <B>KENO 00145EF433BE02DE8BE22CB7A77F90B0</B></A></P> <P><A HREF=\"https://help.sap.com/http.svc/ahp2/DRAFT/SAP_S4HANA_ON-PREMISE/2023.latest/EN/d1/8019cd454211d189710000e8322d00/frameset.htm\"> <B>TRAN SE16</B></A></P> <P><A HREF=\"SAPEVENT:DOCU_LINK(RE.RDOCFINDER)\"><B>REPO RDOCFINDER</B></A></P> </BODY> </HTML>",
"res_langu": "EN"
}, "DE.ABTEI": {
"id_name": "DE.ABTEI",
"short_text": "Department",
"long_text": "<HTML> <HEAD> <META http-equiv=\"Content-Type\" content=\"text/html; charset=utf-16le\"> <TITLE>ABTEI</TITLE> </HEAD> <BODY> <H3>Definition</H3> <P>In this field, you can enter the name of the department to which the <A HREF=\"SAPEVENT:DOCU_LINK(GL.cost_center)\"><B>cost center</B></A> belongs. It then can be used for evaluations.</P> </BODY> </HTML>",
"res_langu": "EN"
}, "GL.ABAP": {
"id_name": "GL.ABAP",
"short_text": "",
"long_text": "<HTML> <HEAD> <META http-equiv=\"Content-Type\" content=\"text/html; charset=utf-16le\"> <TITLE>ABAP</TITLE> </HEAD> <BODY> <H4>ABAP Runtime Environment (BC-ABA)</H4> <P><I>A</I>dvanced <I>B</I>usiness <I>A</I>pplication <I>P</I>rogramming</P> <P>The SAP programming language.</P> <P></P> <H4>Brand Voice - Non-Product (BV-NON-PRODUCT)</H4> <P>SAP proprietary programming language, especially designed for creating large-scale business applications.</P> <H4>Brand Voice - Technology Platform (BV-TECHNOLOGY)</H4> <P>The proprietary SAP software programming language.</P> <H4>Brand Voice - Technology Platform (BV-TECHNOLOGY)</H4> <P>A service that allows the user to download files directly into their SAP system running ABAP from any SAP destination site addressed through a URL.</P> <H4>Brand Voice - Technology Platform (BV-TECHNOLOGY)</H4> <P>The application infrastructure component built on the ABAP programming language that exists between the SAP HANA database and core SAP applications that run on SAP HANA. ABAP platform provides core data services, programming libraries and execution services, user interface technology, and other capabilities to make SAP applications run effectively on premise and in the cloud.</P> </BODY> </HTML>",
"res_langu": ""
}, "GLOS.ABAP": {
"id_name": "GLOS.ABAP",
"short_text": "",
"long_text": "<HTML> <HEAD> <META http-equiv=\"Content-Type\" content=\"text/html; charset=utf-16le\"> <TITLE>ABAP</TITLE> </HEAD> <BODY> <H4>ABAP Runtime Environment (BC-ABA)</H4> <P><I>A</I>dvanced <I>B</I>usiness <I>A</I>pplication <I>P</I>rogramming</P> <P>The SAP programming language.</P> <P></P> <H4>Brand Voice - Non-Product (BV-NON-PRODUCT)</H4> <P>SAP proprietary programming language, especially designed for creating large-scale business applications.</P> <H4>Brand Voice - Technology Platform (BV-TECHNOLOGY)</H4> <P>The proprietary SAP software programming language.</P> <H4>Brand Voice - Technology Platform (BV-TECHNOLOGY)</H4> <P>A service that allows the user to download files directly into their SAP system running ABAP from any SAP destination site addressed through a URL.</P> <H4>Brand Voice - Technology Platform (BV-TECHNOLOGY)</H4> <P>The application infrastructure component built on the ABAP programming language that exists between the SAP HANA database and core SAP applications that run on SAP HANA. ABAP platform provides core data services, programming libraries and execution services, user interface technology, and other capabilities to make SAP applications run effectively on premise and in the cloud.</P> </BODY> </HTML>",
"res_langu": ""
}, "SIMG.ALV_CRYSTAL": {
"id_name": "SIMG.ALV_CRYSTAL",
"short_text": "Generic Crystal Report Layout Maintenance",
"long_text": "<HTML> <HEAD> <META http-equiv=\"Content-Type\" content=\"text/html; charset=utf-16le\"> <TITLE>SIMGALV_CRYSTAL</TITLE> </HEAD> <BODY> <P><STRONG>Use</STRONG></P> <P>This application uploads user generic crystal report layouts, downloads or deletes existing layouts, and specifies the system-wide default layout.</P> <P></P> <P></P> <P></P> <P></P> </BODY> </HTML>",
"res_langu": "EN"
}};
static #shiftRight = false;
/**
* start mock mode
* @param {Help4.engine.ur.UrHarmonizationEngine} engine
* @throws {Error}
*/
static start(engine) {
const {_useFixedVersion, _useABAPHelpTexts, _useURHotspots} = engine;
if (!_useABAPHelpTexts && !_useURHotspots) throw new Error('cannot start UR mock - please enable "useABAPHelpTexts" or "useURHotspots"');
engine.stop();
engine._mock = true;
const {Element, JSON} = Help4;
const {MOCK_FRAME_ID, MOCK_ELEMENTS, MOCK_ELEMENTS_V2} = this;
const mockElements = _useFixedVersion === 1 ? MOCK_ELEMENTS : MOCK_ELEMENTS_V2;
const mockFrame = Element.create('IFRAME', {
id: MOCK_FRAME_ID,
dom: document.body,
sandbox: 'allow-scripts allow-same-origin',
style: {
position: 'absolute',
left: '10px',
top: '50px',
width: '500px',
height: '800px',
backgroundColor: 'silver'
}
});
for (const [index, {position, hotspotId, metadata: {column, row}}] of mockElements.entries()) {
const e = Element.create('div', {
dom: mockFrame.contentDocument.body,
style: {
position: 'absolute',
left: `${position.x}px`,
top: `${position.y}px`,
width: `${position.width}px`,
height: `${position.height}px`,
backgroundColor: 'whitesmoke',
border: index % 2 ? '1px dashed darkgreen': 'auto',
fontSize: 'smaller'
}
});
e.dataset.hotspotId = hotspotId;
e.title = hotspotId;
if (index % 2) {
e.innerText = `${row}::${column}`;
}
}
mockFrame.contentWindow.addEventListener('message', ({data, source}) => {
data = JSON.parse(data);
if (data.type !== 'request') return;
setTimeout(() => { // delay to simulate network latency
const {MSG_TYPE: {v1, v2}} = engine.constructor;
switch (data.service) {
case v1.start:
source.postMessage(JSON.stringify({
service: v1.update,
type: 'request',
body: {technology: 'MOCK', elements: MOCK_ELEMENTS}
}));
source.postMessage(JSON.stringify({
service: v1.app,
type: 'request',
body: {
// examples from API wiki v1
// WDA case:
url: 'https://www.sap.com/' // optional - WDA only
// GUI case:
// helpId: {"id":"wnd[0]/usr/ctxtRSRD1-TBMA_VAL", "dynp":"SAPLSD_ENTRY:1000:SE11", "name":"RSRD1-TBMA_VAL" }, // optional - SAP GUI for HTML only
}
}));
break;
case v2.start:
source.postMessage(JSON.stringify({
service: v2.update,
type: 'request',
body: {hotspots: MOCK_ELEMENTS_V2}
}));
source.postMessage(JSON.stringify({
service: v2.app,
type: 'request',
body: {
// WDA:
// "url": <URL> optional
url: 'https://www.sap.com/'
// GUI:
// "backendHelpCDSQuery": <string> optional,
// "backendHelpKey": JSON object optional,
}
}));
break;
}
}, 500);
});
engine.start();
}
/**
* stop mock mode
* @param {Help4.engine.ur.UrHarmonizationEngine} engine
*/
static stop(engine) {
if (!engine._mock) return;
const {MOCK_FRAME_ID} = this;
const mockFrame = document.getElementById(MOCK_FRAME_ID);
mockFrame?.parentNode.removeChild(mockFrame);
}
/**
* Resend mock update message to engine with altered position
* @param {Help4.engine.ur.UrHarmonizationEngine} engine
*/
static update(engine) {
const {
constructor: {MSG_TYPE: {v1, v2}},
_mock, _apiVersion
} = engine;
if (!_mock) return;
const shiftX = ({position}) => position.x += this.#shiftRight ? 10 : -10;
const {MOCK_ELEMENTS, MOCK_ELEMENTS_V2} = this;
MOCK_ELEMENTS.forEach(shiftX);
MOCK_ELEMENTS_V2.forEach(shiftX);
this.#shiftRight = !this.#shiftRight;
const message = _apiVersion === 1
? {service: v1.update, body: {hotspots: MOCK_ELEMENTS}}
: {service: v2.update, body: {hotspots: MOCK_ELEMENTS_V2}}
window.postMessage(Help4.JSON.stringify(message));
}
/**
* Send Guided Tour messages mocking the app behaviour
* @param {Help4.engine.ur.UrHarmonizationEngine} engine
* @param {string} messageType - activateElement|hoverElement|leaveElement|interactOnElement|hotkeyPress
* @param {string} [hotspotId] - hotspotId to target, optional for hotkeyPress
* @param {string|number} [key] - not optional for hotkeyPress
* @param {boolean} [shift]
* @param {boolean} [ctrl]
* @param {boolean} [alt]
*/
static sendTourMessage(engine, messageType, {hotspotId, key, shift, ctrl, alt}) {
const {
constructor: {MSG_TYPE: {v2}},
_connected,
_mock,
_running
} = engine;
const allowedMockMessages = ['activateElement', 'hoverElement', 'leaveElement', 'interactOnElement', 'hotkeyPress'];
if (!_connected || !_running || !_mock ||
!allowedMockMessages.includes(messageType) ||
(!hotspotId && !key) ||
(hotspotId && !this.MOCK_ELEMENTS_V2.some(e => e.hotspotId === hotspotId)))
{
engine._log?.('CMP: engine not connected to app or invalid parameters',
key ? {messageType, hotspotId, key, shift, ctrl, alt} : {messageType, hotspotId}
);
return;
}
const service = v2[messageType];
engine._log?.('CMP: sending mock message', '️🚧 ' + service);
window.postMessage(Help4.JSON.stringify({
type: 'request',
service,
body: key ? {hotspotId, key, shift, ctrl, alt} : {hotspotId}
}));
}
/**
* Set up Selector Migration message, mocking a response from the app for testing
* works with HtmlGui_SidSelector and matches them with hotspotIds,
* generates positional hotspots for other selectors.
* @param {Help4.engine.ur.UrHarmonizationEngine} engine
*/
static startMigrationResponse(engine) {
const {controller, _appFrame} = engine;
const {help: {useABAPHelpTexts}} = controller.getConfiguration();
if (!useABAPHelpTexts) throw new Error('cannot start UR Selector Migration mock - please enable "useABAPHelpTexts"');
// NOTE: this variant does not use the _mock flag, since it should also work in HTMLGUI with HtmlGui_SidSelector
_appFrame?.contentWindow?.addEventListener('message', async ({data, source}) => {
try {
data = Help4.JSON.parse(data);
} catch (e) {
return;
}
const {body, service, type} = data;
const {v2} = engine.constructor.MSG_TYPE;
if (type !== 'request' || service !== v2.migrate) return;
const {/** @type {Help4.engine.ur.UrHarmonizationEngine.UrMigrationRequest[]} */ selectors} = body;
const migrated = selectors.reduce((migrated, selector, index) => {
try {
const {rule, value} = Help4.JSON.parse(selector);
let hotspotId;
// attempt to find hotspot id for HtmlGui_SidSelector
if (rule === 'HtmlGui_SidSelector') {
let {hint} = _appFrame.contentWindow?.document?.querySelector(value)?.dataset || {};
hint = (hint && Help4.JSON.parse(hint)) || {};
hotspotId = hint?.SapCompanion?.hotspotId;
if (hotspotId) {
engine._log?.(`CMP: 🚧 mock migrated HtmlGui_SidSelector to hotspotId`, {selector, hotspotId});
migrated.push({selector, hotspotId});
}
}
if (!hotspotId) {
const position = {x: 100, y: index * 35 + 500, width: 100, height: 30}; // fake position for other selectors
engine._log?.('CMP: 🚧 mock migrated selector to position', {selector, position});
migrated.push({selector, position});
}
} catch (e) {
engine._log?.('CMP: 🚧 error during mock migration', {selector, e});
}
return migrated;
}, []);
engine._log?.(`CMP: 🚧 sending mock HotspotsFromSelectors`, selectors);
source.postMessage(Help4.JSON.stringify({
service: v2.fromSelectors,
type: 'request',
body: {migrated}
}));
});
}
/**
* Send mock update message in UI5 application, this emulates a UI5-side implementation
* @param {Help4.engine.ur.UrHarmonizationEngine} engine
*/
static startUI5(engine) {
const {Connection} = Help4.engine.ur;
if (Connection.getUI5AppType(engine) !== Connection.APP_TYPE.UI5) throw new Error('cannot start UI5 UR mock on non UI5 app');
const {
_useABAPHelpTexts,
_useUI5HelpTexts
} = engine;
if (!_useABAPHelpTexts || !_useUI5HelpTexts) throw new Error('cannot start UI5 UR mock - please enable "useABAPHelpTexts" and "useUI5HelpTexts"');
// NOTE: this variant does not use the _mock flag, since no app frame is used in UI5
window.addEventListener('message', ({data, source}) => {
try {
data = JSON.parse(data);
} catch (e) {
return;
}
if (data.type !== 'request') return;
const {v2} = engine.constructor.MSG_TYPE;
switch (data.service) {
case v2.start:
let hotspots = /** @type {Help4.engine.ur.UrHarmonizationEngine.UrHotspot[]} */ [];
const allOptions = /** @type {CheckVisibilityOptions} */ {
contentVisibilityAuto: true,
opacityProperty: true,
visibilityProperty: true
};
// generate hotspots from
// toolbar buttons: '[id$=Toolbar] button:not(.sapMTBHiddenElement)'
// buttons and inputs
const selector = '.sapMBtn, .sapMInput, .sapMSF, .sapMSlt, .sapMMultiComboBox';
for (const element of document.querySelectorAll(selector)) {
if (element.checkVisibility(allOptions)) {
const {ariaLabel, id, innerText, title} = element;
hotspots.push({
// backendHelpCDSQuery not sent by UI5, assume SDOC_HLP_CE_UI5_ESID later
// picking known working example key
backendHelpKey: {id: "/IWBEP/V4_REG_DESCRIPTION", origin: "G1Y_000", type: "DE"},
// position not sent by UI5, get from DOM through hotspotId
hotspotId: id,
labelText: ariaLabel || title || innerText
});
}
}
// send hotspots to UR
source.postMessage(JSON.stringify({
service: v2.update,
type: 'request',
body: {hotspots}
}));
// UI5 What's This App?: tbd
// source.postMessage(JSON.stringify({
// service: v2.app,
// type: 'request',
// body: { ??? }
// }));
break;
}
});
}
};
/**
* init mock data
* @private
*/
(function() {
// Massive Hotspot Test; XRAY-4688
const {MOCK_ELEMENTS, MOCK_ELEMENTS_V2} = Help4.engine.ur.Mock;
for (let y = 0; y < 10; y++) {
for (let x = 0; x < 10; x++) {
const o1 = /** @type {Help4.engine.ur.UrHarmonizationEngine.UrElement} */ {
id: {id: `wnd[0]/mock/${y}/${x+1}`, dynp: 'MOCK'},
position: {x: x * 40, y: 400 + y * 40, width: 30, height: 30},
ctrlId: `MOCK::${y}::${x+1}`,
metadata: { column: x + 1, row: y } // for visualization, not part of the API
};
if (!y) o1.labelText = '✅ labelText overwriting label_text';
const o2 = /** @type {Help4.engine.ur.UrHarmonizationEngine.UrHotspot} */ {
backendHelpKey: o1.id,
position: o1.position,
hotspotId: o1.ctrlId,
labelText: o1.labelText || '(' + o1.ctrlId + ')',
metadata: o1.metadata
};
MOCK_ELEMENTS.push(o1);
MOCK_ELEMENTS_V2.push(o2);
}
}
})();
})();