How to conditionally load file? - javascript

Could somebody suggest me a way for loading css or javascript file conditionally i.e only if url is accessible?
for example on my page I have the following files:
<html>
...
<link rel="stylesheet" type="text/css" href="https://service.test/css/a.css"/>
<script type="text/javascript" src="https://services.test/js/a.js"></script>
...
</html>
Is there any way to check if https://service.test/css/a.css is accessible then if yes load this resource (same for https://services.test/js/a.js)?

You could try something like this. but it will only work for the stylesheets that are in head section.
<html>
<link rel="stylesheet" type="text/css" href="https://service.test/css/a.css"/>
<body>
</body>
<script>
// you will have to manuall define the pairs (keys are stylesheets and values are scripts you want to load)
const pairs = {
"https://service.test/css/a.css": "https://services.test/js/a.js"
}
let styles = document.querySelectorAll("link[rel='stylesheet'][type='text/css'][href]");
styles.forEach(s => {
if(pairs[s.href]){
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = pairs[s.href];
document.getElementsByTagName('head')[0].appendChild(script);
}
});
</script>
</html>

Related

Clarification for appendChild

I added a Cookies Consent banner. The requirement is that https://cdn.cookielaw.org/consent/c4337328/OtAutoBlock.js loaded before any other script. I now wonder if appendChild is the right choice. Will it load OtAutoBlock at the exact position I wrote it or will it append the script to the end of the tag (which would be too late). It has to be the first script that's loaded.
<!DOCTYPE html>
<html lang="en">
<head>
<!-- OneTrust Cookies Consent Notice -->
<script type="text/javascript">
if ("%REACT_APP_COOKIE_BAR%" === "true") {
var otAutoBlock = document.createElement("script");
otAutoBlock.setAttribute("type", "text/javascript");
otAutoBlock.setAttribute("src", "https://cdn.cookielaw.org/consent/c4337328/OtAutoBlock.js");
var otSDKStub = document.createElement("script");
otSDKStub.setAttribute("type", "text/javascript");
otSDKStub.setAttribute("src", "https://cdn.cookielaw.org/scripttemplates/otSDKStub.js");
otSDKStub.setAttribute("charset", "UTF-8");
otSDKStub.setAttribute("data-domain-script", "c4337328");
document.getElementsByTagName("head")[0].appendChild(otAutoBlock);
document.getElementsByTagName("head")[0].appendChild(otSDKStub);
function OptanonWrapper() { }
}
</script>
<script type="text/javascript">
/* [Should load after OtAutoBlock loads to avoid tracking before consent was given] */
</script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
document.head.appendChild(script) will add it to the end of the <head> tag, so it will load after all other scripts. You can do two things:
You load it with appendChild at the end, and have all your other scripts with a defer attribute, like this: <script defer> /* something */ </script> The defer forces a script to execute after the page is loaded, but if you load the OtAutoBlock without a defer, it will run before the others. The only thing to note is that defer will cause the scripts not to run last, but after the entire page loads, which includes CSS stylesheets, other JavaScripts, icons, images, HTML content, XHR requests in <script> tags, etc.
<script>
const load = true; // your stuff here
if (load)
{
const script = document.createElement('script');
window.hasRunned = false;
script.text = 'alert(\'OtAutoBlock running.\'); window.hasRunned = true;';
document.head.appendChild(script);
}
</script>
<script defer>
alert('Another script. Has runned OtAutoBlock: ' + window.hasRunned);
</script>
<script defer>
alert('And yet another. Has runned OtAutoBlock: ' + window.hasRunned);
</script>
You use insertBefore to add it before the other scripts, so it will run before them. No need to use defer with this method. This might be what you want if you need the scripts to run before the page loads.
<script>
const load = true; // your stuff here
if (load)
{
let script = document.createElement('script');
window.hasRunned = false;
script.text = 'alert(\'OtAutoBlock running.\'); window.hasRunned = true;';
document.head.insertBefore(script, document.head.children[0]);
}
</script>
<script>
alert('Another script. Has runned OtAutoBlock: ' + window.hasRunned);
</script>
<script>
alert('And yet another. Has runned OtAutoBlock: ' + window.hasRunned);
</script>

