Adding a javascript line to a ruby site written in slim - javascript

I was given a javascript line that calls a javascript file which is made by a company called walkme.
I have an app/assets/javascript/application.js file that calls all of my jquery that I am using for the site. for example it contains:
require feed
which calls feed.js when someone is on the feed page. I would like the walkme.js to also be called at the same time this code is called
I am looking for a way to add this <script ... code to a ruby site that uses slim and jquery.
<script type="text/javascript">(function() {var walkme = document.createElement('script'); walkme.type = 'text/javascript'; walkme.async = true; walkme.src = 'https://cdn.walkme.com/thewalkme.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(walkme, s); window._walkmeConfig = {smartLoad:true}; })();</script>
I have tried a blunt style of just making a walkme.js in the same place as the feed.js and putting that <script ... code in that file while adding the necessary require walkme code, but that seems to do nothing.
Some info:
Ruby on Rails
Ruby 2.1.7p400
ubuntu 14.04 LTS server
some files are named *.html.slim
As you may be able to tell, I did not make all the ruby code and am not an expert in ruby, javascript or jquery.
If this was just an html site, I think could just add the line of code to the header.

Mostly, Javascripts are called after the page has finished loading, since you want to manipulate the DOM, most likely.
So, you either don't want to call the script in the head of your document, unless you have a document.ready in the script.
To answer your question then, if you want the following script:
function(){
var walkme = document.createElement('script');
walkme.type = 'text/javascript';
walkme.async = true;
walkme.src = 'https://cdn.walkme.com/thewalkme.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(walkme, s);
window._walkmeConfig = {smartLoad:true};
};
to be available only on the feed page of your application,
You can make this function a named function, in a separate file (say feed.js.coffee for example) and call the function in your slim view page as follow:
//feed.js.coffee:
#feed = ->
walkme = document.createElement('script')
walkme.type = 'text/javascript'
walkme.async = true
walkme.src = 'https://cdn.walkme.com/thewalkme.js'
s = document.getElementsByTagName('script')[0]
s.parentNode.insertBefore walkme, s
window._walkmeConfig = smartLoad: true
return
and in your view:
/feed.html.slim:
...
your codes...
...
coffeeview:
feed

Related

How to access to external scripts loaded by javascript via script element

I want to create my own asset loader. To load external scripts, I used following javascript
function loadScript(src, callback) {
var script = document.createElement("script");
script.onload = function() {
document.head.appendChild(script);
callback();
};
script.src = src;
}
But I think this isn't the most elegant solution. This code snippet would make my HTML code ugly since it appends code to the head - for all of my dependencies.
So my question: is it possible to access to my external loaded code without using following line
document.head.appendChild(script);
Am I able to executes my script with pure js like
script.execute();
Or even better, is there a way to access to the data stored in my external js file? Like variable "bar", for example?
var foo = script.get("bar")
Could I even execute a function of the external file?
script.function(params)
It would be great to hear of your ideas and experiences!
Darth Moon
Edit: I forgot to exclude ajax. I know I could load code via ajax and executes it via eval(), but that won't be a good idea if you're testing code local since you need a Server (like an XAMPP Apache) to send ajax request to your local files.
You could try something like so as below.
Internal script:
function appendScript(src) {
var script = document.createElement(‘script’);
script.src = src;
document.head.appendChild(script);
}
External script:
function loadedScript() {
// run something
}
loadedScript()
The external code will just run loadedScript() once the file is loaded.

Can I use JavaScript to change the JavaScript files a HTML document accesses?

I am trying to write a HTML page that asks users a series of questions. The answers to these questions are evaluated by my JavaScript code and used to determine which additional JavaScript file the user needs to access. My code then adds the additional JavaScript file to the head tag of my HTML page. I don't want to merge the code into a single JavaScript file because these additional files are large enough to be a nightmare if they're together, and I don't want to add them all to the head when the page first loads because I will have too many variable conflicts. I'm reluctant to redirect to a new webpage for each dictionary because this will make a lot of redundant coding. I'm not using any libraries.
I begin with the following HTML code:
<head>
<link rel="stylesheet" type="text/css" href="main.css">
<script src="firstSheet.js" type="text/JavaScript"></script>
</head>
//Lots of HTML.
<div id="mainUserMenu">
</div>
And I have the following JavaScript function:
function thirdLevelQuestions(secondLevelAnswer) {
//Code here to calculate the variables. This part works.
activeDictionary = firstKey + secondKey + '.js';
//Changing the HTML header to load the correct dictionary.
document.head.innerHTML = '<link rel="stylesheet" type="text/css" href="main.css"><script src="' + activeDictionary + '" type="text/JavaScript"></script><script src="firstSheet.js" type="text/JavaScript"></script>';
//for loop to generate the next level of buttons.
for (var i = 0; i < availableOptions.length; i++) {
document.getElementById('mainUserMenu').innerHTML += '<button onclick="fourthLevelQuestions(' + i + ')">' + availableOptions[i] + '</button>';
}
}
This creates the buttons that I want, and when I inspect the head element I can see both JavaScript files there. When I click on any of the buttons at this level they should call a function in the second file. Instead Chrome tells me "Uncaught ReferenceError: fourthLevelQuestions is not defined" (html:1). If I paste the code back into firstSheet.js the function works, so I assume the problem is that my HTML document is not actually accessing the activeDictionary file. Is there a way to do this?
What Can be done
You are trying to load Javascript on Demand. This has been a well thought out problem lately and most of the native solutions didn't work well across bowser implementations. Check a study here with different solutions and background of the problem explained well.
For the case of large web applications the solution was to use some javascript library that helped with modularising code and loading them on demand using some script loaders. The focus is on modularizing code and not in just script loading. Check some libraries here. There are heavier ones which includes architectures like MVC with them.
If you use AJAX implementation of jQuery with the correct dataType jQuery will help you evaluate the scripts, they are famous for handling browser differences. You can as well take a look at the exclusive getScript() which is indeed a shorthand for AJAX with dataType script. Keep in mind that loading script with native AJAX does not guarantee evaluation of the javascript included, jQuery is doing the evaluation internally during the processing stage.
What is wrong
What you have done above might work in most modern browsers (not sure), but there is an essential flaw in your code. You are adding the script tags to your head using innerHTML which inserts those lines to your HTML. Even if your browser loads the script it takes a network delay time and we call it asynchronous loading, you cannot use the script right away. Then what do you do? Use the script when its ready or loaded. Surprisingly you have an event for that, just use it. Can be something like:
var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.type= 'text/javascript';
script.onreadystatechange= function () {
if (this.readyState == 'complete') helper();
}
script.onload= helper;
script.src= 'helper.js';
head.appendChild(script);
Check this article for help with implementation without using external libraries
From the variable name activeDictionary If I guess that you are loading some data sets as opposed to javascript programs, you should try looking into JSON and loading and using them dynamically.
If this Question/Answer satisfies your needs, you should delete your question to avoid duplicate entries in SO.
The best way to achieve this would be with jQuery:
$(document).ready(function() {
$('#button').click(function() {
var html = "<script src='newfile.js' type='text/javascript'></script>";
var oldhtml = "<script src='firstSheet.js' type='text/javascript'></script>";
if ($(this).attr('src') == 'firstSheet.js') {
$('script[src="firstSheet.js"]').replace(html);
return;
}
$('script[src="newfile.js"]').replace(oldhtml);
});
});
I would suggest you create the elements how they should be and then append them. Also, if you are dynamically adding the firstSheet.js you shouldn't include it in your .html file.
function thirdLevelQuestions(secondLevelAnswer) {
var mainUserMenu = document.getElementById('mainUserMenu');
activeDictionary = firstKey + secondKey + '.js';
var css = document.createElement('link');
css.rel = 'stylesheet';
css.type = 'text/css';
css.href = 'main.css';
var script1 = document.createElement('script');
script1.type = 'text/javascript';
script1.src = 'firstSheet.js';
var script2 = document.createElement('script');
script2.type = 'text/javascript';
script2.src = activeDictionary;
document.head.appendChild(css);
document.head.appendChild(script1);
document.head.appendChild(script2);
for (var i = 0; i < availableOptions.length; i++) {
var btn = document.createElement('button');
btn.onclick = 'fourthLevelQuestions(' + i + ')';
var val = document.createTextNode(availableOptions[i]);
btn.appendChild(val);
mainUserMenu.appendChild(btn);
}
}

Asynchronous PHP page loading within javascript tags

I have the following tag which loads a PHP and I need it to be loaded asynchronously thus everything in the containing page is load even if the called PHP file takes longer to return the value (or even is server is down).
<script language="JavaScript"
src="http://www.server.com/phpfile.php">
</script>
I've tried replacing it with the code use by FB and other methods for JS asynchronous loading but it does not work. The issue is that in this case it is a PHP file the one that is called, not a JS file.
I tried the following but it does not work when the called PHP script plugs HTML code (such as a div with an image) with document.write:
<script language="JavaScript">
(function () {
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true; s.src = 'server.com/phpfile.php';
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
})();
</script>
Any ideas?
Thank you.

How to prevent cross domain javascript loading with .htaccess?

The company which developped my website just added this javascript code on the Zend Guard encrypted index.php file (I saw it with "View source") :
(function ()
{
var smrs = document.createElement("script");
smrs.type = "text/javascript";
smrs.async = true;
smrs.src = document.location.protocol + "//www.domain.com/file.js";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(smrs, s);
})();
It injects a very agressive javascript code which adds a image link to their website (with a SetInterval each 10sec), at the bottom of the page.
The problem ? A local competitor, which is currently being accused of significant fraud, have the same CMS and the same image link.
Being associated with that competitor is prejudicial for me. I would like to know if there is a way to block the "www.domain.com/file.js" loading with a .htaccess.
Thanks.
You can't (using htaccess). This javascript creates a script tag to load the external javascript. The call never passes through the server. So apache (htaccess) can't block that.
The easiest way is to search in the source code and remove the script (if you have access).
UPDATE:
I see the script is encrypted... If you can insert a script at the very beginning (before the code gets executed you can create a hook on the insertBefore method. Here is a working fiddle
var ALLOWED_DOMAINS = ['www.klaartjedevoecht.be', 'jsfiddle.net'];
function creatHook(){
function getDomain(url) {
return url.match(/:\/\/(.[^/]+)/)[1];
}
var insertBefore = Element.prototype.insertBefore;
Element.prototype.insertBefore = function(new_node,existing_node){
if(new_node.tagName.toLowerCase() === 'script' && ALLOWED_DOMAINS.indexOf(getDomain(new_node.src)) > -1){
insertBefore.call(this, new_node, existing_node);
}
}
}
creatHook();
//TESTING CODE:
var smrs = document.createElement("script");
smrs.type = "text/javascript";
smrs.async = true;
smrs.src = document.location.protocol + "//www.klaartjedevoecht.be/test.js";
//var smrs = document.createElement("img");
// smrs.src= "http://img52.imageshack.us/img52/7653/beaverl.gif";
var s = document.getElementsByTagName("div")[0];
s.parentNode.insertBefore(smrs, s);
​I agree it's a bit hacking, but at least its cleaner then the timer solution. If you can't remove it, there is no clean solution.

How can I run a fallback copy of jQuery after the DOM is loaded?

The following are the first lines of code in a <script> tag just above the closing body tag in my document (it specifies that a locally-served copy of jQuery is run in the event that Google's CDN fails):
if(!window.jQuery){
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = '/js/jquery.js';
var scriptHook = document.getElementsByTagName('script')[0];
scriptHook.parentNode.insertBefore(script, scriptHook);
}
jQuery(document).ready(function($){
// page behaviors
});
It does execute successfully, in the sense that if my computer is not connected to the Internet (this is a locally-served page), the local copy of jQuery is inserted. However, the document.ready() section below does not execute. I'm guessing this is because it is invoked before the fallback copy of jQuery takes effect. What's the proper practice for somehow "delaying" its execution so that either copy of jQuery will work properly?
Consider using an existing script loader such as yepnope. There's an example of exactly what you're trying to do on the home page.
You need to be sure that the script you are appending to the dom has finished loading before calling jQuery. You can do this with the technique described here:
if(!window.jQuery){
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = '/js/jquery.js';
script.onreadystatechange= function () {
if (this.readyState == 'complete') jQueryLoaded();
}
script.onload = jQueryLoaded;
var scriptHook = document.getElementsByTagName('script')[0];
scriptHook.parentNode.insertBefore(script, scriptHook);
}
function jQueryLoaded() { };
You can also fetch the jQuery contents as an Ajax request, create a script tag with those as the body of the script and append it. That would also work.
Try that
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.6.2.min.js"><\/script>')</script>
<script>
jQuery(document).ready(function($){
// page behaviors
});
</script>
This way the script tag will be loaded synchronously.
The question "of how do I cope with my CDN failing and load a file hosted on my server" seems to come up a few times lately.
Question I'd ask is whether adding yet more js is the way to achieve the resilience and what level of resilience do the js approaches really add e.g. if the CDN is down they'll be a quick failure but how well do these approaches if the CDN is slow to respond how well do these solutions cope?
An alternative way to approach this is treat it as an infrastructure problem...
Run a CDN based on a domain/sub-domain you own. Have automated monitoring on it's availability, when it fails switch the DNS over to a backup server (anycast may provide an alternative solution too)
A php solution would be something like this:
$google_jquery = 'https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js';
$fp = #fsockopen($google_jquery, 'r');
if (!$fp)
{
echo '<script type="text/javascript" src="js/jquery.js"></script>';
}
else
{
echo '<script src="'.$google_jquery.'"></script>' }
}

Categories