Element Object

Element objects wrap JavaScript DOM nodes. They are created whenever some method returns any type of DOM node (Node, Element, HTMLElement, etc).

splash:select and splash:select_all return element objects; splash:evaljs may also return element objects, but currently they can’t be inside other objects or arrays - only top-level Node and NodeList is supported.

Attributes

element.node

element.node is a object that contains almost all DOM element attributes and methods.

The list of supported properties (some of them are mutable, other are read-only):

Properties inherited from HTMLElement:
  • accessKey
  • accessKeyLabel (read-only)
  • contentEditable
  • isContentEditable (read-only)
  • dataset (read-only)
  • dir
  • draggable
  • hidden
  • lang
  • offsetHeight (read-only)
  • offsetLeft (read-only)
  • offsetParent (read-only)
  • offsetTop (read-only)
  • spellcheck
  • style - a table with styles which can be modified
  • tabIndex
  • title
  • translate
Properties inherited from Element:
  • attributes (read-only) - a table with attributes of the element
  • classList (read-only) - a table with class names of the element
  • className
  • clientHeight (read-only)
  • clientLeft (read-only)
  • clientTop (read-only)
  • clientWidth (read-only)
  • id
  • innerHTML
  • localeName (read-only)
  • namespaceURI (read-only)
  • nextElementSibling (read-only)
  • outerHTML
  • prefix (read-only)
  • previousElementSibling (read-only)
  • scrollHeight (read-only)
  • scrollLeft
  • scrollTop
  • scrollWidth (read-only)
  • tabStop
  • tagName (read-only)
Properties inherited from Node:
  • baseURI (read-only)
  • childNodes (read-only)
  • firstChild (read-only)
  • lastChild (read-only)
  • nextSibling (read-only)
  • nodeName (read-only)
  • nodeType (read-only)
  • nodeValue
  • ownerDocument (read-only)
  • parentNode (read-only)
  • parentElement (read-only)
  • previousSibling (read-only)
  • rootNode (read-only)
  • textContent

The list of supported methods:

Methods inherited from EventTarget:
  • addEventListener
  • removeEventListener
Methods inherited from HTMLElement:
  • blur
  • click
  • focus
Methods inherited from Element:
  • getAttribute
  • getAttributeNS
  • getBoundingClientRect
  • getClientRects
  • getElementsByClassName
  • getElementsByTagName
  • getElementsByTagNameNS
  • hasAttribute
  • hasAttributeNS
  • hasAttributes
  • querySelector
  • querySelectorAll
  • releasePointerCapture
  • remove
  • removeAttribute
  • removeAttributeNS
  • requestFullscreen
  • requestPointerLock
  • scrollIntoView
  • setAttribute
  • setAttributeNS
  • setPointerCapture
Methods inherited from Node:
  • appendChild
  • cloneNode
  • compareDocumentPosition
  • contains
  • hasChildNodes
  • insertBefore
  • isDefaultNamespace
  • isEqualNode
  • isSameNode
  • lookupPrefix
  • lookupNamespaceURI
  • normalize
  • removeChild
  • replaceChild

Also, you can attach event handlers to the specified event. When the handler is called it will receive event table with the almost all available methods and properties.

function main(splash)
    -- ...
    local element = splash:select('.element')

    local x, y = 0, 0

    element.onclick = function(event)
        event:preventDefault()
        x = event.clientX
        y = event.clientY
    end

    assert(splash:wait(10))

    return x, y
end

The another way to attach event handlers is to use element.node:addEventListener(event, listener). It allows you to add more than a single event handler for an event.

Example of using element.node:addEventListener(event, listener)

function main(splash)
    -- ...
    local element = splash:select('.element')

    local x, y = 0, 0

    local store_coordinates = function(event)
        x = event.clientX
        y = event.clientY
    end

    element.node:addEventListener('click', store_coordinates)

    assert(splash:wait(10))

    return x, y
end

The following fields are read-only.

element.inner_id

Id of the inner representation of the element. It may be useful for comparing the elements for the equality.

Example:

function main(splash)
    -- ...

    local same = element2.inner_id == element2.inner_id

    -- ...
end

Methods

To modify or retrieve some information about the element you can use the following methods.

element:exists

Check whether the element exists in DOM. If the element doesn’t exist some of the methods will fail, returning the error flag.

Signature: exists = element:exists()