Function not working if src is a variable?

With this HTML the function myFunc() can be executed. https://myurl.de/myjs.js has the function myFunc in it.
<head>
<script type="text/javascript" src="https://myurl.de/myjs.js"></script>
<body>
<script type="text/javascript">
myFunc();
</script>
</body>
</head>
But with the second HTML I get an Error: Uncaught ReferenceError: myFunc is not defined.
https://myurl.de/settingsFile.js is a file that includes this url in a var: https://myurl.de/myjs.js so basically SettingsFile.UrlToMyJS is this https://myurl.de/myjs.js
<head>
<script src="https://myurl.de/settingsFile.js"></script>
<script type="text/javascript" id="myid"></script>
</head>
<body>
<script type="text/javascript">
document.getElementById('myid').src = SettingsFile.UrlToMyJS;
myFunc();
</script>
</body>
When I console.log(document.getElementById('myid')) this is the output:
<script type="text/javascript" id="myid" src="https://myurl.de/myjs.js></script> which is correct. It looks exactly like the script in the head of the first html (with the difference that it has the id="myid").
Yet it does not work. Why and how can I fix it?
settingsFile.js:
var defaultURL = 'https://myurl.de/';
var SettingsFile = {
UrlToMyJS : defaultURL + 'myjs.js',
}
The reason it's not working is that you can't add a src to a script element that's already in the DOM — or rather, doing so doesn't do anything. The script element has already been processed.
Instead, create it and then append it:
var script = document.createElement("script");
script.onload = function() {
myFunc();
};
script.src = SettingsFile.UrlToMyJS;
document.head.appendChild(script);
// If you need to support IE8, use the following instead of the previous line:
//document.getElementsByTagName("head")[0].appendChild(script);
That waits for the script to load, then calls myFunc (which should exist by then).
Also note that as I and Jeremy pointed out in the comments, body doesn't go in head, it goes after. It's also generally best to put script tags at the end of body (if you're not using async or defer attributes on them or type="module"). So in all, something like:
<head>
<!-- head stuff here -->
</head>
<body>
<!-- content here -->
<script src="https://myurl.de/settingsFile.js"></script>
<script type="text/javascript">
var script = document.createElement("script");
script.onload = function() {
myFunc();
};
script.src = SettingsFile.UrlToMyJS;
document.head.appendChild(script);
// If you need to support IE8, use the following instead of the previous line:
//document.getElementsByTagName("head")[0].appendChild(script);
</script>
</body>
Another option is to use document.write. This sort of thing may be the last at-least-partially appropriate use of document.write during the main parsing of the page:
<head>
<!-- head stuff here -->
</head>
<body>
<!-- content here -->
<script src="https://myurl.de/settingsFile.js"></script>
<script type="text/javascript">
document.write('<script src="' + SettingsFile.UrlToMyJS + '"><\/script>');
</script>
<script>
myFunc();
</script>
</body>
You can try creating a element and then appending it to your title
For Example (script code) :
var script = document.createElement("script");
script.src = "YOUR_SCRIPT_SRC_HERE";
document.getElementsByTagName('head')[0].appendChild(script);
Here I am creating a new tag in html and then appending it to the head of your html. Even as T.J. Crowder mentioned in the comment try removing your body from the head

script.onload JSX file

I have problem when I try to load JSX file via native js function and script.onload event.
In my HTML file inside HEAD tag I have only one script to load:
<script src="js/01_jquery-1.12.2.min.js" defer></script>
Then in body I have this script which will load all other JS and JSX files
window.onload = function onLoad() {
function getScriptFile(inFile, scriptType, qname) {
....
}
function loadJsQ(inObj) {
....
}
// lib js
loadJsFiles({file: 'js/jquery-ui.min.js'});
loadJsFiles({file: 'js/bootstrap.js'});
loadJsFiles({file: 'js/babel-core-5-8-34-browser.js'});
loadJsFiles({file: 'js/react-with-addons.js'});
loadJsFiles({file: 'js/react-dom.js'});
//class app
loadJsFiles({file: 'classes/User.js'});
loadJsFiles({file: 'classes/MainApplication.js'});
//jsx
loadJsFiles({file: 'jsx/mainReact.jsx', type: "text/babel"});
//
$(document).dequeue('queueLoadJsFiles');
};
Function inside window.onload are:
function getScriptFile(inFile, scriptType, qname) {
var scriptType = scriptType || false;
var script = document.createElement('script');
if(scriptType){
script.type = scriptType;
}
document.head.appendChild(script);
script.onload = script.onreadystatechange = function( _, isAbort ) {
console.log("script",script);
if(isAbort || !script.readyState || /loaded|complete/.test(script.readyState) ) {
script.onload = script.onreadystatechange = null;
script = undefined;
if(!isAbort) {
console.log("Script is loaded", inFile);
setTimeout(function () {
$(document).dequeue(qname);
}, 100)
}
}
};
script.src = inFile;
}
Next function is:
function loadJsQ(inObj) {
var qname = "queueLoadJsFiles";
$(document).queue(qname, function() {
var inFile = inObj.file,
inType = inObj.type || false;
getScriptJQueryQueue(inFile, inType, qname);
});
}
Everything loaded and check via console, but jsx is not executed.
My MainReact.jsx file is
//file jsx/mainReact.jsx
"use strict";
console.log("is ok in JSX???");
const SomeComponent = React.createClass({
....
});
const MainApp = React.createClass({
....
});
{
ReactDOM.render(
<MainApp />,
document.getElementById('mainAppCont')
);
let app = new MainApp();
}
My class files are
//file classes/User.js
class User{
constructor(){...}
...
}
And
//file classes/MainApplication.js
class MainApplication{
constructor(){...}
...
}
Before ask My Question, I have to say, When I load all js and jsx files via HEAD, it works.
My question is, why I can not load in this way via getScriptFile. Everything load except jsx file? Can you help me to solve this problem. I need to load via getScriptFile.
After all, HEAD is looking like this:
<head>
<meta charset="UTF-8">
<meta http-equiv="cache-control" content="max-age=0">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT">
<meta http-equiv="pragma" content="no-cache">
<title>Title</title>
<!-- CSS LIBS -->
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/bootstrap.css">
<link rel="stylesheet" href="css/bootstrap-theme.css">
<link rel="stylesheet" href="css/font-awesome.css">
<link rel="stylesheet" href="css/flags.css">
<!-- JS LIBS -->
<script src="js/jquery-1.12.2.min.js" defer=""></script>
<!-- added via getScript -->
<script src="js/jquery-ui.min.js"></script>
<script src="js/bootstrap.js"></script>
<script src="js/babel-core-5-8-34-browser.js"></script>
<script src="js/react-with-addons.js"></script>
<script src="js/react-dom.js"></script>
<script src="classes/User.js"></script>
<script src="classes/MainApplication.js"></script>
<script type="text/babel" src="jsx/mainReact.jsx"></script>
</head>
Line of code in JSX file, at top console.log("is ok in JSX???"); will not be executed...
All files are in place, and there are no any error in console.
:(
Thank you in advance!

How to load different pages in O365 mail app based on regex

I am creating an O365 app and I have 2 .aspx files, when the user clicks on the O365 mail app, I want each of these pages to be loaded based on the subject of the mail.
Scenario 1: Mail subject contains '#'
result: load page1
Scenario 2: Mail subject does not contain '#'
result: load page2
I have tried having an intermediate .js file where I have written the logic,
but when I do window.location = "path_to_aspx_file",
only the html is loaded but the js files do not run.
My current implementation:
I have LandingLogic.js
(function () {
"use strict";
//The Office initialize function must be run each time a new page is loaded
Office.initialize = function (reason) {
$(document).ready(function () {
var item = Office.cast.item.toItemRead(Office.context.mailbox.item);
var sub = item.subject;
if (sub.indexOf("some text") > -1) {
window.location = "http://localhost:51776/File1.aspx";
}
else {
window.location = "http://localhost:51776/File2.aspx";
}
});
};
})();
After a bit of fumbling around.
I am able to navigate to each of these files now, but I am not sure how to access the mail subject from File1.aspx and File2.aspx.
Did you initialize the Office context before you using Office JavaScript API to get the subject? To redirect the HTML page easily, we can include the JavaScript like below:
Home.js:
/// <reference path="../App.js" />
(function () {
"use strict";
// The Office initialize function must be run each time a new page is loaded
Office.initialize = function (reason) {
$(document).ready(function () {
app.initialize();
RedirectHTMLPage();
});
};
function RedirectHTMLPage() {
var subject = Office.context.mailbox.item.subject;
if (subject.indexOf("#") != -1) {
window.location.href = "https://localhost:44300/page1.aspx";
} else {
window.location.href = "https://localhost:44300/page2.aspx";
}
}
})();
The HTML page for redirecting:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<title></title>
<script src="../../Scripts/jquery-1.9.1.js" type="text/javascript"></script>
<link href="../../Content/Office.css" rel="stylesheet" type="text/css" />
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js" type="text/javascript"></script>
<!-- To enable offline debugging using a local reference to Office.js, use: -->
<!-- <script src="../../Scripts/Office/MicrosoftAjax.js" type="text/javascript"></script> -->
<!-- <script src="../../Scripts/Office/1/office.js" type="text/javascript"></script> -->
<link href="../App.css" rel="stylesheet" type="text/css" />
<script src="../App.js" type="text/javascript"></script>
<link href="Home.css" rel="stylesheet" type="text/css" />
<script src="Home.js" type="text/javascript"></script>
</head>
<body>
</body>
</html>
I have tried having an intermediate .js file where I have written the logic, but when I do window.load = "path_to_aspx_file", only the html is loaded but the js files do not run.
Would you mind sharing the detail you using the “window.load”?
Fei Xue answer is correct . if you want to get subject from file2.aspx , add office.js reference and access subject same as file1.aspx inside the Office.initialize event
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js" type="text/javascript"></script>

how can you determine location of <script> tag from inside said tag?

I am trying to figure out the location of the script tag the current javascript is running in. What is really going on is that I need to determine from inside a src'd, dynamically inserted javascript file where it is located in the DOM. These are dynamically generated tags; code snippet:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>where am i?</title>
<script type="text/javascript" charset="utf-8">
function byId(id) {
return document.getElementById(id);
}
function create_script(el, code) {
var script = document.createElement("script");
script.type = "text/javascript";
script.text = code;
el.appendChild(script);
}
</script>
</head>
<body>
<div id="find_me_please"></div>
<script>
create_script(byId("find_me_please"), "alert('where is this code located?');");
</script>
</body>
</html>
You could give the script an id tag, like this dude does...
You can use document.write to create a dummy DOM object and use parentNode to escape out. For example:
<script>
(function(r) {
document.write('<span id="'+r+'"></span>');
window.setTimeout(function() {
var here_i_am = document.getElementById(r).parentNode;
... continue processing here ...
});
})('id_' + (Math.random()+'').replace('.','_'));
</script>
This assumes you don't actually have control of the <script> tag itself, such as when it's inside a <script src="where_am_i.js"></script> - if you do have control of the <script> tag, simply put an ID on it, as in:
<script id="here_i_am">...</script>
If you are just running this on page load, this works
<script>
var allScripts = document.getElementsByTagName('script');
var thisScript = allScripts[allScripts.length];
alert(thisScript);
</script>

Categories