angular TinyMCE integration - javascript

I follow official doc for integrating TinyMCE with Angular: https://www.tinymce.com/docs/integrations/angular2/.
Now everything works fine, but TinyMCEs plugins loaded in application start, but I want it load asynchronously from /src/assets/tinymce. Question is,
How can I load TinyMCE asynchronously when I need it?
~ apologies for grammatical mistakes
In .angular-cli.json I have scripts array:
"scripts": [
"../node_modules/tinymce/tinymce.js",
"../node_modules/tinymce/themes/modern/theme.js",
"../node_modules/tinymce/plugins/link/plugin.js",
"../node_modules/tinymce/plugins/paste/plugin.js",
"../node_modules/tinymce/plugins/table/plugin.js",
"../node_modules/tinymce/plugins/image/plugin.js",
"../node_modules/tinymce/plugins/imagepicker/plugin.js",
"../node_modules/tinymce/plugins/imagetools/plugin.js",
"../node_modules/tinymce/plugins/advlist/plugin.js",
"../node_modules/tinymce/plugins/autolink/plugin.js",
"../node_modules/tinymce/plugins/lists/plugin.js",
"../node_modules/tinymce/plugins/charmap/plugin.js",
"../node_modules/tinymce/plugins/print/plugin.js",
"../node_modules/tinymce/plugins/preview/plugin.js",
"../node_modules/tinymce/plugins/hr/plugin.js",
"../node_modules/tinymce/plugins/anchor/plugin.js",
"../node_modules/tinymce/plugins/pagebreak/plugin.js",
"../node_modules/tinymce/plugins/searchreplace/plugin.js",
"../node_modules/tinymce/plugins/wordcount/plugin.js",
"../node_modules/tinymce/plugins/visualblocks/plugin.js",
"../node_modules/tinymce/plugins/visualchars/plugin.js",
"../node_modules/tinymce/plugins/fullscreen/plugin.js",
"../node_modules/tinymce/plugins/insertdatetime/plugin.js",
"../node_modules/tinymce/plugins/media/plugin.js",
"../node_modules/tinymce/plugins/nonbreaking/plugin.js",
"../node_modules/tinymce/plugins/save/plugin.js",
"../node_modules/tinymce/plugins/contextmenu/plugin.js",
"../node_modules/tinymce/plugins/directionality/plugin.js",
"../node_modules/tinymce/plugins/template/plugin.js",
"../node_modules/tinymce/plugins/textcolor/plugin.js",
"../node_modules/tinymce/plugins/colorpicker/plugin.js",
"../node_modules/tinymce/plugins/textpattern/plugin.js",
"../node_modules/tinymce/plugins/toc/plugin.js",
"../node_modules/tinymce/plugins/code/plugin.js",
"../node_modules/tinymce/plugins/autoresize/plugin.js",
"../node_modules/tinymce/plugins/help/plugin.js"
],
these scripts are plugins of TinyMCE

Declare these 2 on top in your component:
declare var tinymce: any;
const url = '//cdn.tinymce.com/4/tinymce.min.js';
Use this function to load the script in your component's onInit function:
loadScript() {
let scriptTag = document.querySelector('script[src="//cdn.tinymce.com/4/tinymce.min.js"]');
let node;
if (!scriptTag) {
node = document.createElement('script');
node.src = url;
node.type = 'text/javascript';
node.async = true;
node.charset = 'utf-8';
document.getElementsByTagName('head')[0].appendChild(node);
}
}
and then use the following function to load the tinymce:
loadTinyMCE() {
if (tinymce)
tinymce.init({
selector: '#tinymce',
skin_url: 'assets/skins/lightgray',
plugins: ['paste', 'link', 'autoresize','image'],
setup: editor => {
this.editor = editor;
}
})
}
and finally destroy the tinymce object on ngdestroy:
ngOnDestroy() {
tinymce.remove();
}
It might be the bad approach but it saves me from loading the script on application load and gives me the ability to load it only when it is needed.

Related

Inject hotjar script into angular page inside head element

