How to render mathml which retrieved by restful api with mathjax dynamically - vuejs2

I have a vue project using mathjax to render partial html files which include some mathml inside. Those files are dynamically retrieved from remote server when customers search something and shown with vue v-html as raw html.
In details, all these occurs in the component 'Home', in the mounted function, I add mathjax related script as below:
const mathjaxScript = document.createElement('script');
mathjaxScript.setAttribute('id', 'MathJax-script');
mathjaxScript.setAttribute('async', 'async');
mathjaxScript.setAttribute('src', 'https://cdn.jsdelivr.net/npm/mathjax#3/es5/tex-mml-chtml.js');
document.head.appendChild(mathjaxScript);
Then when customers search some keyword, corresponding partial html file will be retrieved and replace v-html tag, the math equation should be shown expectedly. However, those embeded mml:math tags weren't handled, they are just plain text, the math equation not handled correctly.
However, when I put one partial html in the vue template (not dynamically retrieve from remote server), the math equation rendered correctly. the mml:math tag will be replaced with mjx-container, etc.
So my question is: how to apply mathjax to those dynamically retrieved mathml? that is, rendering mathml on the fly with mathjax, Thanks.
Note: I use vuejs, mathjax 3 and typescript.

Related

Render non-vuejs HTML in a component

I have a working VueJS app with nested components.
In one of the components, I want to be able to inject arbitrary HTML but I don't want VUEJS to parse it : I want plain old HTML tags (scripts, iframes, style, divs, native events, whatever I need).
I know I can do that outside the root "#app", but is there a way to do that inside it ?
Thanks.
You can use v-html directive, it takes an expression that evaluates to a string and sets the element's innerHTML to that string. Vue won't parse it as a template and insert it into the DOM instead. This is one of those things that you need to pay attention to security for.
See docs: https://vuejs.org/api/built-in-directives.html#v-html

How to integer an oembed javascript tag inside a VueJs component?

I have an "embed" field used by my users for transform a simple link to a rich content link (link with image, title, description, etc.).
Example:
Note: I use this library to get all link information: oscarotero/Embed
As you can see, when you provide an url (a twitter tweet by example), the "code" parameter contain the HTML and script tags to include on my frontend:
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">I am so hopelessly in love with #ChucklefishLTD ‘s spooky logo pic.twitter.com/2KtjCNOOUl</p>— Tom Slayed 🔪😱 (#TomJamesSlade) October 12, 2020</blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
The problem is with VueJs and the script tag. When my ajax call is OK, I store all embed informations like that:
this.preview = response.embed
And inside my component, I display the html code with the "v-html" VueJs directive
<div v-if="preview['code']" v-html="preview['code']"></div>
The html is displayed :
The script tag is visible inside the code inspector :
But the script is not loaded :
I have the same problem with all oembed url who provide a javascript tag inside the response.
Note: If I try to load the script directly inside the component, VueJs return this error:
VueCompilerError: Tags with side effect ( and ) are ignored in client component templates
A solution on google is to use the "mounted" event, but it's not compatible with my context.
Because the script I have to load is received from an api and can be different each time depending of the link.
it's bit late but here is an option: The api gives you the possibility to not send the script tag, so you can include it on your own in the html before. Add to the url a omit_script=true and it's gone in the result.
Then you can insert the twitter block. Maybe you have to call twttr.widgets.load() to initialize the tweet.
Edit: Since you're using the plugin, this should be working
$embed = new Embed();
$result = $embed->get('https://www.instagram.com/p/B_C0wheCa4V/');
$result->setSettings([
'oembed:query_parameters' => ['omit_script' => true]
]);
$oembed = $info->getOEmbed();

Is lazy loading B64 images from vuex Store possible?

