JSDOM not loading script files in Node - javascript

I am trying to do a test of loading up an html page in jsdom which will eventually generate graphs. I cannot overcome the first hurdle of just loading the html page and having the javascript execute.
Below is my html page which I am trying to load which doesnt take any parameters and just renders a simple graph.
<html>
<head>
<script src="http://code.jquery.com/jquery.min.js"/>
<script src="http://static.fusioncharts.com/code/latest/fusioncharts.js"/>
<script src="http://static.fusioncharts.com/code/latest/fusioncharts.charts.js"/>
<script src="http://static.fusioncharts.com/code/latest/themes/fusioncharts.theme.fint.js"/>
<script>
var testVar = true;
function test(){
testVar = false;
};
</script>
<script>
$(document).ready(function(){
FusionCharts.ready(function () {
var revenueChart = new FusionCharts({
type: 'column2d',
renderAt: 'container',
width: '400',
height: '200',
dataFormat: 'json',
dataSource: {
"chart": {
"caption": "Split of Revenue by Product Categories",
"subCaption": "2014",
"numberPrefix": "$",
"theme": "fint",
"captionFontSize": "13",
"subcaptionFontSize": "12",
"subcaptionFontBold": "0",
"showValues": "0"
},
"data": [{
"label": "Food",
"value": "28504"
}, {
"label": "Apparels",
"value": "14633"
}, {
"label": "Electronics",
"value": "10507"
}, {
"label": "Household",
"value": "4910"
}]
}
}).render();
});
var svg = $('#container').html();
});
</script>
<head>
<body>
<div id="container">Charts will render here</div>
</body>
Here is the code in node where I am trying to load this page..
var config = {
file: path.join(__dirname, "chart.html"),
features:{
FetchExternalResources: ["script"],
ProcessExternalResources: ["script"],
MutationEvents: '2.0'
},
scripts:[
"http://code.jquery.com/jquery.min.js",
"http://static.fusioncharts.com/code/latest/fusioncharts.js",
'http://static.fusioncharts.com/code/latest/fusioncharts.charts.js',
"http://static.fusioncharts.com/code/latest/themes/fusioncharts.theme.fint.js"
],
onload: function(err, window) {
console.log('*******onload')
},
created: function(err, window) {
console.log('*******created')
},
done: function(err, window) {
console.log('*******done')
if(err){
console.log('*****got err ' + err.message);
callback(err);
}
global.window = window;
console.log('inside done ----------')
var $ = window.jQuery || window.$,
FusionCharts = window.FusionCharts,
document = window.document;
if(typeof FusionCharts == 'undefined')
console.log('FusionCharts NOT LOADED')
else
console.log('FusionCharts LOADED')
if(typeof $ == 'undefined')
console.log('JQUERY NOT LOADED')
else
console.log('JQUERY LOADED')
console.log('testVar ' + window.testVar)
console.log(window.test())
console.log('testVar ' + window.testVar)
console.log('svg is ' + window.svg);
console.log($('#container').html());
window.close();
}
}
jsdom.env(config);
The strange thing here is that if i do not include scripts in the config object, it will not load them and make them available in the done callback even thought it is there on the html page.
Also, testVar is never defined in the callback even thought it is present in the page, the same with window.test(), even though its in the html page it just does not seem to be available in the callback.
I have tried all different variations of creating the jsdom object, but none of them allows the page to load the scripts rather than me passing it into the config object, and none of the different versions allow me to access variables and functions defined in the script tags.
Is there something I am missing ?

Change your script elements so that they are correct HTML:
<script src="http://code.jquery.com/jquery.min.js"></script>
If you do that everything will load fine and you won't have to use scripts in your configuration.

Related

Javascript not working after type change