Returns: exists indicated whether the element exists.

Async: no.

There are several reasons why the element can be absent from DOM. One of the reasons is that the element was removed by some JavaScript code.

Example 1: the element was removed by JS code

function main(splash)
    -- ...
    local element = splash:select('.element')
    assert(splash:runjs('document.write("<body></body>")'))
    assert(splash:wait(0.1))
    local exists = element:exists() -- exists will be `false`
    -- ...
end

Another reason is that the element was created by script and not inserted into DOM.

Example 2: the element is not inserted into DOM

function main(splash)
    -- ...
    local element = splash:select('.element')
    local cloned = element.node:cloneNode() -- the cloned element isn't in DOM
    local exists = cloned:exists() -- exists will be `false`
    -- ...
end

element:mouse_click

Trigger mouse click event on the element.

Signature: ok, reason = element:mouse_click{x=0, y=0}

Parameters:

  • x - optional, x coordinate relative to the left corner of the element
  • y - optional, y coordinate relative to the top corner of the element

Returns: ok, reason pair. If ok is nil then error happened during the function call; reason provides an information about error type.

Async: no.

If x or y coordinate is not provided they will be set to 0 and the click will be triggered on the left-top corner of the element. The coordinates can have a negative value which means the click will be triggered outside of the element.

Mouse events are not propagated immediately, to see consequences of click reflected in page source you must call splash:wait

Example 1: get width and height of the element, calculate its center and click on it

function main(splash)
    -- ...
    local element = splash:select('.element')
    local bounds = element:bounds()
    assert(element:mouse_click{x=bounds.width/2, y=bounds.height/2})
    -- ...
end

Example 2: click on the area above the element by 10 pixels

function main(splash)
    -- ...
    local element = splash:select('.element')
    assert(element:mouse_click{y=-10})
    -- ...
end

See more about mouse events in splash:mouse_click.

element:mouse_hover

Trigger mouse hover (JavaScript mouseover) event on the element.

Signature: ok, reason = element:mouse_hover{x=0, y=0}

Parameters:

  • x - optional, x coordinate relative to the left corner of the element
  • y - optional, y coordinate relative to the top corner of the element

Returns: ok, reason pair. If ok is nil then error happened during the function call; reason provides an information about error type.

Async: no.

If x or y coordinate is not provided they will be set to 0 and the hover will be triggered on the left-top corner of the element. The coordinates can have a negative value which means the hover will be triggered outside of the element.

Mouse events are not propagated immediately, to see consequences of hover reflected in page source you must call splash:wait

Example 1: get width and height of the element, calculate its center and hover over it

function main(splash)
    -- ...
    local element = splash:select('.element')
    local bounds = element:bounds()
    assert(element:mouse_hover{x=bounds.width/2, y=bounds.height/2})
    -- ...
end

Example 2: hover over the area above the element by 10 pixels

function main(splash)
    -- ...
    local element = splash:select('.element')
    assert(element:mouse_hover{y=-10})
    -- ...
end

See more about mouse events in splash:mouse_hover.

element:styles

Return the computed styles of the element.

Signature: styles = element:styles()

Returns: styles is a table with computed styles of the element.

Async: no.

This method returns the result of JavaScript window.getComputedStyle() applied on the element.

Example: get all computed styles and return the font-size property.

function main(splash)
    -- ...
    local element = splash:select('.element')
    return element:styles()['font-size']
end

element:bounds

Return the bounding client rectangle of the element

Signature: bounds = element:bounds()

Returns: bounds is a table with the client bounding rectangle with the top, right, bottom and left coordinates and also with width and height values.

Async: no.

Example: get the bounds of the element.

function main(splash)
    -- ..
    local element = splash:select('.element')
    return element:bounds()
    -- e.g. bounds is { top = 10, right = 20, bottom = 20, left = 10, height = 10, width = 10 }
end

element:png

Return a screenshot of the element in PNG format

Signature: shot = element:png{width=nil, scale_method='raster', pad=0}

Parameters:

  • width - optional, width of a screenshot in pixels;
  • scale_method - optional, method to use when resizing the image, 'raster' or 'vector';
  • pad - optional, integer or {left, top, right, bottom} values of padding

Returns: shot is a PNG screenshot data, as a binary object. When the result is empty (e.g. if the element doesn’t exist in DOM or it isn’t visible) nil is returned.

