forked from amir20/phantomjs-node
-
Notifications
You must be signed in to change notification settings - Fork 0
/
shim.coffee
140 lines (112 loc) · 4.36 KB
/
shim.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# Require gets overwritten by browserify, so we have to reimplement it from scratch - boo :(
webpage = core_require('webpage');
shoe = require('shoe');
dnode = require('dnode');
system = core_require('system');
port = system.args[1]
hostname = system.args[2]
# controlPage = webpage.create()
fnwrap = (target) -> -> target.apply this, arguments
# Descend into objects with dotted keys
descend = (op, obj, key, val) ->
cur = obj
keys = key.split '.'
cur = cur[keys.shift()] while keys.length > 1
cur[keys[0]] = val if op is 'set'
cur[keys[0]]
_transform = (val) ->
if typeof val is "string" and val.indexOf('__phantomCallback__') is 0
val = 'return ' + val.replace('__phantomCallback__', '');
val = phantom.callback(new Function(val)());
return val;
transform = (obj) ->
if typeof obj is "string"
_transform(obj)
else if typeof obj is "object"
for key of obj
if typeof obj[key] is "object"
transform(obj[key])
else
obj[key] = _transform(obj[key])
return obj
mkwrap = (src, pass=[], special={}) ->
obj =
set: (key, val, cb=->) ->
#Fnwrap so PhantomJS doesn't segfault when it tries to call the callback
val = fnwrap val if typeof val is "function"
val = transform(val)
cb descend 'set', src, key, val
get: (key, cb) -> cb descend 'get', src, key
for k in pass
do (k) ->
obj[k] = (args...) ->
# This idempotent tomfoolery is required to stop PhantomJS from segfaulting
args[i] = fnwrap arg for arg, i in args when typeof arg is 'function'
src[k] args...
for own k of special
obj[k] = special[k]
obj
pageWrap = (page) -> mkwrap page,
['open','close','includeJs','sendEvent','release','uploadFile','goBack','goForward','reload', 'switchToFrame', 'switchToMainFrame', 'switchToParentFrame', 'switchToFocusedFrame']
# this is here to let the user pass in a function that has access to request.abort() and other functions on the request object.
onConsoleMessage: (fn, cb=(->)) ->
page.onConsoleMessage = ->
fn.apply(this, arguments)
cb()
onError: (fn, cb=(->)) ->
page.onError = ->
fn.apply(this, arguments)
cb()
onResourceRequested: (fn, cb=(->), args...) ->
page.onResourceRequested = ->
# prepare a arguments with the extra args
argumentsWithExtraArgs = [].slice.apply(arguments).concat(args)
# give a name to the anonymouse function so that we can call it
fn = fn.replace /function.*\(/, 'function x('
# the only way we can access the request object is by passing a function to this point as a string and expanding it
eval(fn) # :(
# this function has access to request.abort()
x.apply(this, argumentsWithExtraArgs)
# this function does not have access to request.abort()
cb.apply(this, argumentsWithExtraArgs)
injectJs: (js, cb=->) -> cb page.injectJs js
evaluate: (fn, cb=(->), args...) -> cb page.evaluate.apply(page, [fn].concat(args))
render: (file, opts={}, cb) ->
unless cb?
if typeof opts is 'function'
cb = opts
opts = {}
else
cb = ->
page.render file, opts; cb()
getContent: (cb=->) -> cb page.content
getCookies: (cb=->) -> cb page.cookies
renderBase64: (type, cb=->) -> cb page.renderBase64 type
setHeaders: (headers, cb=->) -> page.customHeaders = headers; cb()
setContent: (html, url, cb=->) ->
page.onLoadFinished = (status) ->
page.onLoadFinished = null
cb status
page.setContent html, url
setViewportSize: (width, height, cb=->) ->
page.viewportSize = {width:width, height:height}; cb()
setPaperSize: (options, cb=->) ->
page.paperSize = transform(options); cb()
setZoomFactor: (zoomFactor, cb=->) -> page.zoomFactor = zoomFactor; cb()
setFileOnPicker: (fileName, cb=->) ->
page.onFilePicker = ->
cb.apply(this, arguments)
fileName
_phantom = mkwrap phantom,
['exit'],
injectJs: (js, cb=->) -> cb phantom.injectJs js
getCookies: (cb=->) -> cb(phantom.cookies)
addCookie: (cookie, cb=->) ->
cb(phantom.addCookie(cookie))
clearCookies: (cb=->) -> cb phantom.clearCookies()
createPage: (cb) -> cb pageWrap webpage.create()
setProxy: (host, port, type, user, password, cb=->) -> cb(phantom.setProxy(host, port, type, user, password))
stream = shoe('http://' + hostname + ':' + port + '/dnode')
d = dnode _phantom
d.pipe stream
stream.pipe d