I'm trying to implement the Insites Cookie Consent script (opt-in version) and load some javascript-scripts after a user has accepted cookies.
Implementing the script isn't a problem, but I keep ending up with no javascript loading. My cookieconsent code:
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.0.3/cookieconsent.min.css" />
<script src="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.0.3/cookieconsent.min.js"></script>
<script>
window.addEventListener("load", function(){
window.cookieconsent.initialise({
"palette": {
"popup": {
"background": "#252e39"
},
"button": {
"background": "#14a7d0"
}
},
"position": "bottom-left",
"type": "opt-in",
"content": {
"message": "This site uses cookies",
"dismiss": "I don't want cookies",
"allow": "I accept",
"link": "Privacy policy"
},
onInitialise: function (status) {
var type = this.options.type;
var didConsent = this.hasConsented();
if (type == 'opt-in' && didConsent) {
// enable cookies
$(".loadlaterscripts").attr("type", "text/javascript");
}
},
onStatusChange: function(status, chosenBefore) {
var type = this.options.type;
var didConsent = this.hasConsented();
if (type == 'opt-in' && didConsent) {
// enable cookies
location.reload();
}
},
})});
</script>
I implemented a few scripts and widgets with the following code:
<script type="text/plain" class="loadlaterscripts" src="//link-to.script/file.js"></script>
In the console I can see the type attribute changes to text/javascript successfully after accepting cookies, but none of the scripts will work after that. This happens for example to the Google Adsense script, but also simple embed-codes provided by websites.
Is there something I'm overlooking here?

Code Prints To DOM When Dynamically Inserting Inline Scripts With Javascript

I'm trying to insert a chart dynamically with javascript. I found an example of how to do such a thing and it almost works. The chart loads but then underneath the chart, part of the Javascript used to display the chart actually shows as text on the page. It otherwise works fine.
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<div id="tvTest"></div>
<script>
/* helpers
*/
// runs an array of async functions in sequential order
function seq (arr, callback, index) {
// first call, without an index
if (typeof index === 'undefined') {
index = 0
}
arr[index](function () {
index++
if (index === arr.length) {
callback()
} else {
seq(arr, callback, index)
}
})
}
// trigger DOMContentLoaded
function scriptsDone () {
var DOMContentLoadedEvent = document.createEvent('Event')
DOMContentLoadedEvent.initEvent('DOMContentLoaded', true, true)
document.dispatchEvent(DOMContentLoadedEvent)
}
/* script runner
*/
function insertScript ($script, callback) {
var s = document.createElement('script')
s.type = 'text/javascript'
if ($script.src) {
s.onload = callback
s.onerror = callback
s.src = $script.src
} else {
s.textContent = $script.innerText
}
// re-insert the script tag so it executes.
document.head.appendChild(s)
// clean-up
$script.parentNode.removeChild($script)
// run the callback immediately for inline scripts
if (!$script.src) {
callback()
}
}
// https://html.spec.whatwg.org/multipage/scripting.html
var runScriptTypes = [
'application/javascript',
'application/ecmascript',
'application/x-ecmascript',
'application/x-javascript',
'text/ecmascript',
'text/javascript',
'text/javascript1.0',
'text/javascript1.1',
'text/javascript1.2',
'text/javascript1.3',
'text/javascript1.4',
'text/javascript1.5',
'text/jscript',
'text/livescript',
'text/x-ecmascript',
'text/x-javascript'
]
function runScripts ($container) {
// get scripts tags from a node
var $scripts = $container.querySelectorAll('script')
var runList = []
var typeAttr
[].forEach.call($scripts, function ($script) {
typeAttr = $script.getAttribute('type')
// only run script tags without the type attribute
// or with a javascript mime attribute value
if (!typeAttr || runScriptTypes.indexOf(typeAttr) !== -1) {
runList.push(function (callback) {
insertScript($script, callback)
})
}
})
// insert the script tags sequentially
// to preserve execution order
seq(runList, scriptsDone)
}
$(document).ready(function()
{
var htmlContent = `<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
<script type="text/javascript">
new TradingView.widget({
"width": 500,
"height": 400,
"symbol": "BINANCE:AMBETH",
"interval": "60",
"timezone": "Etc/UTC",
"theme": "Dark",
"style": "1",
"locale": "en",
"toolbar_bg": "#f1f3f6",
"enable_publishing": false,
"allow_symbol_change": true,
"hideideas": true
});
</script>`;
var $container = document.querySelector('#tvTest');
$container.innerHTML = htmlContent;
runScripts($container);
});
</script>
</body>
</html>
If I run that, the chart displays and just underneath it, I see the code var $container = document.querySelector('#tvTest'); $container.innerHTML = htmlContent; runScripts($container); }); as text in the DOM. How can I get it to render the chart without printing any code to the DOM?
By default this trading view library appends to the body. You can override that by passing "container_id" property. Here is a simplified example of your code:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://s3.tradingview.com/tv.js"></script>
</head>
<body>
<div id="tvTest"></div>
<script type="text/javascript">
new TradingView.widget({
"container_id": "tvTest", // THIS IS THE LINE I ADDED
"width": 500,
"height": 400,
"symbol": "BINANCE:AMBETH",
"interval": "60",
"timezone": "Etc/UTC",
"theme": "Dark",
"style": "1",
"locale": "en",
"toolbar_bg": "#f1f3f6",
"enable_publishing": false,
"allow_symbol_change": true,
"hideideas": true
});
</script>
</body>
</html>
You need to escape the <\/script> inside of the string template

