Capturing a popup window and download url using casperjs - javascript

I am trying to scrape a table from an aspx site using casperjs (a wrapper on phantomjs). One of the table items I need is a link which opens a new page and downloads the PDF. The contents of the TD tag are:
<input type="image" src="images/document.png" alt="View Document" onclick="javascript:__doPostBack('ctl00$mbody$tcManageDocs$tpViewDocs$gv_formData','View$1');return false;">
Once clicked, I have determined that it opens a new window to download the file. Using wireshark, I have captured (relevant parts of) the response to the __doPostBack POST request:
<script type="text/javascript">
//<![CDATA[
window.open('documents/path/to/document.pdf', 'popup_window', 'width=1024,height=768,left=10,top=10,resizable=yes,scrollbars=1,menubar=yes,toolbar=yes');popup_window.print();//]]>
</script>
<script type='text/javascript'>new Sys.WebForms.Menu({ element: 'Menu1', disappearAfter: 500, orientation: 'horizontal', tabIndex: 0, disabled: false });</script></form>
However, when executing the link:
this.click('#mbody_tcManageDocs_tpViewDocs_gv_formData > tbody:nth-child(1) > tr:nth-child(2) > td:nth-child(1) > input:nth-child(1)');
I get a Page Error: ReferenceError: Can't find variable: popup_window error when I try to run this.
Is there any way I can capture the window using javascript?
Do I need to capture it in the page context or from the phantomjs/casperjs context?
The relevant data I want to capture is the url only (being 'documents/path/to/document.pdf') as a text stream: I would rather not actually perform the download to reduce the bandwidth/server demand and script execution time.
Being this is my first scraping attempt and I'm trying to learn javascript at the same time, I am stumped as how to proceed: even some direction as to what to try would be helpful.
EDIT: I have captured the events as commented by Artjom: I don't get any notifications for the resource messages, but in popup.loaded I get the following:
popup.loaded
{
"objectName": "WebPage",
"title": "",
"frameTitle": "",
"content": "<html><head></head><body></body></html>",
"frameContent": "<html><head></head><body></body></html>",
"url": "about:blank",
"frameUrl": "about:blank",
"loading": false,
"loadingProgress": 100,
"canGoBack": false,
"canGoForward": false,
"plainText": "",
"framePlainText": "",
"libraryPath": "/usr/share/casperjs/bin",
"offlineStoragePath": "/home/rob/.qws/share/data/Ofi Labs/PhantomJS",
"offlineStorageQuota": 5242880,
"viewportSize": {
"height": 300,
"width": 400
},
"paperSize": {},
"clipRect": {
"height": 0,
"left": 0,
"top": 0,
"width": 0
},
"scrollPosition": {
"left": 0,
"top": 0
},
"navigationLocked": false,
"customHeaders": {},
"zoomFactor": 1,
"cookies": [],
"windowName": "popup_window",
"pages": [],
"pagesWindowName": [],
"ownsPages": true,
"framesName": [],
"frameName": "popup_window",
"framesCount": 0,
"focusedFrameName": "popup_window"
}
Is there something in the casperjs/phantomjs that is failing? I am starting to suspect that the error above is one of the main issues. When I wait for the popup for a while, casperjs times out and I get no further resource events.

Related

How enableJavaScript flag works with percy snapshot

While setting up Percy snapshot test, I noticed, there is a flag enableJavaScript provided which my understanding is to control if a web app in browser is to be loaded with JS disabled or enabled.
Here is how I invoke my percy test:
npx #percy/cli snapshot ./snapshots.json --base-url http://localhost:9000 -c ./.percy.json
persy.json
{
"version": 2,
"snapshot": {
"percy-css": ".hide-in-percy {\n visibility: hidden;\n}\n",
"widths": [360, 600, 900, 1200, 1600]
},
"discovery": {
"userAgent": "percy-cli",
"networkIdleTimeout": 750
}
}
snapshot.json
[
{
"name": "Page 1: JS enabled",
"url": "/page-1",
"waitForTimeout": 1000,
"enableJavaScript": true
},
{
"name": "Page 1: JS disabled",
"url": "/page-1",
"waitForTimeout": 1000,
"enableJavaScript": false
}
]
But it seems with enableJavaScript set to false, images do not show up in the snapshot although if I load the app myself with JS disabled in the browser, images show up just fine. What am I missing here. How do I test my pages with JS enabled/disabled

Uncaught TypeError: $(...).fullCalendar is not a function error