I want to add conditions to load this script in the head tag. I need to check if the URL is from our live domain then only it runs otherwise not. I could simply add this script to the head if there was no condition requirement. How I can inject this script in the head tag in angular?
For eg:
window.origin == 'https://www.stackoverflow.com' then inject this script into the head tag otherwise not.
<script>
(function(h,o,t,j,a,r){
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
h._hjSettings={hjid:*******,hjsv:*};
a=o.getElementsByTagName('head')[0];
r=o.createElement('script');r.async=1;
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
a.appendChild(r);
})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');
</script>
You can handle this in one of your components, preferably in app.component. You could check the URL of course but more elegant would be to have some flag like enableHotjarTracking in your environment.ts file and set it to true only for your production environment.
Then you could call it as follows in your app.component.ts
import { environment } from './environments/environment';
import { DOCUMENT } from '#angular/common';
...
// inject document wrapper
constructor(
#Inject(DOCUMENT) private document: Document,
){}
ngAfterContentInit() {
if(environment.enableHotjarTracking) {
((h, o, t, j, a, r) => {
h.hj =
h.hj ||
/* tslint:disable:only-arrow-functions */
function () {
(h.hj.q = h.hj.q || []).push(arguments);
};
h._hjSettings = { hjid: xxxx, hjsv: x };
a = o.getElementsByTagName('head')[0];
r = o.createElement('script');
r.async = 1;
r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
a.appendChild(r);
})(window as any, this.document, 'https://static.hotjar.com/c/hotjar-', '.js?sv=');
}
}
You could also keep your hotjar id in the environment file.

barba js v2 reinit main.js script

I am struggling with barba js v2. After ajaxtransition my main.js script stops working. I would like to reinit this script somehow ...
I have simple barba transition like this ->
import barba from "#barba/core"
class Transition {
constructor() {
// console.log(barba)
this.events()
}
events() {
// console.log("events")
barba.init({
transitions: [
{
name: "default-transition",
leave() {
// create your stunning leave animation here
console.log("leave")
},
enter() {
console.log("enter")
// create your amazing enter animation here
}
}
]
})
}
}
export default Transition
and at the and of </body> tag I have
<script src="js/main-dist.js"></script>
</body>
Inside this main-dist.js script there are couple of other scripts that are imported, for example a function that shows current date.
When I go to the page at first time, everything works fine, but when I go to another page and come back to the page that should display the current date, the date is not displaying because script is not initialized. It initalizes only on load not on ajaxload.
So my roadblock is to re-init somehow this script on ajaxload.
I figured it out. There is barba hook "after" that we can use in the transition script :)
barba.hooks.after(() => {
const bottomDOM = document.getElementsByTagName("body")[0]
const newScript = document.createElement("script")
const oldScript = document.querySelector(".main-script")
newScript.src = "js/main-dist.js"
newScript.className = "main-script"
oldScript.remove()
bottomDOM.appendChild(newScript)
})
I have a <script class="main-script" src="js/main-dist.js"></script> at the end of the DOM, and use barba.hook to remove it and then add it again

React Portals - Execute function that references new window's DOM

I'm trying to create a React Portal that when mounted, requires running a specific line to load an ActiveReports Designer component.
Here's is my portal code:
constructor(props: IWindowPortalProps) {
super(props);
this.containerEl = document.createElement('div'); // STEP 1: create an empty div
this.containerEl.id = 'designer-host';
this.containerEl.className = styles.designerHost;
this.externalWindow = null;
}
private copyStyles = (sourceDoc: Document, targetDoc: Document) => {
Array.from(sourceDoc.styleSheets).forEach(styleSheet => {
if (styleSheet.cssRules) { // true for inline styles
const newStyleEl = sourceDoc.createElement('style');
Array.from(styleSheet.cssRules).forEach(cssRule => {
newStyleEl.appendChild(sourceDoc.createTextNode(cssRule.cssText));
});
targetDoc.head.appendChild(newStyleEl);
} else if (styleSheet.href) { // true for stylesheets loaded from a URL
const newLinkEl = sourceDoc.createElement('link');
newLinkEl.rel = 'stylesheet';
newLinkEl.href = styleSheet.href;
targetDoc.head.appendChild(newLinkEl);
}
});
}
componentDidMount() {
this.externalWindow = window.open('', '', `height=${window.screen.height},width=${window.screen.width}`);
this.externalWindow.document.body.appendChild(this.containerEl);
this.externalWindow.document.title = 'A React portal window';
this.externalWindow.addEventListener('load', () => {
new Designer('#designer-host');
});
}
render() {
return ReactDOM.createPortal(null, this.containerEl);
}
However, when the new window loads, I get the error
Error: Cannot find the host element. at Function.<anonymous>
which indicates that the designer-host div is not there. I think the load function points to the main DOM and not the new window's one.
Alternatively, I tried appending the ActiveReports .js file by doing in my componentDidMount()
s.type = "text/javascript";
s.src = "../node_modules/#grapecity/activereports/lib/node_modules/#grapecity/ar-js-designer/index.js";
this.externalWindow.document.head.append(s);
and then assigning the Designer instantiation on the onLoad property of the element. Again with no luck.
Is there maybe a way I could run JavaScript a code after the portal has been loaded and point to that DOM?
Thank you
I work for GrapeCity. Could you please go to our support portal and submit a ticket. We will need a full code sample for us to be able to answer this question. Please give us a download link to the sample within the ticket.
Thank you