Using AJAX to retrieve data from JSON File

so I am trying to read the data from my JSON file and display it on the webpage using HTML. It would work with simple keys with this particular database it wouldn't work for me.
JSON:
var carInfo = [
{
carId: 1,
carPrice : 15.00,
},
{
carId: 2,
carPrice : 25.00,
}
];
JS:
$(document).ready(function() {
$.getJSON("vehicle_data.json", function(data) {
$.each(data.carInfo, function() {
$("ul").append("<li>Car ID: "+this[carInfo[0].carId]);
});
});
});
HTML:
<html>
<body>
<ul></ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="json_data_retrieve.js"></script>
</body>
</html>
It is not a valid JSON file. It is a JS script.
var carInfo = [
{
carId: 1,
carPrice : 15.00,
},
{
carId: 2,
carPrice : 25.00,
}
];
Try this:
{
"carInfo":
[
{
"carId": 1,
"carPrice": 15
},
{
"carId": 2,
"carPrice": 25
}
]
}
Update:
You may load this script as a script source in an HTML. It must be an .js file.
<script src="vehicle_data.js"></script>
If you need to load it dynamically, use jQuery $.getScript method.
It doesn't matter that it has .json extensions because it will be evaluated as a script.
$(document).ready(function()
{
$.getScript("vehicle_data.json", function()
{
// Pay attention. In this case, you work with carInfo
// variable because it has been executed as a script,
// but not loaded as a JSON file.
$.each(carInfo, function() {
$("ul").append("<li>Car ID: " + this[carInfo[0].carId]);
});
});
});
However, it is very strange that someone gives you .json file with JS declaration and tells you that you should execute it but shouldn't rename it or load as a script.
Looks like you are trying to iterate the parent object from within itself.
Try this
$.each(data.carInfo, function(k, v) {
$("ul").append("<li>Car ID: "+v.carId);
});

How can we consume JSON data using OPENUI5/SAPUI5?

