We have recently switched over from WebChatV3 to V4. As an ongoing effort we're porting all our custom functionality to the new client. One of those functionalities is checking URLs for a specific domain and setting the target on the a tag to "_parent".
To implement this we've added a dependency to markdown-it, since the ReactWebChat element can take it as an argument as described here: BotFramework-Webchat Middleware for renderMarkdown Instead of adding an emoji renderer, we've built a rule into it and passed it into ReactWebChat as per the example given in the answer above. That code looks like this:
export const getConfiguredMarkdownIt = () => {
const markdownIt = new MarkdownIt.default({ html: false, xhtmlOut: true, breaks: true, linkify: true, typographer: true });
const defaultRender = markdownIt.renderer.rules.link_open || ((tokens, idx, options, env, self) => {
return self.renderToken(tokens, idx, options);
});
markdownIt.renderer.rules.link_open = (tokens, idx, options, env, self) => {
let href = '';
const hrefIndex = tokens[idx].attrIndex('href');
if (hrefIndex >= 0) {
href = tokens[idx].attrs[hrefIndex][1];
}
const newTarget = Helper.getTargetForUrl(href);
const targetIndex = tokens[idx].attrIndex('target');
if (targetIndex < 0) {
tokens[idx].attrPush(['target', newTarget]);
} else {
tokens[idx].attrs[targetIndex][1] = newTarget;
}
const relIndex = tokens[idx].attrIndex('rel');
const rel = 'noopener noreferrer';
if (relIndex < 0) {
tokens[idx].attrPush(['rel', rel]);
} else {
tokens[idx].attrs[relIndex][1] = rel;
}
console.log(tokens[idx]);
return defaultRender(tokens, idx, options, env, self);
};
return markdownIt;
}
This is then used to pass into the ReactWebChat element as such (left out a lot for brevity):
import { getConfiguredMarkdownIt } from './MarkdownSetup'
const md = getConfiguredMarkdownIt();
...
<ReactWebChat renderMarkdown={ md.render.bind(md) } />
The first message our bot returns to the user sends a URL that should be targeting "_parent". However, it turns up as "_blank" consistently while the "rel" attribute is absolutely being set through our custom method. To me this confirms that our custom rule is working but something weird is going on. I've debugged what happens and the rendered HTML, including the "target" attribute keeps the correct value for a while but eventually gets switched over to "_blank". Later messages all get their target rendered correctly, I've replaced the URL in the opening activity to one of those to see what would happen and the result is the same: "_blank".
Javascript isn't really my expertise and I have a hard time following what happens when I step through the code in chrome debug tools. But I did manage to observe the correct HTML all the way up to card-elements.ts. When I get there, at the end of the isBleedingAtBottom function, the HTML I find suddenly has "_blank" in the "target" attribute. I am at a complete loss as to why this is happening.
Is this a bug or is there something I'm missing?
Versions:
"botframework-webchat": "^4.7.0",
"markdown-it": "8.3.1",
Here's the (slightly modified) JSON of the message:
{
"type": "message",
"serviceUrl": "http://localhost:57714",
"channelId": "emulator",
"from": {
"id": "63700ba0-e2ca-11ea-8243-4773a3b07af6",
"name": "Bot",
"role": "bot"
},
"conversation": {
"id": "63727ca0-e2ca-11ea-b639-bf8d0ffe9da8|livechat"
},
"recipient": {
"id": "3952a99d-87de-4b22-a1b3-04fd8c9f141b",
"role": "user"
},
"locale": "en-US",
"inputHint": "acceptingInput",
"attachments": [
{
"contentType": "application/vnd.microsoft.card.hero",
"content": {
"text": "Go to [this page](REMOVED URL) bla bla blah. click start to continue",
"buttons": [
{
"type": "imBack",
"title": "Start",
"value": "Start"
}
]
}
}
],
"entities": [],
"replyToId": "654f52f0-e2ca-11ea-b639-bf8d0ffe9da8",
"id": "688a0b90-e2ca-11ea-b639-bf8d0ffe9da8",
"localTimestamp": "2020-08-20T11:49:15+02:00",
"timestamp": "2020-08-20T09:49:15.336Z"
}