Loading Scripts on specific component (Route) in React

Is it possible to run html scripts in a specific React component only, instead of directly in index.html. The script loads a third party barcode scanner, which is only being used in one component, and therefore I want to avoid loading it for every component as this will slow the whole app down.
The npm module can be found here: https://www.npmjs.com/package/dynamsoft-javascript-barcode but there is no documentation on how to import it, only to include it like this:
<script src="https://cdn.jsdelivr.net/npm/dynamsoft-javascript-barcode#7.2.2-v2/dist/dbr.js" data-productKeys="LICENSE-KEY"></script>
<script>
let barcodeScanner = null;
Dynamsoft.BarcodeScanner.createInstance({
onFrameRead: results => {console.log(results);},
onUnduplicatedRead: (txt, result) => {alert(txt);}
}).then(scanner => {
barcodeScanner = scanner;
barcodeScanner.show();
});
</script>
Here is the React sample provided by Dynamsoft GitHub repository: https://github.com/dynamsoft-dbr/javascript-barcode/tree/master/example/web/react
You can check out Dynamsoft.js and HelloWorld.js to see how to import and use the module:
import Dynamsoft from "dynamsoft-javascript-barcode";
Dynamsoft.BarcodeReader.engineResourcePath = "https://cdn.jsdelivr.net/npm/dynamsoft-javascript-barcode#7.3.0-v1/dist/";
// Please visit https://www.dynamsoft.com/CustomerPortal/Portal/TrialLicense.aspx to get a trial license
Dynamsoft.BarcodeReader.productKeys = "PRODUCT-KEYS";
// Dynamsoft.BarcodeReader._bUseFullFeature = true; // Control of loading min wasm or full wasm.
export default Dynamsoft;
import Dynamsoft from "../Dynamsoft";
import React from 'react';
class HelloWorld extends React.Component {
...
let reader = this.reader = this.reader || await Dynamsoft.BarcodeReader.createInstance();
...
}
Note: This sample uses 7.3.0-v1. 7.2.2-v2 does not support this usage.
I haven't tried this code but I have done some code like this.You can add script tag like this:
class YourComponent extends React.Component {
loadScript() {
let script = document.createElement("script");
script.src = "https://cdn.jsdelivr.net/npm/dynamsoft-javascript-barcode#7.2.2-v2/dist/dbr.js";
script.setAttribute("data-productKeys","LICENSE-KEY");
script.type = "text/javascript";
document.head.append(script);
}
componentWillMount() {
if(!YourComponent.bScriptLoaded){
this.loadScript();
YourComponent.bScriptLoaded = true;
}
}
}
This will add script tag in head tag and.And after that you can run your code in component.

Load module with parameter after bundle

I've got the following codeblock in the layout.js
import $ from "jquery";
import LayoutModel from 'js/models/LayoutModel';
let elements = {
$window: $(window),
$html: $('html'),
$content: $('#content')
};
let viewmodel = null;
export function init(options) {
viewmodel = new LayoutModel(options, elements);
ko.applyBindings(viewmodel, elements.$content[0]);
}
and I load it in the view with system.js and call the init() with options. The options contains values and it has to be in the view because some of it comes from the back-end model.
System.import('resources/javascript/layout').then(function(controller) {
var options = {
something: 'value'
};
controller.init(options);
});
This solution works while it's not bundled with jspm:
jspm bundle resources\javascript\layout resources\javascript\dist\layout.min.js --minify
In production I have to do it, but in this case I'm not able to use the system.import() and the .then(), because I have to load the bundled script with a normal <script> tag:
<script src="resources\javascript\dist\layout.min.js"></script>
So the question: How can I bundle and minify it and call the init() method with the options?
Thank you!

Categories

Resources