I am new to SAPUI5/OPENUI5.
I am trying out a sample program to consume json data from a domain and display it in my openui5 table. I have tried two methods to get the data and bind it to table control.But I am not able to generate the table with the json data.
Please let me know my mistake in the code.
And also please refer me some links to understand the concept in a better way.
Thanks in advance.
Please find the two approaches below :
JSON Data :
[
{
"name": "Rajesh"
},
{
"name": "Kunal Jauhari"
},
{
"name": "Ashish Singh"
},
{
"name": "Ansuman Parhi"
},
{
"name": "Arup Kumar"
},
{
"name": "Deepak Malviya"
},
{
"name": "Seshu"
},
{
"name": "Ankush Datey"
},
{
"name": "Tapesh Syawaria"
},
{
"name": "Mahesh"
},
{
"name": "Vinay Joshi"
},
{
"name": "Ardhendu Karna"
},
{
"name": "Abhishek Shukla"
},
{
"name": "Kashim"
},
{
"name": "Vinayak"
}
]
Approach 1 : I am using a php file to echo the JSON data and use it in my ui5 screen.
When I access the run the php file individually, it generates the data and prints the data on screen.
Error I get is getJSON is not called.
Code :
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'/>
<script src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-libs="sap.ui.commons,sap.ui.table"
data-sap-ui-theme="sap_bluecrystal">
</script>
<!-- add sap.ui.table,sap.ui.ux3 and/or other libraries to 'data-sap-ui-libs' if required -->
<script>
var json_url = "http://mydomain/teamdetails_ui5.php?t=6";
$.ajax({
url : json_url,
jsonpCallback : 'getJSON',
contentType : "application/json",
dataType: 'jsonp',
success: function(data,textStatus,jqXHR) {
oModel.setData({data: data});
sap.ui.getCore().setModel(oModel);
var oTable1 = new sap.ui.table.Table({
title : "Players List",
visibleRowCount : 3,
selectionMode : sap.ui.table.SelectionMode.Single,
navigationMode : sap.ui.table.NavigationMode.Paginator,
});
//Define the columns and the control templates to be used
oTable1.addColumn(new sap.ui.table.Column({
label : new sap.ui.commons.Label({
text : "Player Name"
}),
template : new sap.ui.commons.TextView().bindProperty(
"text", "name"),
width : "10px"
}));
oTable1.setModel(oModel);
oTable1.bindRows("/oModel");
oTable1.placeAt('table_cont');
},
error : function(jqXHR,textStatus,errorThrown) {
alert("Oh no, an error occurred");
alert(jqXHR);
alert(textStatus);
alert(errorThrown);
}
});
</script>
</head>
<body class="sapUiBody" role="application">
<div id="table_cont"></div>
</body>
</html>
Approach 2 : I am trying to access the JSON file directly on my domain and access the data.
Code is the same as above except url.
Url is used for this approach is (mydomain/players.json) where players.json contain the above json data.
Please help me in understanding the concept of JSON data handling.
Regards,
Rajan
First of all: SAPUI5 is built onto jQuery, yes. But there should be no need to use jQuery inside your SAPUI5 Application.
Use a JSONModel to load JSON-Data. Also the JSONModel can load the data from URL.
See the Documentation
this will look like:
// create a "json" Model
var oModel = new sap.ui.model.json.JSONModel();
// load data from URL
oModel.loadData('http://mydomain/teamdetails_ui5.php?t=6');
after this you can register this model in your sap.ui.core with:
sap.ui.getCore().setModel(oModel);
after this line every control can use the data from this model by simple binding-syntax.
Now lets create the table:
// create your table
var oTable1 = new sap.ui.table.Table({
title : "Players List",
visibleRowCount : 3,
selectionMode : sap.ui.table.SelectionMode.Single,
navigationMode : sap.ui.table.NavigationMode.Paginator,
// bind the core-model to this table by aggregating player-Array
rows: '{/player}'
});
beware of the part with "rows: '{/player}'". This is the only thing that has to be done to get the data from the model inside your table.
now finish the demo by adding the column and add the table to the DOM:
// define the columns and the control templates to be used
oTable1.addColumn(new sap.ui.table.Column({
label : new sap.ui.commons.Label({
text : "Player Name"
}),
template : new sap.ui.commons.TextView({
text: '{name}'
}),
width : "10px"
}));
//place at DOM
oTable1.placeAt('content');
Thats it. If it doesn't work, here is a running DEMO.

Backbone JS multiple level navigation example