I have a small code with FullCalendar library displaying 2 calendars. One on the first tab, one on the 2nd tab. Both calendars show up, however, the one that is invisible when the page loads is not showing up properly.
Full code: https://codepen.io/MadBoyEvo/pen/rNxQQYP
So I thought I would do a refresh or quickly change the view from current to new one and back to current on a tab switch but whatever I do it doesn't work.
<script type="text/javascript">var tabs = tabbis.init({
tabGroup: "[data-tabs]",
paneGroup: "[data-panes]",
tabActive: "active",
paneActive: "active",
callback: function (tab, pane) {
// console.log("TAB id:" + tab.id);
// console.log(pane.id);
// console.log(tableid);
// this makes sure to refresh tables on tab change to make sure they have buttons and everything
// it's a bit heavy as it touches all tables, may require some improvements in future to consider
// which tab has which table
try {
var tableid = document.getElementById(tab.id + "-Content").querySelector('table[id^="DT-"]').id;
$("#" + tableid).DataTable().columns.adjust().responsive.recalc();
} catch (e) {
console.log('No datatables available.');
}
// this code here doesn't work
var view = $('#Calendar-on26xq0w').fullCalendar('getView');
alert("The view's title is " + view.title);
}
});
// in theory should take care of removing local storage for tabbis
// some errors occurs if the local storage is not cleaned after a while
window.addEventListener("unload", tabbis.remove, false);
</script><!-- JS Elastic Tabbis END -->
The error shows up: Uncaught TypeError: $(...).fullCalendar is not a function
I tried moving calendar.js script from top to bottom, to before or after the script code that fails but nothing is helping.
I am a bit of JS noob so it's a bit unclear to me why it doesn't work. I used similar approach for DataTables (the Try/catch) and it works fine (if there is DataTable loaded)
Edit:
I've tried searching for calendar id - and I can find it, yet the same error is visible on that 3rd line.
var calendarid = document.getElementById(tab.id + "-Content").querySelector('div[id^="Calendar-"]').id;
alert("The calendarid " + calendarid);
var view = $('#' + calendarid).fullCalendar('getView');
alert("The view's title is " + view.title);
Thanks to #ADyson from comments I was able to understand my issues:
FullCalendar V5 doesn't have the method I was trying to use
If you're using fullcalendar v5 as per your tag, then
$('#Calendar-on26xq0w').fullCalendar will never work - that's the
syntax from fullCalendar v3 (back when it was a jQuery plugin, hence
the jQuery-style selector to initialise the object). If you want to
call a method in v4 or v5 then you need a reference to the object you
created when initialising the calendar, and then to get the current
view you can simply write calendar.view (it's a property not a
function) - see fullcalendar.io/docs/Calendar-view . (There's no such
function as getView in v5 either.)
I can't use query DOM Object and pass it somehow to FullCalendar as I was trying to do
What I actually have to do is create object https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects and store relevant JS objects.
At the very top defined empty object
<!-- JS FullCalendar Basic START -->
<script type="text/javascript">var calendarTracker = {
};
</script><!-- JS FullCalendar Basic END -->
<!-- CSS FullCalendar Basic START -->
Next for each calendar that I created
<script>document.addEventListener('DOMContentLoaded', function () {
var calendarEl = document.getElementById('Calendar-c43nxqpi');
var calendar = new FullCalendar.Calendar(calendarEl,
{
"headerToolbar": {
"left": "prev,next,today",
"right": "dayGridMonth,timeGridWeek,timeGridDay,listMonth",
"center": "title"
},
"initialView": "listWeek",
"initialDate": "2020-07-20",
"nowIndicator": true,
"navLinks": true,
"businessHours": false,
"editable": false,
"events": [
{
"title": "Active Directory Meeting",
"description": "We will talk about stuff",
"start": "2020-07-20T11:43:35"
},
{
"title": "Lunch",
"description": "Very long lunch",
"start": "2020-07-22T08:43:35",
"end": "2020-07-23T11:43:35"
}
],
"dayMaxEventRows": true,
"weekNumbers": true,
"weekNumberCalculation": "ISO",
"selectable": true,
"selectMirror": true,
"buttonIcons": false,
"views": {
"listWeek": {
"buttonText": "list week"
},
"listMonth": {
"buttonText": "list month"
},
"listDay": {
"buttonText": "list day"
}
},
eventRender: function (info) {
var tooltip = new Tooltip(info.el, {
title: info.event.extendedProps.description,
placement: 'top',
trigger: 'hover',
container: 'body'
});
}
}
);
calendar.render();
calendarTracker['Calendar-c43nxqpi'] = calendar;
});
</script>
I've stored this calendar object with key based on it's html id.
calendarTracker['Calendar-c43nxqpi'] = calendar;
Finally on tab switch
<script type="text/javascript">var tabs = tabbis.init({
tabGroup: "[data-tabs]",
paneGroup: "[data-panes]",
tabActive: "active",
paneActive: "active",
callback: function (tab, pane) {
// We need to make same thing for calendar
function redrawCalendar(calendar) {
//console.log(calendarTracker[calendar.id].view);
calendarTracker[calendar.id].changeView(calendarTracker[calendar.id].view.type);
console.log('Redrawing view for' + calendar.id)
}
try {
var calendar = document.getElementById(tab.id + "-Content").querySelectorAll('div[id^="Calendar-"]');
calendar.forEach(redrawCalendar)
} catch (e) {
console.log('No calendars available.');
}
}
});
// in theory should take care of removing local storage for tabbis
// some errors occurs if the local storage is not cleaned after a while
window.addEventListener("unload", tabbis.remove, false);
</script>
I'm basically finding all calendars on the given tab using querySelectorAll and then for each calendar on the tab I'm running redrawCalendar function which based on the HTML DOM ID finds the correct calendar object, and resets its view making sure the visual part is up and running again.
You can create a calendar2 on the fly when the user tries to switch to the next tab. Listen for the change event on the tab and initialize the second calendar based on the calendarID.
var calendarid = document.getElementById(tab.id + "-Content").querySelector('div[id^="Calendar-"]').id;
// alert("The calendarid " + calendarid);
if(calendarid == 'Calendar-3fso0g65') {
loadCalendarFirst(calendarid);
} else {
loadCalendarSecond(calendarid);
}
I added the following two methods to call when needed
<script>
function loadCalendarFirst(claendarID) {
var calendarEl = document.getElementById(claendarID);
var calendar = new FullCalendar.Calendar(calendarEl,
{
"headerToolbar": {
"left": "prev,next,today",
"right": "dayGridMonth,timeGridWeek,timeGridDay,listMonth",
"center": "title"
},
"initialView": "listWeek",
"initialDate": "2020-07-19",
"nowIndicator": true,
"navLinks": true,
"businessHours": false,
"editable": false,
"events": [
{
"title": "Active Directory Meeting",
"description": "We will talk about stuff",
"start": "2020-07-19T10:07:02"
},
{
"title": "Lunch",
"description": "Very long lunch",
"start": "2020-07-21T07:07:02",
"end": "2020-07-22T10:07:02"
}
],
"dayMaxEventRows": true,
"weekNumbers": true,
"weekNumberCalculation": "ISO",
"selectable": true,
"selectMirror": true,
"buttonIcons": false,
"views": {
"listWeek": {
"buttonText": "list week"
},
"listMonth": {
"buttonText": "list month"
},
"listDay": {
"buttonText": "list day"
}
},
eventRender: function (info) {
var tooltip = new Tooltip(info.el, {
title: info.event.extendedProps.description,
placement: 'top',
trigger: 'hover',
container: 'body'
});
}
}
);
calendar.render();
}
function loadCalendarSecond(calendarID) {
var calendarEl = document.getElementById(calendarID);
var calendar = new FullCalendar.Calendar(calendarEl,
{
"headerToolbar": {
"left": "prev,next,today",
"right": "dayGridMonth,timeGridWeek,timeGridDay,listMonth",
"center": "title"
},
"initialDate": "2020-07-19",
"nowIndicator": true,
"navLinks": true,
"businessHours": false,
"editable": false,
"events": [
{
"title": "Active Directory Meeting",
"description": "We will talk about stuff",
"start": "2020-07-19T10:07:02"
},
{
"title": "Lunch",
"description": "Very long lunch",
"start": "2020-07-21T07:07:02",
"end": "2020-07-22T10:07:02"
}
],
"dayMaxEventRows": true,
"weekNumbers": true,
"weekNumberCalculation": "ISO",
"selectable": true,
"selectMirror": true,
"buttonIcons": false,
"views": {
"listWeek": {
"buttonText": "list week"
},
"listMonth": {
"buttonText": "list month"
},
"listDay": {
"buttonText": "list day"
}
},
eventRender: function (info) {
var tooltip = new Tooltip(info.el, {
title: info.event.extendedProps.description,
placement: 'top',
trigger: 'hover',
container: 'body'
});
}
}
);
calendar.render();
}
loadCalendarFirst('Calendar-3fso0g65');
</script>
Here's the Updated Plunker
The error indicates that the element you try to run the fullCalendar() function on is not available. This means that the HTML element with the ID Calendar-on26xq0w can't be found on the document.