I have a vue template with 12 img tags
<img
:src="item.logo"
onerror="this.style.visibility='hidden'"
/>
The img tag is inside a loop.
The value of item.logo is for example:
"data:image/svg+xml;base64,PHN2ZyBpZD0iRWJlbmVfMSIgZGF0YS1uYW1lPSJFYmVuZSAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNDIuNzYgNTYuODMiPjxkZWZzPjxzdHlsZT4uY2xzLTEsLmNscy0yLC5jbHMtM3tmaWxsOiNmZmY7fS5jbHMtMXtvcGFjaXR5OjAuNjt9LmNscy0ze29wYWNpdHk6MC41OTt9LmNscy00e2ZpbGw6I2EyMWMyNjt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPmxvZ28td25kLXR2LWluZm88L3RpdGxlPjxyZWN0IGNsYXNzPSJjbHMtMSIgeD0iMjYuODEiIHk9IjAuMTQiIHdpZHRoPSIxMTUuOTUiIGhlaWdodD0iNTYuNjkiLz48cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik04Ni44OSw3OS40OWgtNS43VjU0LjQxaDUuN1oiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zOS4wMSAtMzcuO"
I do not put here the whole content of the b64, just know that it is a base64 encoded SVG.
The SVGs show correctly.
My problem is that the page rendering is quite long, because the device I use is very slow.
But when I modify the item.logo value by a URI that points to a hosted SVG, the page renders fast without showing at once the svgs, allowing the user to interact with the page while the logos load (lazy load?)
My question:
Is it possible to have a kind of asyncroneous load of these images in the case they are stored in the Vuex store in a b64 format? So the user would still be able to interact with the page while the images get loaded.
Vue module for lazyloading images in your applications: https://www.npmjs.com/package/vue-lazyload.
Looks like this is what you need.

Vuepress README.doc first page in format yaml convert to markdown format doc

I am not able to find information on how to modify the main page of Vuepress, which, although I like its structure, being in .yaml format does not allow me to put links.
Is it possible to put links?
Or better, is it possible to convert that page to markdown format but keeping the output it delivers?
Unfortunately it is not possible without modifying the Vue templates. The home page is rendered by the Home component component and it renders the page's frontmatter using Vue's "Mustache" syntax. Values inside the mustaches will only ever be rendered as plain text.
You'll have to modify the Home component by either "ejecting" the default theme or by creating a custom layout for the home page. In both cases, you will obviously not receive any updates to the components anymore when you upgrade Vuepress.
I've created a demo to show how to use a custom layout to allow the frontmatter to be HTML. I've copied the Layout and Home components from Vuepress and changed the new Home component to use v-html to inject HTML values into the h1 component. So now your heroText could be Hi! This is a <a href='https://www.google.com'>link</a> and it will be displayed as a link on the home page. You could obviously do the same for the other elements.
Be sure to set the layout value of your home page to the new layout, e.g. layout: HomeLayout.

How to work with vue.js and window.getSelection()?

Here is an example from some tutorial:
<p id="p">Example: <i>italic</i> and <b>bold</b></p>
<script>
let range = new Range();
range.setStart(p.firstChild, 2);
range.setEnd(p.querySelector('b').firstChild, 3);
alert(range); // ample: italic and bol
// use this range for selection (explained later)
window.getSelection().addRange(range);
</script>
How to do this with vue?
Should I use query selectors too?
I am interested how to do this selection manipulation within contenteditable. I can use "ref" for contenteditable container but inner content with bold, italic etc. tags is dynamic and mark this code with refs:
... <b><i>some text</i></b> ...
isn't appropriate.
If you're using the Selection API to manipulate the DOM (not just creating ranges, but adding/removing/modifing/reordering DOM nodes), then you should be doing those manipulations on DOM elements not managed by Vue. You must not modify parts of the DOM managed by Vue because Vue won't know about those changes and it will get confused when trying to patch the DOM during the next render cycle. Vue "owns" the rendered DOM of its components.
This doesn't mean you can't use the Selection API and Vue together, it just means you need to be careful not to tinker in the DOM willy-nilly.
Should I use query selectors too? Using p.querySelector('b').firstChild isn't vue way but I don't know what should I use insted
This rule only applies if you want to get a reference to a DOM node rendered by Vue. If the container were content editable, then its contents would not be managed by Vue and you would have no way of referencing its contents without using querySelector and other DOM functions. Try not to get caught up with "am I doing it the Vue-way?" when what you are trying to do is inherently not Vue related anyway.