how to navigate between pages using phantomjs - web-scraping

I want to navigate between pages inside the same page.open(url, function(status) { } using only phantomjs. Is that possible?
Example:
page.open(url, function(status) {
page.includeJs("https://code.jquery.com/jquery-3.0.0.slim.min.js", function() {
var response = page.evaluate(function() {
..code..
window.location.replace('new url');
..code for new url..
return response;
});
console.log(response);
phantom.exit();
});
});
Any help is appreciated.

I just figure out that the best option to do that is use casperjs.
casperjs.org

Related

Fullcalendar 4.x - Adding header "X-Requested-With: XMLHttpRequest"

Using Fullcalendar 4.x, is it possible to add the "X-Requested-With: XMLHttpRequest" header when fetching events ?
I'm setting up the event source in this way :
calendar.addEventSource({ url: ev_url, id: 'default' });
Everything works and the request is sent correctly, but the header i mentioned is missing (on server side we require that header to be present).
I tried adding the following to addEventSource:
beforeSend: function (xhr) {
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
}
Another thing i tried was to add this in the js file (probably pointless since Fullcalendar 4 is not using jquery anymore ?):
$.ajaxSetup({
beforeSend: function (xhr) {
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
}
});
Unfortunately neither solution worked.
In the past when using fullcalendar 3.x that header was present when requesting events. I guess that was because JQuery was adding it automatically.
I was looking for the answer to this as well. I modified the FullCalendar main.js file which is not ideal but does the trick!
I modified the file # around line 4242 here is the full source from that function:
/*! FullCalendar Core Package v4.3.1
function requestJson(method, url, params, successCallback, failureCallback) {
method = method.toUpperCase();
// Set Headers From Params to own varaible
var headers;
if(params.hasOwnProperty('headers') && Array.isArray(params.headers)){
headers = params.headers;
// Remove them from the params object
delete params.headers;
}
var body = null;
if (method === 'GET') {
url = injectQueryStringParams(url, params);
}
else {
body = encodeParams(params);
}
var xhr = new XMLHttpRequest();
xhr.open(method, url, true);
// Create Headers If Avaiable
if(typeof headers !== "undefined"){
for(var key in headers){
if (!headers.hasOwnProperty(key)) continue;
var obj = headers[key];
for(var prop in obj){
if (!obj.hasOwnProperty(prop)) continue;
xhr.setRequestHeader(prop, obj[prop]);
}
}
}
if (method !== 'GET') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 400) {
try {
var res = JSON.parse(xhr.responseText);
successCallback(res, xhr);
}
catch (err) {
failureCallback('Failure parsing JSON', xhr);
}
}
else {
failureCallback('Request failed', xhr);
}
};
xhr.onerror = function () {
failureCallback('Request failed', xhr);
};
xhr.send(body);
}
To Use it I simply add a headers key to the extraParams object like so:
extraParams = {
action: 'get_event',
headers: [
{"X-Requested-With":"XMLHttpRequest"}
]
};
This way you can add as many extra headers as you need.

Get image url in Meteor method

I cannot seem to find any documentation that will explain how I can get the filename and filepath of an uploaded collectionFS image into my meteor method.
I am able to get the image URL on the client side no problem using helpers, but I cannot seem to figure out how I can send the filename and filepath of the attached image to my method.
Method JS
Meteor.methods({
addQuote: function(data) {
check(data, Object);
var attachments = [];
var html = html;
// need to get the filename and filepath from collectionFS
// I would then have the data go here
attachments.push({filename: , filePath: });
this.unblock();
var email = {
from: data.contactEmail,
to: Meteor.settings.contactForm.emailTo,
subject: Meteor.settings.contactForm.quoteSubject,
html: html,
attachmentOptions: attachments
};
EmailAtt.send(email);
}
});
Controller JS
function ($scope, $reactive, $meteor) {
$reactive(this).attach($scope);
this.user = {};
this.helpers({
images: () => {
return Images.find({});
}
});
this.subscribe('images');
this.addNewSubscriber = function() {
// Uploads the Image to Collection
if(File.length > 0) {
Images.insert(this.user.contactAttachment);
console.log(this.user.contactAttachment);
}
// This is the variable I use to push to my method
// I image I need to push the filename and filepath also
// I am unsure how to access that information in the controller.
var data = ({
contactEmail: this.user.contactEmail,
contactName: this.user.contactName,
contactPhone: this.user.contactPhone,
contactMessage: this.user.contactMessage
});
// This will push the data to my meteor method "addQuote"
$meteor.call('addQuote', data).then(
function(data){
// Show Success
},
function(err) {
// Show Error
}
);
};
You can use the insert callback to get this informations:
Images.insert(fsFile, function (error, fileObj)
{
if (error) console.log(error);
else
{
console.log(fileObj);
//Use fileObj.url({brokenIsFine: true}); to get the url
}
});

Multiple Data Contexts in router - Meteor

I'm building a meteor app and on one route I'm adding multiple data context like so -
this.route('orgPage', {
path: '/org/:title',
data: {
orgs: function () {Orgs.findOne(this.params._id)},
projects: function() {Meteor.subscribe('projects', this.params._id)}
}
The only problem is that when I try to access this data in my templates js file, I can't access the _id or any of the attributes of orgs.
I've tried several approaches, but it always returns undefined. If I use a single data context, it works perfectly. Here is the function that doesn't function properly -
Template.orgPage.events({
'click #newProject': function(e) {
$('#npModal').modal();
},
'submit #npModal form': function(e, template) {
e.preventDefault();
if(!$(e.target).find('[name=newTitle]').val()) {
var projectTitle = 'Untitled'
} else {
var projectTitle = $(e.target).find('[name=newTitle]').val()
}
var theid = this._id;
var newProject = {
title: projectTitle,
organization: theid
}
Meteor.call('project', newProject, function(error, id) {
if (error)
return alert(error.reason);
$('#npModal').modal('hide');
$('#npModal').on('hidden.bs.modal', function (e) {
Router.go('newFields', {});
})
});
});
Anyone have any ideas? Thanks!!
You have missed a return statement. function () {Orgs.findOne(this.params._id)} should be function () {return Orgs.findOne(this.params._id)}. Further more, this inside this function won't refer to what you want, so you can't use this.params. And why do you subscribe to a subscription as a data context property? Do it in the waitOn function instead.

Route loads notFound briefly first

I have a iron route that searches for a collection item based on the url param. If it finds it, it returns the item as a data context, otherwise it renders a notFound template. The code looks like this:
this.route('profileView', {
path: list_path + '/profiles/:_id',
fastRender: true,
waitOn: function() {
if (Meteor.user()) {
return [Meteor.subscribe('singleProfile', this.params._id, Session.get("currentListId"))];
}
},
data: function() {
var profile = Profiles.findOne({
_id: this.params._id
});
if (!profile) {
this.render("notFound");
} else
return profile;
}
});
The problem is the notFound template gets loaded briefly prior to profile getting returned, although I thought the waitOn function would have handled that. What's the correct pattern to have the desired result using iron router? Thanks.
Is it possible that you forgot to configure the loading and dataNotFound hooks?
Router.onBeforeAction('loading');
Router.onBeforeAction('dataNotFound');
If you want to understand what is actually going on here, please look here.
I had to check for this.ready() in data. Updated code
this.route('profileView', {
path: list_path + '/profiles/:_id',
fastRender: true,
waitOn: function() {
if (Meteor.user()) {
return [Meteor.subscribe('singleProfile', this.params._id, Session.get("currentListId"))];
}
},
data: function() {
if(this.ready()){
var profile = Profiles.findOne({
_id: this.params._id
});
if (!profile) {
this.render("notFound");
} else
return profile;
}
}
});

Meteor - Setting the document title

Is there a way to change the <title> element in a Meteor app? Seems templates are only processed in the <body>.
Pretty much anywhere in your client-side JavaScript code:
document.title = "My new title";
You can extend David Wihl's solution:
Deps.autorun(function(){
document.title = Session.get("DocumentTitle");
});
Then You can in any time call:
Session.set("DocumentTitle","New Document Title");
If you use iron:router you can add the package manuelschoebel:ms-seo to handle the title along with meta tags. This is useful for static and dynamic SEO data:
Router.map(function() {
return this.route('blogPost', {
path: '/blog/:slug',
onAfterAction: function() {
var post = this.data().post;
SEO.set({
title: post.title,
meta: {
'description': post.description
},
og: {
'title': post.title,
'description': post.description
}
});
}
});
});
You can create a helper for setting the title (CoffeeScript):
UI.registerHelper "setTitle", ->
title = ""
for i in [0..arguments.length-2]
title += arguments[i]
document.title = title
undefined
or the same in Js:
UI.registerHelper("setTitle", function() {
var title = "";
for (var i = 0; i < arguments.length - 1; ++i) {
title += arguments[i];
}
document.title = title;
});
Then you can use it in complex ways, and it will be reactive:
{{#if book}}
{{setTitle book.title}}
{{else}}
{{setTitle "My books"}}
{{/if}}
I find it more convenient to handle that kind of thing directly in the router with a onBeforeAction:
Router.map(function() {
return this.route('StudioRoot', {
path: '/',
onBeforeAction: function() {
return document.title = "My Awesome Meteor Application";
}
});
});
you can also include in <head> </head> tags which does not reside in a template. try this:
contents of sample.html:
<head>
<title>my title</title>
</head>
<body>
...
</body>
<template name="mytemplate">
...
</template>
What I ended up doing:
in the Meteor.isClient:
Meteor.startup(function() {
Deps.autorun(function() {
document.title = Session.get('documentTitle');
});
});
now that the var is set reactively, go in the router file (if not already done: meteor add iron:router. My router file is both client and server)
Router.route('/', {
name: 'nameOfYourTemplate',
onBeforeAction: function () {
Session.set('documentTitle', 'whateverTitleIWant');
this.next(); //Otherwise I would get no template displayed
}
});
It doesn't matter if you already set a title in the head tag. It will be replaced by this one according to your route.
I had to look for an answer that would work for ui-router. I know that this might not be the answer you were looking for. Since this question was posted about 2 years ago, I figured if someone else was to come here looking for a solution with ui-router, this answer could help them:
myApp.run.js
(function() {
'use strict';
angular
.module('myApp')
.run(run);
run.$inject = ['$rootScope', '$state'];
function run($rootScope, $state) {
$rootScope.$on("$stateChangeSuccess", function(previousRoute, currentRoute){
document.title = 'myApp - ' + currentRoute.data.pageTitle;
});
};
})();
routes.js
(function() {
'use strict';
angular
.module('myApp')
.config(config);
config.$inject =
['$urlRouterProvider', '$stateProvider', '$locationProvider'];
function config($urlRouterProvider, $stateProvider) {
// ...
$stateProvider
.state('home', {
url: '/',
templateUrl: 'client/home/views/home.ng.html',
controller: 'HomeController',
data: {
pageTitle: 'My Dynamic title'
}
})
}
})();

Resources