I'm trying to construct a solid Backbone JS experiment, where I have a local JSON data file which contains my pages (a project I'm doing has this sort of requirement anyhow). And I've coded this example so I can have endless nested subpages in the pages data. It seems to be working great. But when it comes to the URLs, I'm a little stuck.
How do I approach giving this multiple level navigation example totally dynamic URLs? What I mean is, correctly using the url property of the models and collections to construct the right URLs for all the top level and nested elements. Is it even possible? I just can't think how to do it.
See a live demo of where I am now:
http://littlejim.co.uk/code/backbone/multiple-level-navigation-experiment/
Just so it's easier, the source code is below...
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Multiple Level Navigation Experiment</title>
<script type="text/javascript" src="../../media/scripts/jquery-1.5.1.min.js"></script>
<script type="text/javascript" src="../../media/scripts/underscore-min.js"></script>
<script type="text/javascript" src="../../media/scripts/backbone-min.js"></script>
<script type="text/javascript" src="application.js"></script>
<script type="text/javascript">
// wait for the DOM to load
$(document).ready(function() {
App.initialize();
});
</script>
</head>
<body>
<div id="header">
<h1>Multiple Level Navigation Experiment</h1>
<p>Want to get this page structure pulled from JSON locally and have a fully functional multiple level nested navigation with correct anchors.</p>
</div>
<div id="article">
<!-- dynamic content here -->
</div>
</body>
</html>
content.json
{
"pages": [
{
"id": 1,
"title": "Home",
"slug": "home"
},
{
"id": 2,
"title": "Services",
"slug": "services",
"subpages": [
{
"id": 1,
"title": "Details",
"slug": "details",
"subpages": [
{
"id": 1,
"title": "This",
"slug": "this"
},
{
"id": 2,
"title": "That",
"slug": "that"
}
]
},
{
"id": 2,
"title": "Honest Service",
"slug": "honest-service"
},
{
"id": 3,
"title": "What We Do",
"slug": "what-we-do"
}
]
},
{
"id": 3,
"title": "Contact Us",
"slug": "contact-us"
}
]
}
application.js
// global app class
window.App = {
Data: {},
Controller: {},
Model: {},
Collection: {},
View: {},
initialize : function () {
$.ajax({
url: "data/content.json",
dataType: "json",
success: function(json) {
App.Data.Pages = json.pages;
new App.Controller.Main();
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
console.log(errorThrown);
}
});
}
}
// main controller class
// when called it should have 'data' in JSON format passed to it
App.Controller.Main = Backbone.Controller.extend({
initialize: function() {
var pagesCollection = new App.Collection.Pages(App.Data.Pages);
var pagesView = new App.View.Pages({collection: pagesCollection});
$('#article').html(pagesView.render().el);
}
});
// pages model class
App.Model.Page = Backbone.Model.extend({
initialize: function() {
if (!_.isUndefined(this.get("subpages"))) {
this.subpages = new App.Collection.Pages(this.get("subpages"));
} // end if
this.view = new App.View.Page({model: this});
},
});
// page collection class
App.Collection.Pages = Backbone.Collection.extend({
model: App.Model.Page
});
// single page view class
App.View.Page = Backbone.View.extend({
tagName: "li",
initialize: function() {
_.bindAll(this, "render");
},
render: function() {
$(this.el).html(_.template("<%=title%>", {title: this.model.get("title")}));
return this;
}
});
// multiple pages view class
App.View.Pages = Backbone.View.extend({
tagName: "ul",
initialize: function() {
_.bindAll(this, "render");
},
render: function() {
var that = this;
this.collection.each(function(page) {
$(that.el).append(page.view.render().el);
if (!_.isUndefined(page.subpages)) {
var subpagesView = new App.View.Pages({collection: page.subpages});
$(that.el).append(subpagesView.render().el);
} // end if
});
return that;
}
});
I'm just needing so right direction on how to do the URLs properly. The idea I'm wanting is that I can setup my controller for routes so it can expect any page of any nested level. The models, collections and nested collections should be able to generate their URLs on their own, but the hash URL must reflect the level.
Ideally, this navigation would go to URLs like these:
http://example.com/#pages/services
http://example.com/#pages/services/details
http://example.com/#pages/services/details/this
...the URLs using the "slug" from the content.json data. Does any of this make sense? I'm pretty new to Backbone JS and just want to do things right.
Thanks, James
Here's my favorite solution to this problem: use PathJS !
Why not just parse out the slug?
So you can have a single route in the Backbone.Controller that looks like this:
'pages/:id' : showPage
And then showPage looks like:
showPage(id) : function(id) {
parse out the string 'services/details/etc'
look up the slug data based on that IE pages['services']['details']['etc']
}
or if the pages actually need to be processed differently, you can setup multiple routes, ever more granular like this:
'pages/:id' : showPage
'pages/:id/:nest' : showNestedPage
'pages/:id/:nest/:more' : showNestedMorePage

Categories