Async: no.

pad parameter sets the padding of the resulting image. If it is a single integer then the padding from all sides will be equal. If the value of the padding is positive the resulting screenshot will be expanded by the specified amount of pixes. And if the value of padding is negative the resulting screenshot will be shrunk by the specified amount of pixels.

Example: return a padded screenshot of the element

function main(splash)
    -- ..
    local element = splash:select('.element')
    return element:png{pad=10}
end

See more in splash:png.

element:jpeg

Return a screenshot of the element in JPEG format

Signature: shot = element:jpeg{width=nil, scale_method='raster', quality=75, region=nil, pad=0}

Parameters:

  • width - optional, width of a screenshot in pixels;
  • scale_method - optional, method to use when resizing the image, 'raster' or 'vector';
  • quality - optional, quality of JPEG image, integer in range from 0 to 100;
  • pad - optional, integer or {left, top, right, bottom} values of padding

Returns: shot is a JPEG screenshot data, as a binary object. When the result is empty (e.g. if the element doesn’t exist in DOM or it isn’t visible) nil is returned.

Async: no.

pad parameter sets the padding of the resulting image. If it is a single integer then the padding from all sides will be equal. If the value of the padding is positive the resulting screenshot will be expanded by the specified amount of pixes. And if the value of padding is negative the resulting screenshot will be shrunk by the specified amount of pixes.

See more in splash:jpeg.

element:visible

Check whether the element is visible.

Signature: visible = element:visible()

Returns: visible indicates whether the element is visible.

Async: no.

element:focused

Check whether the element has focus.

Signature: focused = element:focused()

Returns: focused indicates whether the element is focused.

Async: no.

element:text

Fetch a text information from the element

Signature: text = element:text()

Returns: text is a text content of the element.

Async: no.

It tries to return the trimmed value of the following JavaScript Node properties:

  • textContent
  • innerText
  • value

If all of them are empty an empty string is returned.

element:info

Get useful information about the element.

Signature: info = element:info()

Returns: info is a table with element info.

Async: no.

Info is a table with the following fields:

  • nodeName - node name in a lower case (e.g. h1)
  • attributes - table with attributes names and its values
  • tag - html string representation of the element
  • html - inner html of the element
  • text - inner text of the element
  • x - x coordinate of the element
  • y - y coordinate of the element
  • width - width of the element
  • height - height of the element
  • visible - flag representing if the element is visible

element:field_value

Get value of the field element (input, select, textarea, button).

Signature: ok, value = element:field_value()

Returns: ok, value pair. If ok is nil then error happened during the function call; value provides an information about error type. When there is no error ok is true and value is a value of the element.

Async: no.

This method works in the following way:

  • if the element type is select:
    • if the multiple attribute is true it returns a table with the selected values;
    • otherwise it returns the value of the select;
  • if the element has attribute type="radio":
    • if it’s checked returns its value;
    • other it returns nil
  • if the element has attribute type="checkbox" it returns bool value
  • otherwise it returns the value of the value attribute or empty string if it doesn’t exist

element:form_values

Return a table with form values if the element type is form

Signature: form_values, reason = element:form_values{values='auto'}

Parameters:

  • values - type of the return value, can be one of 'auto', 'list' or 'first'

Returns: form_values, reason pair. If form_values is nil then error happened during the function call or node type is not form; reason provides an information about error type; otherwise form_values is a table with element names as keys and values as values.

Async: no.

The returned values depend on values parameter. It can be in 3 states:

'auto'

Returned values are tables or singular values depending on the form element type:

  • if the element is <select multiple> the returned value is a table with the selected option values or text contents if the value attribute is missing;
  • if the form has several elements with the same name attribute the returned value is a table with all values of that elements;
  • otherwise it is a string (for text and radio inputs), bool (for checkbox inputs) or nil the value of value attribute.

This result type is convenient if you’re working with the result in a Lua script.

'list'

Returned values always are tables (lists), even if the form element can be a singular value, useful for forms with unknown structure. Few notes:

  • if the element is a checkbox input and a value attribute then the table will contain that value;
  • if the element is <select multiple> and they are several of them with the same names then their values will be concatenated with the previous ones

This result type is convenient if you’re writing generic form-handling code - unlike auto there is no need to support multiple data types.

