I have a file called index.html that is supposedly display a map by executing this line : Controller.startup(notauth);. I have made sure that the logic comes to this line.
Somehow the map wont appear and i find out in the Chrome debugger that there are some calls to a wrong JS scripts path.
Here I include some lines from my index.html :
<script type="text/javascript">
var dojoConfig = {
async: true,
packages: [{
name: 'viewer',
location: location.pathname.replace(/[^\/]+$/, '') + 'js/viewer'
},{
name: 'config',
location: location.pathname.replace(/[^\/]+$/, '') + 'js/config'
},{
name: 'gis',
location: location.pathname.replace(/[^\/]+$/, '') + 'js/gis'
}]
};
</script>
<script type="text/javascript" src="http://10.255.1.77/sonar/arcgis_js_api/library/3.15/3.15/init.js"></script>
<script type="text/javascript">
//Get app ID from url
var file = 'config/viewer', s = window.location.search, q = s.match(/config=([^&]*)/i);
//alert ('var file ORI (config/viewer) : ' + file);
//alert ('nilainya Q : ' + q);
if (q && q.length > 0) {
file = q[1];
//alert ('Q1 : ' + file);
//alert ('S : ' + s);
if(file.indexOf('/') < 0) {
configfile = 'config/' + file;
}
//alert ('CONFIG-FILE : ' + configfile);
}
if (configfile == 'config/all')
{
//alert ('config == ALL');
//alert ('configfile is ' + configfile + ' -- strpathfile : ' + strpathfile);
if (ImgStatus && checkfileimg_js(strpathfile)) {
require(['viewer/Controller', configfile + '_imagery'], function(Controller, config){
Controller.startup(config);
});
}
else
{
alert ('controller.startup(notauth) Hellow NOAUTH ');
require(['viewer/Controller', 'config/all'], function(Controller, notauth)
{
Controller.startup(notauth);
});
}
}
else //IF configfile <> ALL (env,pims,clear dll)
{
Controller.startup(auth);
}
When i debug it in Chrome, I have the following results :
- result 1 : https://snag.gy/g37joA.jpg
- result 1 : https://snag.gy/aBMren.jpg
The correct path should be "http://10.255.1.77/sonar/arcgis_js_api/library/3.15/3.15/dijit/TitlePane.js"
NOT http://10.255.1.77/sonar/arcgis_js_api/library/3.15/dijit/TitlePane.js
Where are those JS coming from ? I cant find them being called in my index.html. Where and how can i find lines that calls these JS scripts ?
Please help
You can find this information in Chrome DevTools, tab Network, column Initiator:
You have to configure correctly the HOSTNAME_AND_PATH_TO_JSAPI in your init.js and dojo.js (inside esri js api),
should look like in both init.js and :
http://10.255.1.77/sonar/arcgis_js_api/library/3.15/3.15/
Where are those JS coming from ?
The scripts are laoded asynchronously ( see Modern dojo AMD )
require(['viewer/Controller'], function(controller)) ...
this will search for viewer (depends on config dojo created on top)your_app_url/js/viewer/Controller.js and load it in script and register it ,
also every require inside your controller will load scripts asynchronously , this modern AMD will prevent import unused modules (modular loading) .
Related
I'm using backbone to manage my routing. I need to implement multi-language on my website as following :
in french : www.example.com
in english : www.example.com/en
Moreover I have an additional root on my url on production, so it gives www.example.com/dev or www.example.com/dev/en
The root is provided through my web server (node). It's retrieved through the <%- prefix %> variable in the example below.
It works well on localhost, but as soon as I pass on my server with a url with the additional root, the pages are not found. I'm looking for a generic solution to manage both situations (with or without root).
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
<script type="text/javascript">
window.onload = function()
{
let prefix = '<%- prefix %>'.substr(1);
var BaseRouter = Backbone.Router.extend({
routes: {
[prefix + 'imgfocus/:imgid'] : 'imgfocus',
[prefix + 'skymap/:obsids'] : 'skymap',
// ...
},
imgfocus : function(imgid)
{
navservice.loadScreen({page : 'imgfocus', imgid : imgid});
},
skymap : function(obsids, stateid, tourid)
{
navservice.loadScreen({page : 'skymap', obsids : parseInt(obsids) === 0 ? undefined : obsids, stateid : stateid, tourid : tourid});
},
/// ...
});
let br = new BaseRouter();
for (let i = 0; i < navservice.languages.length; i++)
{
if (navservice.languages[i] !== '')
{
for (let key in br.routes)
{
br.routes[navservice.formatUrl(key, navservice.languages[i]).substr(1)] = br.routes[key];
}
}
}
// language retrieval
var language = navservice.getUserLanguage();
Backbone.history.start({pushState : true, root: '/' + (language ? language : '')});
}
$(document).on("click", "a:not([data-bypass])", function (evt) {
var href = { prop: $(this).prop("href"), attr: $(this).attr("href") };
var root = location.protocol + "//" + location.host + Backbone.history.options.root;
if (href.prop && href.prop.slice(0, root.length) === root) {
evt.preventDefault();
var route = href.attr;
// language retrieval
var lang = navservice.getUserLanguage(route);
if(lang && route.slice(0,lang.length+1) === "/" + lang) {
route = route.slice(lang.length+1);
}
Backbone.history.navigate(route, {trigger : true});
}
});
}
</script>
Create differents templates, then use history root option:
Backbone.history.start({pushState: true, root: "/en/"})
More info backbone history start.
Actually I managed to fix it by adding log inside backbone.js and checking what was going on.
The real issue was in the usage of 'prefix' variable in the routes definition. I removed it and most of the fix was done.
I have a PhantomJS script that goes through folders in my file system and takes screenshots of HTML pages.
Because of window size and a variety of issues explained here I've opted to place the HTML file in an Object of the width and height of my choosing and then take a screenshot of that instead.
If I create a basic HTML file with an object with a relative data URL and open it in my browser, it works perfectly.
Here's an overview of my file structure.
.
├── dist
| ├── page_one
| └── page_one.html
| └── page_two
| └── page_two.html
└── tools
└── screenshot.js
The code below, is saved in a file I call screenshot.js. I want to be able to run this through PhantomJS. It essentially reads through a comma separated string of directories (eg page_one,page_two), navigates to those pages, takes a screenshot and moves onto the next one. But despite the fact that the HTML generated is the same as the test file I created earlier, the screenshots are always blank.
If I replace the relative data URL with an absolute path, the script works perfectly, but obviously this isn't very re-usable if the file path has to be changed for every project.
I've tried using a number of ../ before the relative data url, but this still doesn't work.
var args = require('system').args,
resourceWait = 300,
maxRenderWait = 10000,
filesbefore = "page_one,page_twoK",
files = filesbefore.split(','),
mode = 'iframe',
page = require('webpage').create(),
count = 0,
forcedRenderTimeout,
renderTimeout;
page.viewportSize = { width: 1024, height : 768 };
function doRender() {
page.render(filename);
next();
}
page.onResourceRequested = function (req) {
count += 1;
clearTimeout(renderTimeout);
};
page.onResourceReceived = function (res) {
if (!res.stage || res.stage === 'end') {
count -= 1;
if (count === 0) {
clearTimeout(forcedRenderTimeout);
renderTimeout = setTimeout(doRender, resourceWait);
}
}
};
page.onConsoleMessage = function (msg) {
console.log("from page: " + msg);
};
function evaluateJsWithArgs(func) {
var args = [].slice.call(arguments, 1);
var fn = "function() { return (" + func.toString() + ").apply(this, " + JSON.stringify(args) + "); }";
return page.evaluate(fn);
};
function next(error) {
if(!error) {
if (files.length == 0){
phantom.exit();
}else{
takeScreenshot(files.pop());
}
}
}
function takeScreenshot(file){
var url = 'dist/' + file + '/' + file + '.html';
filename = file + '.png';
page.open('about:blank', function (status) {
if (status !== "success") {
console.log('Unable to load url');
phantom.exit();
} else {
page.includeJs(
"https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js",
function() {
evaluateJsWithArgs(
function(url, w, h) {
console.log(url);
$('body')
.css({margin: 0, padding: 0})
.html('<object style="background: red;" data="../' + url + '" width="'+ w + '" height="' + h + '" id="screen-frame" />');
console.log($('body').html());
},
url,
page.viewportSize.width,
page.viewportSize.height
);
}
);
forcedRenderTimeout = setTimeout(function () {
doRender();
}, maxRenderWait);
}
});
}
takeScreenshot(files.pop());
Please can someone tell me why this doesnt work.
Thanks in advance.
-
Note: If you'd like to run this locally, then create a basic file structure like mine above, download PhantomJS, cd to root directory of the project and run phantomjs tools/screenshot.js.
-
EDIT
After searching I've found this Q&A. So to my understanding, PhantomJS just can't open local files when using a relative path.
Having an absolute path isn't a suitable option as it will never always be the same.
The only other option I can find at the moment is to put the files on a local server and then run the script from the server URL.
Is there a way to save the current webpage by using casperjs or phantomjs?
I tried to get the html and save it into a file. But the resulting file was a lot different from the screenshot of that time (with casper.capture). Is there a way to save the current webpage?
Andrey Borisko suggested to use the disk cache to retrieve the resources. My solution is not that efficient, but you don't need to decompress text files.
I use XMLHttpRequest to retrieve all resources after I registered them with the resource.received event handler. I then filter the resources into images, css and fonts. The current limitation is that remote resource paths that contain something like ../ or ./ are not handled correctly.
I retrieve the current page content with getHTML and iterate over all captured resources to replace the path used in the markup, that is identified by a portion of the complete resource URL, with a randomly generated file name. The file extension is created from the content type of the resource. It is converted using mimeType from this gist.
Since CSS files may contain background images or fonts, they have to be processed before saving to disk. The provided loadResource function loads the resource, but does not save it.
Since XMLHttpRequest to download the resources the script has to be invoked with the --web-security=false flag:
casperjs script.js --web-security=false
script.js
var casper = require("casper").create();
var utils = require('utils');
var fs = require('fs');
var mimetype = require('./mimetype'); // URL provided below
var cssResources = [];
var imgResources = [];
var fontResources = [];
var resourceDirectory = "resources";
var debug = false;
fs.removeTree(resourceDirectory);
casper.on("remote.message", function(msg){
this.echo("remote.msg: " + msg);
});
casper.on("resource.error", function(resourceError){
this.echo("res.err: " + JSON.stringify(resourceError));
});
casper.on("page.error", function(pageError){
this.echo("page.err: " + JSON.stringify(pageError));
});
casper.on("downloaded.file", function(targetPath){
if (debug) this.echo("dl.file: " + targetPath);
});
casper.on("resource.received", function(resource){
// don't try to download data:* URI and only use stage == "end"
if (resource.url.indexOf("data:") != 0 && resource.stage == "end") {
if (resource.contentType == "text/css") {
cssResources.push({obj: resource, file: false});
}
if (resource.contentType.indexOf("image/") == 0) {
imgResources.push({obj: resource, file: false});
}
if (resource.contentType.indexOf("application/x-font-") == 0) {
fontResources.push({obj: resource, file: false});
}
}
});
// based on http://docs.casperjs.org/en/latest/modules/casper.html#download
casper.loadResource = function loadResource(url, method, data) {
"use strict";
this.checkStarted();
var cu = require('clientutils').create(utils.mergeObjects({}, this.options));
return cu.decode(this.base64encode(url, method, data));
};
function escapeRegExp(string) {
// from https://stackoverflow.com/a/1144788/1816580
return string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}
function replaceAll(find, replace, str) {
// from https://stackoverflow.com/a/1144788/1816580
return str.replace(find, replace);
}
var wrapFunctions = [
function wrapQuot1(s){
return '"' + s + '"';
},
function wrapQuot2(s){
return "'" + s + "'";
},
function csswrap(s){
return '(' + s + ')';
}
];
function findAndReplace(doc, resources, resourcesReplacer) {
// change page on the fly
resources.forEach(function(resource){
var url = resource.obj.url;
// don't download again
if (!resource.file) {
// set random filename and download it **or** call further processing which in turn will load ans write to disk
resource.file = resourceDirectory+"/"+Math.random().toString(36).slice(2)+"."+mimetype.ext[resource.obj.contentType];
if (typeof resourcesReplacer != "function") {
if (debug) casper.echo("download resource (" + resource.obj.contentType + "): " + url + " to " + resource.file);
casper.download(url, resource.file, "GET");
} else {
resourcesReplacer(resource);
}
}
wrapFunctions.forEach(function(wrap){
// test the resource url (growing from the back) with a string in the document
var lastURL;
var lastRegExp;
var subURL;
// min length is 4 characters
for(var i = 0; i < url.length-5; i++) {
subURL = url.substring(i);
lastRegExp = new RegExp(escapeRegExp(wrap(subURL)), "g");
if (doc.match(lastRegExp)) {
lastURL = subURL;
break;
}
}
if (lastURL) {
if (debug) casper.echo("replace " + lastURL + " with " + resource.file);
doc = replaceAll(lastRegExp, wrap(resource.file), doc);
}
});
});
return doc;
}
function capturePage(){
// remove all <script> and <base> tags
this.evaluate(function(){
Array.prototype.forEach.call(document.querySelectorAll("script"), function(scr){
scr.parentNode.removeChild(scr);
});
Array.prototype.forEach.call(document.querySelectorAll("base"), function(scr){
scr.parentNode.removeChild(scr);
});
});
// TODO: remove all event handlers in html
var page = this.getHTML();
page = findAndReplace(page, imgResources);
page = findAndReplace(page, cssResources, function(cssResource){
var css = casper.loadResource(cssResource.obj.url, "GET");
css = findAndReplace(css, imgResources);
css = findAndReplace(css, fontResources);
fs.write(cssResource.file, css, "wb");
});
fs.write("page.html", page, "wb");
}
casper.start("http://www.themarysue.com/").wait(3000).then(capturePage).run(function(){
this.echo("DONE");
this.exit();
});
The magic happens in findAndReplace. capturePage is completely synchronous so it can be dropped anywhere without much head ache.
URL for mimetype.js
No, I don't think there is an easy way to do this as phantomjs doesn't support rendering pages in mht format (Render as a .mht file #10117). I believe that's what you wanted.
So, it needs some work to accomplish this. I did something similar, but i was doing it the other way around I had a rendered html code that I was rendering into image/pdf through phantomjs. I had to clean the file first and it worked fine for me.
So, what I think you need to do is:
strip all js calls, like script tags or onload attributes, etc..
if you have access from local to the resources like css, images and so on (and you don't need authentication to that domain where you grab the page) than you need to change relative paths of src attributes to absolute to load images/etc.
if you don't have access to the resources when you open the page then I think you need to implement similar script to download those resources at the time phantomjs loads the page and then redirect src attributes to that folder or maybe use data uri.
You might need to change links in css files as well.
This will bring up the images\fonts and styling you are missing currently.
I'm sure there are more points. I'll update the answer if you need more info, once I see my code.
I'm trying to create a simple HTML page that will basically, load up some javascript, and check my direction (../Files)
the Files folder contains
file_001.txt
file_002.txt
file_003.txt
I then want javascript to use the latest one (file_003.txt), and update a anchor tag with the id of "file_download".
Would anyone by any chance have an idea how to do this?
The reason is, lets say I have a terms and conditions PDF file that is T&C_001.pdf and download the line a new terms and conditions is released. so we keep the T&C_001.pdf for any old records and we upload T&C_002.pdf. Now this will not need any HTML knowledge or even Javascript. The owner of the site would just need to add a new file with 002 on the end.
though, not fully accurate, you could try
<script type="text/javascript">
function getLatest(location, filename, ext, readyCallback, index) {
var tgIndex = typeof index === 'undefined' ? 1 : index;
$.ajax({
type: 'HEAD',
url: location + '/' + filename + '-' + index + '.' + ext,
success: function() {
getLatest(location, filename, ext, readyCallback, tgIndex + 1);
},
error: function() {
if (tgIndex > 1) {
readyCallback(location + '/' + filename + '-' + (tgIndex-1) + '.txt');
return;
}
readyCallback();
}
});
}
getLatest('linkToSite', 'file', 'txt', function(filename) {
if (typeof filename === 'undefined') {
alert('No file found on the location');
}
// do something with returned filename
});
</script>
which would try to check if the file is there, when not the previous index was the latest one. If the first one fails, there is no file on the specified location
This reply doesn't add formatting, and rather expects the files as:
- file-1.txt, file-2.txt, ...
this example assumes jquery :)
a fiddle of it you can find here
http://jsfiddle.net/Icepickle/JL5Su/
I have reorganized my directory structure and my php file is not being used/called. It's as if I can't access it. My functions and the php file were working as expected before this and my file permissions are sorted out so can someone lead me in the right direction?
The directory is as follows:
public_html(folder)
- javascript(folder)
- main(folder)
- userManagement.js => The `tryEmail` function is in here.
- php(folder)
- users-profs(folder)
- tryEmail.php
- index.html
The code:
function tryEmail(email)
{
console.log("function:tryEmail, param: " + email);
return function()
{
$.post("../../php/users-profs/tryEmail.php",
{
email:email
},
function(data)
{
console.log("function:tryEmail-post, data: " + data);
if(data == "valid")
return true;
else
return false;
});
}
}
The URL ../../php/users-profs/tryEmail.php will be interpreted relative to the user's current URL, not the URL of the .js file. Match the URL in $.post() to the URL where you will invoke this script, and it will be fine.
Edit based on comment: Add a slash: /php/users-profs/tryEmail.php -- without it, it's a relative URL, so it's looking in the wrong place.
Also, you need to remove the anonymous wrapper function, because you can't return an anonymous function, and it won't execute anyway. Your code should look like this:
function tryEmail(email)
{
console.log("function:tryEmail, param: " + email);
$.post("/php/users-profs/tryEmail.php", // fixed the leading / here
{
email:email
},
function(data)
{
console.log("function:tryEmail-post, data: " + data);
if(data == "valid")
return true;
else
return false;
});
}
instead of
"../../php/users-profs/tryEmail.php"
use your project's base url and then concatenate your file location to it like
<your_project_base_url> + 'php/users-profs/tryEmail.php'