store the name of a function in a JSON file and later be able to load and call it from within a script?

That title is kind of garbled and this is probably a duplicate but I've been digging a while. This must be really simple. The accepted answer on this question didn't work for me: How to declare and use the name of a function from a json object?
The task: I am trying to externalize the set-up data for a Vis.js timeline into a JSON file . The data set was no problem nor are all of the options except for the function references, "orderByID" and "visTemplate". Those are functions I defined which exist within the script where I am working with the JSON data.
When I try to use the JSON without attempting to convert it, Vis.js complains. When I tried the answer from the question above with the code below, I get the errors show in the image.
This is in Electron and the script is being loaded through a script tag in the index.html.
I await the one-line answer to this simple issue which have spent so much time describing. 😉
console.log(' timelineOptions.order', timelineOptions.order);
console.log(' timelineOptions.template', timelineOptions.template);
console.log('this', this);
console.log('window', window);
timelineOptions.order = window[timelineOptions.orderByID];
timelineOptions.template = window[timelineOptions.visTemplate];
"timelineOptions": {
"order": "orderByID",
"selectable": true,
"zoomable": false,
"width": "100%",
"height": "90%",
"minHeight": 700,
"format": {
"minorLabels": {
"hour": "HH\\h"
}
},
"margin": {
"axis": 20,
"item": 20
},
"start": "2016-12-30",
"end": "2017-01-4",
"template": "visTemplate",
"showCurrentTime": false,
"dataAttributes": "all",
"timeAxis": { "scale": "day", "step": 1 },
"orientation": {
"axis": "top",
"item": "top"
}
}
Not sure if you've setup the right reference on the window object but shouldn't your code read:
timelineOptions.order = window[timelineOptions.order];
You've referenced the string value orderByID instead of the property name you used to set the object up.

