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 141 142 143 144 145 146
|
# Proxy object for forwarding method calls to the node object inside the page.
class Poltergeist.Node
@DELEGATES = ['allText', 'visibleText', 'getAttribute', 'value', 'set', 'setAttribute', 'isObsolete',
'removeAttribute', 'isMultiple', 'select', 'tagName', 'find', 'getAttributes',
'isVisible', 'isInViewport', 'position', 'trigger', 'parentId', 'parentIds', 'mouseEventTest',
'scrollIntoView', 'isDOMEqual', 'isDisabled', 'deleteText', 'containsSelection',
'path', 'getProperty']
constructor: (@page, @id) ->
parent: ->
new Poltergeist.Node(@page, this.parentId())
for name in @DELEGATES
do (name) =>
this.prototype[name] = (args...) ->
@page.nodeCall(@id, name, args)
mouseEventPosition: (offset = {})->
viewport = @page.viewportSize()
if image = @_getAreaImage()
pos = image.position()
if area_offset = @_getAreaOffsetRect()
pos.left = pos.left + area_offset.x
pos.right = pos.left + area_offset.width
pos.top = pos.top + area_offset.y
pos.bottom = pos.top + area_offset.height
else
pos = this.position()
middle = (start, end, size) ->
start + ((Math.min(end, size) - start) / 2)
if offset['x']? && offset['y']?
x: pos.left + offset['x'],
y: pos.top + offset['y']
else
x: middle(pos.left, pos.right, viewport.width),
y: middle(pos.top, pos.bottom, viewport.height)
mouseEvent: (name, keys, offset) ->
if area_image = @_getAreaImage()
area_image.scrollIntoView()
else
@scrollIntoView()
pos = this.mouseEventPosition(offset)
test = this.mouseEventTest(pos.x, pos.y)
if test.status == 'success'
modifier_keys = (keys || []).join(',').replace('control', 'ctrl')
modifiers_code = @page.keyModifierCode(modifier_keys)
if name == 'rightclick'
@page.mouseEvent('click', pos.x, pos.y, 'right', modifiers_code)
if phantom.version.major == 2 && phantom.version.minor >= 1
@page.sendEvent('contextmenu', pos.x, pos.y, 'right', modifiers_code)
else
scroll_pos = @page.scrollPosition()
@trigger('contextmenu',
screenX: pos.x
screenY: pos.y
clientX: pos.x + scroll_pos['left']
clientY: pos.y + scroll_pos['top']
ctrlKey: modifier_keys.indexOf('ctrl') != -1
altKey: modifier_keys.indexOf('alt') != -1
metaKey: modifier_keys.indexOf('meta') != -1
shiftKey: modifier_keys.indexOf('shift') != -1
button: 2
)
else
@page.mouseEvent(name, pos.x, pos.y, 'left', modifiers_code)
pos
else
throw new Poltergeist.MouseEventFailed(name, test.selector, pos)
dragTo: (other) ->
this.scrollIntoView()
position = this.mouseEventPosition()
otherPosition = other.mouseEventPosition()
@page.mouseEvent('mousedown', position.x, position.y)
@page.mouseEvent('mouseup', otherPosition.x, otherPosition.y)
dragBy: (x, y) ->
this.scrollIntoView()
position = this.mouseEventPosition()
final_pos =
x: position.x + x
y: position.y + y
@page.mouseEvent('mousedown', position.x, position.y)
@page.mouseEvent('mouseup', final_pos.x, final_pos.y)
isEqual: (other) ->
@page == other.page && this.isDOMEqual(other.id)
_getAreaOffsetRect: ->
# get the offset of the center of selected area
shape = @getAttribute('shape').toLowerCase();
coords = (parseInt(coord,10) for coord in @getAttribute('coords').split(','))
rect = switch shape
when 'rect', 'rectangle'
#coords.length == 4
[x,y] = coords
{ x: x, y: y, width: coords[2] - x, height: coords[3] - y }
when 'circ', 'circle'
# coords.length == 3
[centerX, centerY, radius] = coords
{ x: centerX - radius, y: centerY - radius, width: 2 * radius, height: 2 * radius }
when 'poly', 'polygon'
# coords.length > 2
# This isn't correct for highly concave polygons but is probably good enough for
# use in a testing tool
xs = (coords[i] for i in [0...coords.length] by 2)
ys = (coords[i] for i in [1...coords.length] by 2)
minX = Math.min xs...
maxX = Math.max xs...
minY = Math.min ys...
maxY = Math.max ys...
{ x: minX, y: minY, width: maxX-minX, height: maxY-minY }
_getAreaImage: ->
if 'area' == @tagName().toLowerCase()
map = @parent()
if map.tagName().toLowerCase() != 'map'
throw new Error('the area is not within a map')
mapName = map.getAttribute('name')
if not mapName?
throw new Error ("area's parent map must have a name")
mapName = '#' + mapName.toLowerCase()
image_node_id = @page.find('css', "img[usemap='#{mapName}']")[0]
if not image_node_id?
throw new Error ("no image matches the map")
@page.get(image_node_id)
|