'first'
Returned values always are singular values, even if the form element can multiple value. If the element has multiple values only the first one will be selected.

Example 1: return the values of the following login form

<form id="login">
    <input type="text" name="username" value="admin" />
    <input type="password" name="password" value="pass" />
    <input type="checkbox" name="remember" value="yes" checked />
</form>
function main(splash)
    -- ...
    local form = splash:select('#login')
    return assert(form:form_values())
end

-- returned values are
{ username = 'admin', password = 'pass', remember = true }

Example 2: when values is equal to 'list'

function main(splash)
    -- ...
    local form = splash:select('#login')
    return assert(form:form_values{values='list'}))
end

-- returned values are
{ username = ['admin'], password = ['pass'], remember = ['checked'] }

Example 3: return the values of the following form when values is equal to 'first'

<form>
    <input type="text" name="foo[]" value="coffee"/>
    <input type="text" name="foo[]" value="milk"/>
    <input type="text" name="foo[]" value="eggs"/>
    <input type="text" name="baz" value="foo"/>
    <input type="radio" name="choice" value="yes"/>
    <input type="radio" name="choice" value="no" checked/>
    <input type="checkbox" name="check" checked/>

    <select multiple name="selection">
        <option value="1" selected>1</option>
        <option value="2">2</option>
        <option value="3" selected>2</option>
    </select>
</form>
function main(splash)
    -- ...
    local form = splash:select('form')
    return assert(form:form_values(false))
end

-- returned values are
{
    ['foo[]'] = 'coffee',
    baz = 'foo',
    choice = 'no',
    check = false,
    selection = '1'
}

element:fill

Fill the form with the provided values

Signature: ok, reason = element:fill(values)

Parameters:

  • values - table with input names as keys and values as input values

Returns: ok, reason pair. If ok is nil then error happened during the function call; reason provides an information about error type.

Async: no.

In order to fill your form your inputs must have name property and this method will select those input using that property.

Example 1: get the current values, change password and fill the form

<form id="login">
    <input type="text" name="username" value="admin" />
    <input type="password" name="password" value="pass" />
</form>
function main(splash)
    -- ...
    local form = splash:select('#login')
    local values = assert(form:form_values())
    values.password = "l33t"
    assert(form:fill(values))
end

Example 2: fill more complex form

<form id="signup" action="/signup">
    <input type="text" name="name"/>
    <input type="radio" name="gender" value="male"/>
    <input type="radio" name="gender" value="female"/>

    <select multiple name="hobbies">
        <option value="sport">Sport</option>
        <option value="cars">Cars</option>
        <option value="games">Video Games</option>
    </select>

    <button type="submit">Sign Up</button>
</form>
function main(splash)
  assert(splash:go(splash.args.url))
  assert(splash:wait(0.1))

  local form = splash:select('#signup')
  local values = {
    name = 'user',
    gender = 'female',
    hobbies = {'sport', 'games'},
  }

  assert(form:fill(values))
  assert(form:submit())
  -- ...
end

element:send_keys

Send keyboard events to the element.

Signature: ok, reason = element:send_keys(keys)

Parameters

  • keys - string representing the keys to be sent as keyboard events.

Returns: ok, reason pair. If ok is nil then error happened during the function call; reason provides an information about error type.

Async: no.

This method does the following:

  • clicks on the element
  • send the specified keyboard events

See more about keyboard events in in splash:send_keys.

element:send_text

Send keyboard events to the element.

Signature: ok, reason = element:send_text(text)

Parameters

  • text - string to be sent as input.

Returns: ok, reason pair. If ok is nil then error happened during the function call; reason provides an information about error type.

Async: no.

This method does the following:

  • clicks on the element
  • send the specified text to the element

See more about it in splash:send_text.

element:submit

Submit the form element.

Signature: ok, reason = element:submit()

Returns: ok, reason pair. If ok is nil then error happened during the function call (e.g. you are trying to submit on element which is not a form); reason provides an information about error type.

Async: no.

Example: get the form, fill with values and submit it

<form id="login" action="/login">
    <input type="text" name="username" />
    <input type="password" name="password" />
    <input type="checkbox" name="remember" />
    <button type="submit">Submit</button>
</form>
function main(splash)
    -- ...
    local form = splash:select('#login')
    assert(form:fill({ username='admin', password='pass', remember=true }))
    assert(form:submit())
    -- ...
end