Change object value in javascript from another file

I am using this code
$.fn.lightbox.defaults = {
adminBarHeight:28,
overlayOpacity: 0.8,
borderSize: 10,
imageArray: new Array,
activeImage: null,
inprogress: false, //this is an internal state variable. don't touch.
widthCurrent: 250,
heightCurrent: 250,
xScale: 1,
yScale: 1,
displayTitle: true,
disableNavbarLinks: true,
loopImages: true,
imageClickClose: true,
jsonData: null,
jsonDataParser: null,
followScroll: false,
isIE8: false //toyNN:internal value only
};
When I adjust borderSize I get the effect I want however I need to be able to adjust this from another script rather than just changing the value above because I need to leave the code above unchanged as it may be overwritten during updates. How can I do this
I tried
$.fn.lightbox.defaults[borderSize] = 0;
but it had no effect.
The code is from WP Lightbox 2.
It's:
$.fn.lightbox.defaults['borderSize']
$.fn.lightbox.defaults['borderSize'] = 0;
or
$.fn.lightbox.defaults.borderSize = 0;
And ensure that this script is loaded after

ExtJs 4 - Window.show() - window size is very small

I'm getting to grips with ExtJs 4 and having an issue showing a modal window upon a double click event on a grid.
A listener defined on grid component:
"listeners": {
"itemdblclick": function() {
var win =Ext.getCmp('myCmp');
win.myWindow.show();
}
}
previously defined property of myCmp to be a window component:
(I've used the parent container object myCmp as I'm code generating the javascript to build the ExtJs config)
myCmp.myWindow = Ext.create('Ext.window.Window',{
"layout": "fit",
"items": [
....
],
"title": "Hello Window",
"width": "300",
"height": "300",
"id": "myWindow"
});
The logic works well, I double click the grid, the window object is present (myCmp.myWindow) but when i call show() the window is displayed very small (6px x 6px).
if I change the handler to :
Ext.create('Ext.window.Window',{
"layout": "fit",
"items": [
....
],
"title": "Hello Window",
"width": "300",
"height": "300",
"id": "myWindow"
}).show();
It works ok. obviously this is creating a new window instance.
Any ideas? am I doing this right?
Thanks in advance
sam
Why do you refer to "myCmp" when you can directly refer to your window?
var win = Ext.getCmp('myWindow');
win.show();
This should work. Also, Why do you instantiate a window else where and then use it? Wouldn't it be better to create a instance when you need it and destroy it after use?
Also, you should configure the window correctly. The width and height are numeric fields and not string. Refer to api documentation and examples to see how to configure the objects properly. you should use the following window:
Ext.create('Ext.window.Window',{
layout: 'fit',
items: [
....
],
title: 'Hello Window',
width: 300,
height: 300,
id: 'myWindow'
}).show();

Categories

Resources