phantomjs-binaries 1.8.0 → 1.8.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/modules/cli.js DELETED
@@ -1,138 +0,0 @@
1
- /*!
2
- * Casper is a navigation utility for PhantomJS.
3
- *
4
- * Documentation: http://casperjs.org/
5
- * Repository: http://github.com/n1k0/casperjs
6
- *
7
- * Copyright (c) 2011-2012 Nicolas Perriault
8
- *
9
- * Part of source code is Copyright Joyent, Inc. and other Node contributors.
10
- *
11
- * Permission is hereby granted, free of charge, to any person obtaining a
12
- * copy of this software and associated documentation files (the "Software"),
13
- * to deal in the Software without restriction, including without limitation
14
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15
- * and/or sell copies of the Software, and to permit persons to whom the
16
- * Software is furnished to do so, subject to the following conditions:
17
- *
18
- * The above copyright notice and this permission notice shall be included
19
- * in all copies or substantial portions of the Software.
20
- *
21
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
- * DEALINGS IN THE SOFTWARE.
28
- *
29
- */
30
-
31
- /*global CasperError console exports phantom require*/
32
-
33
- var system = require('system');
34
- var utils = require('utils');
35
-
36
- /**
37
- * Extracts, normalize ad organize PhantomJS CLI arguments in a dedicated
38
- * Object.
39
- *
40
- * @param array phantomArgs system.args value
41
- * @return Object
42
- */
43
- exports.parse = function parse(phantomArgs) {
44
- "use strict";
45
- var extract = {
46
- args: [],
47
- options: {},
48
- raw: {
49
- args: [],
50
- options: {}
51
- },
52
- drop: function drop(what) {
53
- if (utils.isNumber(what)) {
54
- // deleting an arg by its position
55
- this.args = this.args.filter(function _filter(arg, index) {
56
- return index !== what;
57
- });
58
- } else if (utils.isString(what)) {
59
- // deleting an arg by its value
60
- this.args = this.args.filter(function _filter(arg) {
61
- return arg !== what;
62
- });
63
- // deleting an option by its name (key)
64
- var self = this;
65
- Object.keys(this.options).forEach(function _forEach(option) {
66
- if (option === what) {
67
- delete self.options[what];
68
- }
69
- });
70
- } else {
71
- throw new CasperError("cannot drop argument of type " + typeof what);
72
- }
73
- },
74
- has: function has(what) {
75
- if (utils.isNumber(what)) {
76
- return what in this.args;
77
- } else if (utils.isString(what)) {
78
- return what in this.options;
79
- } else {
80
- throw new CasperError("Unsupported cli arg tester " + typeof what);
81
- }
82
- },
83
- get: function get(what) {
84
- if (utils.isNumber(what)) {
85
- return this.args[what];
86
- } else if (utils.isString(what)) {
87
- return this.options[what];
88
- } else {
89
- throw new CasperError("Unsupported cli arg getter " + typeof what);
90
- }
91
- }
92
- };
93
- phantomArgs.forEach(function _forEach(arg) {
94
- if (arg.indexOf('--') === 0) {
95
- // named option
96
- var optionMatch = arg.match(/^--(.*?)=(.*)/i);
97
- if (optionMatch) {
98
- extract.options[optionMatch[1]] = castArgument(optionMatch[2]);
99
- extract.raw.options[optionMatch[1]] = optionMatch[2];
100
- } else {
101
- // flag
102
- var flagMatch = arg.match(/^--(.*)/);
103
- if (flagMatch) {
104
- extract.options[flagMatch[1]] = extract.raw.options[flagMatch[1]] = true;
105
- }
106
- }
107
- } else {
108
- // positional arg
109
- extract.args.push(castArgument(arg));
110
- extract.raw.args.push(castArgument(arg));
111
- }
112
- });
113
- extract.raw = utils.mergeObjects(extract.raw, {
114
- drop: extract.drop,
115
- has: extract.has,
116
- get: extract.get
117
- });
118
- return extract;
119
- };
120
-
121
- /**
122
- * Cast a string argument to its typed equivalent.
123
- *
124
- * @param String arg
125
- * @return Mixed
126
- */
127
- function castArgument(arg) {
128
- "use strict";
129
- if (arg.match(/^-?\d+$/)) {
130
- return parseInt(arg, 10);
131
- } else if (arg.match(/^-?\d+\.\d+$/)) {
132
- return parseFloat(arg);
133
- } else if (arg.match(/^(true|false)$/i)) {
134
- return arg.trim().toLowerCase() === "true" ? true : false;
135
- } else {
136
- return arg;
137
- }
138
- }
@@ -1,781 +0,0 @@
1
- /*!
2
- * Casper is a navigation utility for PhantomJS.
3
- *
4
- * Documentation: http://casperjs.org/
5
- * Repository: http://github.com/n1k0/casperjs
6
- *
7
- * Copyright (c) 2011-2012 Nicolas Perriault
8
- *
9
- * Part of source code is Copyright Joyent, Inc. and other Node contributors.
10
- *
11
- * Permission is hereby granted, free of charge, to any person obtaining a
12
- * copy of this software and associated documentation files (the "Software"),
13
- * to deal in the Software without restriction, including without limitation
14
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15
- * and/or sell copies of the Software, and to permit persons to whom the
16
- * Software is furnished to do so, subject to the following conditions:
17
- *
18
- * The above copyright notice and this permission notice shall be included
19
- * in all copies or substantial portions of the Software.
20
- *
21
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
- * DEALINGS IN THE SOFTWARE.
28
- *
29
- */
30
-
31
- /*global console escape exports NodeList window*/
32
-
33
- (function(exports) {
34
- "use strict";
35
-
36
- exports.create = function create(options) {
37
- return new this.ClientUtils(options);
38
- };
39
-
40
- /**
41
- * Casper client-side helpers.
42
- */
43
- exports.ClientUtils = function ClientUtils(options) {
44
- /*jshint maxstatements:40*/
45
- // private members
46
- var BASE64_ENCODE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
47
- var BASE64_DECODE_CHARS = new Array(
48
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
49
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
50
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
51
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
52
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
53
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
54
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
55
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
56
- );
57
- var SUPPORTED_SELECTOR_TYPES = ['css', 'xpath'];
58
-
59
- // public members
60
- this.options = options || {};
61
- this.options.scope = this.options.scope || document;
62
- /**
63
- * Clicks on the DOM element behind the provided selector.
64
- *
65
- * @param String selector A CSS3 selector to the element to click
66
- * @return Boolean
67
- */
68
- this.click = function click(selector) {
69
- return this.mouseEvent('click', selector);
70
- };
71
-
72
- /**
73
- * Decodes a base64 encoded string. Succeeds where window.atob() fails.
74
- *
75
- * @param String str The base64 encoded contents
76
- * @return string
77
- */
78
- this.decode = function decode(str) {
79
- /*jshint maxstatements:30 maxcomplexity:30 */
80
- var c1, c2, c3, c4, i = 0, len = str.length, out = "";
81
- while (i < len) {
82
- do {
83
- c1 = BASE64_DECODE_CHARS[str.charCodeAt(i++) & 0xff];
84
- } while (i < len && c1 === -1);
85
- if (c1 === -1) {
86
- break;
87
- }
88
- do {
89
- c2 = BASE64_DECODE_CHARS[str.charCodeAt(i++) & 0xff];
90
- } while (i < len && c2 === -1);
91
- if (c2 === -1) {
92
- break;
93
- }
94
- out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
95
- do {
96
- c3 = str.charCodeAt(i++) & 0xff;
97
- if (c3 === 61)
98
- return out;
99
- c3 = BASE64_DECODE_CHARS[c3];
100
- } while (i < len && c3 === -1);
101
- if (c3 === -1) {
102
- break;
103
- }
104
- out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
105
- do {
106
- c4 = str.charCodeAt(i++) & 0xff;
107
- if (c4 === 61) {
108
- return out;
109
- }
110
- c4 = BASE64_DECODE_CHARS[c4];
111
- } while (i < len && c4 === -1);
112
- if (c4 === -1) {
113
- break;
114
- }
115
- out += String.fromCharCode(((c3 & 0x03) << 6) | c4);
116
- }
117
- return out;
118
- };
119
-
120
- /**
121
- * Echoes something to casper console.
122
- *
123
- * @param String message
124
- * @return
125
- */
126
- this.echo = function echo(message) {
127
- console.log("[casper.echo] " + message);
128
- };
129
-
130
- /**
131
- * Base64 encodes a string, even binary ones. Succeeds where
132
- * window.btoa() fails.
133
- *
134
- * @param String str The string content to encode
135
- * @return string
136
- */
137
- this.encode = function encode(str) {
138
- /*jshint maxstatements:30 */
139
- var out = "", i = 0, len = str.length, c1, c2, c3;
140
- while (i < len) {
141
- c1 = str.charCodeAt(i++) & 0xff;
142
- if (i === len) {
143
- out += BASE64_ENCODE_CHARS.charAt(c1 >> 2);
144
- out += BASE64_ENCODE_CHARS.charAt((c1 & 0x3) << 4);
145
- out += "==";
146
- break;
147
- }
148
- c2 = str.charCodeAt(i++);
149
- if (i === len) {
150
- out += BASE64_ENCODE_CHARS.charAt(c1 >> 2);
151
- out += BASE64_ENCODE_CHARS.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
152
- out += BASE64_ENCODE_CHARS.charAt((c2 & 0xF) << 2);
153
- out += "=";
154
- break;
155
- }
156
- c3 = str.charCodeAt(i++);
157
- out += BASE64_ENCODE_CHARS.charAt(c1 >> 2);
158
- out += BASE64_ENCODE_CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
159
- out += BASE64_ENCODE_CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
160
- out += BASE64_ENCODE_CHARS.charAt(c3 & 0x3F);
161
- }
162
- return out;
163
- };
164
-
165
- /**
166
- * Checks if a given DOM element exists in remote page.
167
- *
168
- * @param String selector CSS3 selector
169
- * @return Boolean
170
- */
171
- this.exists = function exists(selector) {
172
- try {
173
- return this.findAll(selector).length > 0;
174
- } catch (e) {
175
- return false;
176
- }
177
- };
178
-
179
- /**
180
- * Fetches innerText within the element(s) matching a given CSS3
181
- * selector.
182
- *
183
- * @param String selector A CSS3 selector
184
- * @return String
185
- */
186
- this.fetchText = function fetchText(selector) {
187
- var text = '', elements = this.findAll(selector);
188
- if (elements && elements.length) {
189
- Array.prototype.forEach.call(elements, function _forEach(element) {
190
- text += element.textContent || element.innerText;
191
- });
192
- }
193
- return text;
194
- };
195
-
196
- /**
197
- * Fills a form with provided field values, and optionnaly submits it.
198
- *
199
- * @param HTMLElement|String form A form element, or a CSS3 selector to a form element
200
- * @param Object vals Field values
201
- * @return Object An object containing setting result for each field, including file uploads
202
- */
203
- this.fill = function fill(form, vals) {
204
- /*jshint maxcomplexity:8*/
205
- var out = {
206
- errors: [],
207
- fields: [],
208
- files: []
209
- };
210
- if (!(form instanceof HTMLElement) || typeof form === "string") {
211
- this.log("attempting to fetch form element from selector: '" + form + "'", "info");
212
- try {
213
- form = this.findOne(form);
214
- } catch (e) {
215
- if (e.name === "SYNTAX_ERR") {
216
- out.errors.push("invalid form selector provided: '" + form + "'");
217
- return out;
218
- }
219
- }
220
- }
221
- if (!form) {
222
- out.errors.push("form not found");
223
- return out;
224
- }
225
- for (var name in vals) {
226
- if (!vals.hasOwnProperty(name)) {
227
- continue;
228
- }
229
- var field = this.findAll('[name="' + name + '"]', form);
230
- var value = vals[name];
231
- if (!field || field.length === 0) {
232
- out.errors.push('no field named "' + name + '" in form');
233
- continue;
234
- }
235
- try {
236
- out.fields[name] = this.setField(field, value);
237
- } catch (err) {
238
- if (err.name === "FileUploadError") {
239
- out.files.push({
240
- name: name,
241
- path: err.path
242
- });
243
- } else if(err.name === "FieldNotFound") {
244
- out.errors.push('Form field named "' + name + '" was not found.');
245
- } else {
246
- out.errors.push(err.toString());
247
- }
248
- }
249
- }
250
- return out;
251
- };
252
-
253
- /**
254
- * Finds all DOM elements matching by the provided selector.
255
- *
256
- * @param String selector CSS3 selector
257
- * @param HTMLElement|null scope Element to search child elements within
258
- * @return NodeList|undefined
259
- */
260
- this.findAll = function findAll(selector, scope) {
261
- scope = scope || this.options.scope;
262
- try {
263
- var pSelector = this.processSelector(selector);
264
- if (pSelector.type === 'xpath') {
265
- return this.getElementsByXPath(pSelector.path, scope);
266
- } else {
267
- return scope.querySelectorAll(pSelector.path);
268
- }
269
- } catch (e) {
270
- this.log('findAll(): invalid selector provided "' + selector + '":' + e, "error");
271
- }
272
- };
273
-
274
- /**
275
- * Finds a DOM element by the provided selector.
276
- *
277
- * @param String selector CSS3 selector
278
- * @param HTMLElement|null scope Element to search child elements within
279
- * @return HTMLElement|undefined
280
- */
281
- this.findOne = function findOne(selector, scope) {
282
- scope = scope || this.options.scope;
283
- try {
284
- var pSelector = this.processSelector(selector);
285
- if (pSelector.type === 'xpath') {
286
- return this.getElementByXPath(pSelector.path, scope);
287
- } else {
288
- return scope.querySelector(pSelector.path);
289
- }
290
- } catch (e) {
291
- this.log('findOne(): invalid selector provided "' + selector + '":' + e, "error");
292
- }
293
- };
294
-
295
- /**
296
- * Downloads a resource behind an url and returns its base64-encoded
297
- * contents.
298
- *
299
- * @param String url The resource url
300
- * @param String method The request method, optional (default: GET)
301
- * @param Object data The request data, optional
302
- * @return String Base64 contents string
303
- */
304
- this.getBase64 = function getBase64(url, method, data) {
305
- return this.encode(this.getBinary(url, method, data));
306
- };
307
-
308
- /**
309
- * Retrieves string contents from a binary file behind an url. Silently
310
- * fails but log errors.
311
- *
312
- * @param String url Url.
313
- * @param String method HTTP method.
314
- * @param Object data Request parameters.
315
- * @return String
316
- */
317
- this.getBinary = function getBinary(url, method, data) {
318
- try {
319
- return this.sendAJAX(url, method, data, false);
320
- } catch (e) {
321
- if (e.name === "NETWORK_ERR" && e.code === 101) {
322
- this.log("getBinary(): Unfortunately, casperjs cannot make cross domain ajax requests", "warning");
323
- }
324
- this.log("getBinary(): Error while fetching " + url + ": " + e, "error");
325
- return "";
326
- }
327
- };
328
-
329
- /**
330
- * Retrieves total document height.
331
- * http://james.padolsey.com/javascript/get-document-height-cross-browser/
332
- *
333
- * @return {Number}
334
- */
335
- this.getDocumentHeight = function getDocumentHeight() {
336
- return Math.max(
337
- Math.max(document.body.scrollHeight, document.documentElement.scrollHeight),
338
- Math.max(document.body.offsetHeight, document.documentElement.offsetHeight),
339
- Math.max(document.body.clientHeight, document.documentElement.clientHeight)
340
- );
341
- };
342
-
343
- /**
344
- * Retrieves bounding rect coordinates of the HTML element matching the
345
- * provided CSS3 selector in the following form:
346
- *
347
- * {top: y, left: x, width: w, height:, h}
348
- *
349
- * @param String selector
350
- * @return Object or null
351
- */
352
- this.getElementBounds = function getElementBounds(selector) {
353
- try {
354
- var clipRect = this.findOne(selector).getBoundingClientRect();
355
- return {
356
- top: clipRect.top,
357
- left: clipRect.left,
358
- width: clipRect.width,
359
- height: clipRect.height
360
- };
361
- } catch (e) {
362
- this.log("Unable to fetch bounds for element " + selector, "warning");
363
- }
364
- };
365
-
366
- /**
367
- * Retrieves the list of bounding rect coordinates for all the HTML elements matching the
368
- * provided CSS3 selector, in the following form:
369
- *
370
- * [{top: y, left: x, width: w, height:, h},
371
- * {top: y, left: x, width: w, height:, h},
372
- * ...]
373
- *
374
- * @param String selector
375
- * @return Array
376
- */
377
- this.getElementsBounds = function getElementsBounds(selector) {
378
- var elements = this.findAll(selector);
379
- var self = this;
380
- try {
381
- return Array.prototype.map.call(elements, function(element) {
382
- var clipRect = element.getBoundingClientRect();
383
- return {
384
- top: clipRect.top,
385
- left: clipRect.left,
386
- width: clipRect.width,
387
- height: clipRect.height
388
- };
389
- });
390
- } catch (e) {
391
- this.log("Unable to fetch bounds for elements matching " + selector, "warning");
392
- }
393
- };
394
-
395
- /**
396
- * Retrieves information about the node matching the provided selector.
397
- *
398
- * @param String|Object selector CSS3/XPath selector
399
- * @return Object
400
- */
401
- this.getElementInfo = function getElementInfo(selector) {
402
- var element = this.findOne(selector);
403
- var bounds = this.getElementBounds(selector);
404
- var attributes = {};
405
- [].forEach.call(element.attributes, function(attr) {
406
- attributes[attr.name.toLowerCase()] = attr.value;
407
- });
408
- return {
409
- nodeName: element.nodeName.toLowerCase(),
410
- attributes: attributes,
411
- tag: element.outerHTML,
412
- html: element.innerHTML,
413
- text: element.innerText,
414
- x: bounds.left,
415
- y: bounds.top,
416
- width: bounds.width,
417
- height: bounds.height,
418
- visible: this.visible(selector)
419
- };
420
- };
421
-
422
- /**
423
- * Retrieves a single DOM element matching a given XPath expression.
424
- *
425
- * @param String expression The XPath expression
426
- * @param HTMLElement|null scope Element to search child elements within
427
- * @return HTMLElement or null
428
- */
429
- this.getElementByXPath = function getElementByXPath(expression, scope) {
430
- scope = scope || this.options.scope;
431
- var a = document.evaluate(expression, scope, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
432
- if (a.snapshotLength > 0) {
433
- return a.snapshotItem(0);
434
- }
435
- };
436
-
437
- /**
438
- * Retrieves all DOM elements matching a given XPath expression.
439
- *
440
- * @param String expression The XPath expression
441
- * @param HTMLElement|null scope Element to search child elements within
442
- * @return Array
443
- */
444
- this.getElementsByXPath = function getElementsByXPath(expression, scope) {
445
- scope = scope || this.options.scope;
446
- var nodes = [];
447
- var a = document.evaluate(expression, scope, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
448
- for (var i = 0; i < a.snapshotLength; i++) {
449
- nodes.push(a.snapshotItem(i));
450
- }
451
- return nodes;
452
- };
453
-
454
- /**
455
- * Retrieves the value of a form field.
456
- *
457
- * @param String inputName The for input name attr value
458
- * @return Mixed
459
- */
460
- this.getFieldValue = function getFieldValue(inputName) {
461
- function getSingleValue(input) {
462
- try {
463
- type = input.getAttribute('type').toLowerCase();
464
- } catch (e) {
465
- type = 'other';
466
- }
467
- if (['checkbox', 'radio'].indexOf(type) === -1) {
468
- return input.value;
469
- }
470
- // single checkbox or… radio button (weird, I know)
471
- if (input.hasAttribute('value')) {
472
- return input.checked ? input.getAttribute('value') : undefined;
473
- }
474
- return input.checked;
475
- }
476
- function getMultipleValues(inputs) {
477
- type = inputs[0].getAttribute('type').toLowerCase();
478
- if (type === 'radio') {
479
- var value;
480
- [].forEach.call(inputs, function(radio) {
481
- value = radio.checked ? radio.value : undefined;
482
- });
483
- return value;
484
- } else if (type === 'checkbox') {
485
- var values = [];
486
- [].forEach.call(inputs, function(checkbox) {
487
- if (checkbox.checked) {
488
- values.push(checkbox.value);
489
- }
490
- });
491
- return values;
492
- }
493
- }
494
- var inputs = this.findAll('[name="' + inputName + '"]'), type;
495
- switch (inputs.length) {
496
- case 0: return null;
497
- case 1: return getSingleValue(inputs[0]);
498
- default: return getMultipleValues(inputs);
499
- }
500
- };
501
-
502
- /**
503
- * Retrieves a given form all of its field values.
504
- *
505
- * @param String selector A DOM CSS3/XPath selector
506
- * @return Object
507
- */
508
- this.getFormValues = function getFormValues(selector) {
509
- var form = this.findOne(selector);
510
- var values = {};
511
- var self = this;
512
- [].forEach.call(form.elements, function(element) {
513
- var name = element.getAttribute('name');
514
- if (name) {
515
- values[name] = self.getFieldValue(name);
516
- }
517
- });
518
- return values;
519
- };
520
-
521
- /**
522
- * Logs a message. Will format the message a way CasperJS will be able
523
- * to log phantomjs side.
524
- *
525
- * @param String message The message to log
526
- * @param String level The log level
527
- */
528
- this.log = function log(message, level) {
529
- console.log("[casper:" + (level || "debug") + "] " + message);
530
- };
531
-
532
- /**
533
- * Dispatches a mouse event to the DOM element behind the provided selector.
534
- *
535
- * @param String type Type of event to dispatch
536
- * @param String selector A CSS3 selector to the element to click
537
- * @return Boolean
538
- */
539
- this.mouseEvent = function mouseEvent(type, selector) {
540
- var elem = this.findOne(selector);
541
- if (!elem) {
542
- this.log("mouseEvent(): Couldn't find any element matching '" + selector + "' selector", "error");
543
- return false;
544
- }
545
- try {
546
- var evt = document.createEvent("MouseEvents");
547
- var center_x = 1, center_y = 1;
548
- try {
549
- var pos = elem.getBoundingClientRect();
550
- center_x = Math.floor((pos.left + pos.right) / 2),
551
- center_y = Math.floor((pos.top + pos.bottom) / 2);
552
- } catch(e) {}
553
- evt.initMouseEvent(type, true, true, window, 1, 1, 1, center_x, center_y, false, false, false, false, 0, elem);
554
- // dispatchEvent return value is false if at least one of the event
555
- // handlers which handled this event called preventDefault;
556
- // so we cannot returns this results as it cannot accurately informs on the status
557
- // of the operation
558
- // let's assume the event has been sent ok it didn't raise any error
559
- elem.dispatchEvent(evt);
560
- return true;
561
- } catch (e) {
562
- this.log("Failed dispatching " + type + "mouse event on " + selector + ": " + e, "error");
563
- return false;
564
- }
565
- };
566
-
567
- /**
568
- * Processes a selector input, either as a string or an object.
569
- *
570
- * If passed an object, if must be of the form:
571
- *
572
- * selectorObject = {
573
- * type: <'css' or 'xpath'>,
574
- * path: <a string>
575
- * }
576
- *
577
- * @param String|Object selector The selector string or object
578
- *
579
- * @return an object containing 'type' and 'path' keys
580
- */
581
- this.processSelector = function processSelector(selector) {
582
- var selectorObject = {
583
- toString: function toString() {
584
- return this.type + ' selector: ' + this.path;
585
- }
586
- };
587
- if (typeof selector === "string") {
588
- // defaults to CSS selector
589
- selectorObject.type = "css";
590
- selectorObject.path = selector;
591
- return selectorObject;
592
- } else if (typeof selector === "object") {
593
- // validation
594
- if (!selector.hasOwnProperty('type') || !selector.hasOwnProperty('path')) {
595
- throw new Error("Incomplete selector object");
596
- } else if (SUPPORTED_SELECTOR_TYPES.indexOf(selector.type) === -1) {
597
- throw new Error("Unsupported selector type: " + selector.type);
598
- }
599
- if (!selector.hasOwnProperty('toString')) {
600
- selector.toString = selectorObject.toString;
601
- }
602
- return selector;
603
- }
604
- throw new Error("Unsupported selector type: " + typeof selector);
605
- };
606
-
607
- /**
608
- * Removes all DOM elements matching a given XPath expression.
609
- *
610
- * @param String expression The XPath expression
611
- * @return Array
612
- */
613
- this.removeElementsByXPath = function removeElementsByXPath(expression) {
614
- var a = document.evaluate(expression, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
615
- for (var i = 0; i < a.snapshotLength; i++) {
616
- a.snapshotItem(i).parentNode.removeChild(a.snapshotItem(i));
617
- }
618
- };
619
-
620
- /**
621
- * Performs an AJAX request.
622
- *
623
- * @param String url Url.
624
- * @param String method HTTP method (default: GET).
625
- * @param Object data Request parameters.
626
- * @param Boolean async Asynchroneous request? (default: false)
627
- * @return String Response text.
628
- */
629
- this.sendAJAX = function sendAJAX(url, method, data, async) {
630
- var xhr = new XMLHttpRequest(),
631
- dataString = "",
632
- dataList = [];
633
- method = method && method.toUpperCase() || "GET";
634
- xhr.open(method, url, !!async);
635
- this.log("sendAJAX(): Using HTTP method: '" + method + "'", "debug");
636
- xhr.overrideMimeType("text/plain; charset=x-user-defined");
637
- if (method === "POST") {
638
- if (typeof data === "object") {
639
- for (var k in data) {
640
- dataList.push(encodeURIComponent(k) + "=" + encodeURIComponent(data[k].toString()));
641
- }
642
- dataString = dataList.join('&');
643
- this.log("sendAJAX(): Using request data: '" + dataString + "'", "debug");
644
- } else if (typeof data === "string") {
645
- dataString = data;
646
- }
647
- xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
648
- }
649
- xhr.send(method === "POST" ? dataString : null);
650
- return xhr.responseText;
651
- };
652
-
653
- /**
654
- * Sets a field (or a set of fields) value. Fails silently, but log
655
- * error messages.
656
- *
657
- * @param HTMLElement|NodeList field One or more element defining a field
658
- * @param mixed value The field value to set
659
- */
660
- this.setField = function setField(field, value) {
661
- /*jshint maxcomplexity:99 */
662
- var logValue, fields, out;
663
- value = logValue = (value || "");
664
- if (field instanceof NodeList) {
665
- fields = field;
666
- field = fields[0];
667
- }
668
- if (!(field instanceof HTMLElement)) {
669
- var error = new Error('Invalid field type; only HTMLElement and NodeList are supported');
670
- error.name = 'FieldNotFound';
671
- throw error;
672
- }
673
- if (this.options && this.options.safeLogs && field.getAttribute('type') === "password") {
674
- // obfuscate password value
675
- logValue = new Array(value.length + 1).join("*");
676
- }
677
- this.log('Set "' + field.getAttribute('name') + '" field value to ' + logValue, "debug");
678
- try {
679
- field.focus();
680
- } catch (e) {
681
- this.log("Unable to focus() input field " + field.getAttribute('name') + ": " + e, "warning");
682
- }
683
- var nodeName = field.nodeName.toLowerCase();
684
- switch (nodeName) {
685
- case "input":
686
- var type = field.getAttribute('type') || "text";
687
- switch (type.toLowerCase()) {
688
- case "color":
689
- case "date":
690
- case "datetime":
691
- case "datetime-local":
692
- case "email":
693
- case "hidden":
694
- case "month":
695
- case "number":
696
- case "password":
697
- case "range":
698
- case "search":
699
- case "tel":
700
- case "text":
701
- case "time":
702
- case "url":
703
- case "week":
704
- field.value = value;
705
- break;
706
- case "checkbox":
707
- if (fields.length > 1) {
708
- var values = value;
709
- if (!Array.isArray(values)) {
710
- values = [values];
711
- }
712
- Array.prototype.forEach.call(fields, function _forEach(f) {
713
- f.checked = values.indexOf(f.value) !== -1 ? true : false;
714
- });
715
- } else {
716
- field.checked = value ? true : false;
717
- }
718
- break;
719
- case "file":
720
- throw {
721
- name: "FileUploadError",
722
- message: "File field must be filled using page.uploadFile",
723
- path: value
724
- };
725
- case "radio":
726
- if (fields) {
727
- Array.prototype.forEach.call(fields, function _forEach(e) {
728
- e.checked = (e.value === value);
729
- });
730
- } else {
731
- out = 'Provided radio elements are empty';
732
- }
733
- break;
734
- default:
735
- out = "Unsupported input field type: " + type;
736
- break;
737
- }
738
- break;
739
- case "select":
740
- case "textarea":
741
- field.value = value;
742
- break;
743
- default:
744
- out = 'Unsupported field type: ' + nodeName;
745
- break;
746
- }
747
- // firing the `change` event
748
- var changeEvent = document.createEvent("HTMLEvents");
749
- changeEvent.initEvent('change', true, true);
750
- field.dispatchEvent(changeEvent);
751
- // blur the field
752
- try {
753
- field.blur();
754
- } catch (err) {
755
- this.log("Unable to blur() input field " + field.getAttribute('name') + ": " + err, "warning");
756
- }
757
- return out;
758
- };
759
-
760
- /**
761
- * Checks if a given DOM element is visible in remote page.
762
- *
763
- * @param String selector CSS3 selector
764
- * @return Boolean
765
- */
766
- this.visible = function visible(selector) {
767
- try {
768
- var comp,
769
- el = this.findOne(selector);
770
-
771
- if (el) {
772
- comp = window.getComputedStyle(el, null);
773
- return comp.visibility !== 'hidden' && comp.display !== 'none' && el.offsetHeight > 0 && el.offsetWidth > 0;
774
- }
775
- return false;
776
- } catch (e) {
777
- return false;
778
- }
779
- };
780
- };
781
- })(typeof exports === "object" ? exports : window);