Ejemplo n.º 1
0
 def set_node_style(self, property_name, property_value):
     """ Set value of the style property of the element """
     return self.tab.evaljs(u"{element}.style[{property}] = {value}".format(
         element=self.element_js,
         property=escape_js(property_name),
         value=escape_js(property_value)
     ))
Ejemplo n.º 2
0
 def set_node_style(self, property_name, property_value):
     """ Set value of the style property of the element """
     return self.tab.evaljs(u"{element}.style[{property}] = {value}".format(
         element=self.element_js,
         property=escape_js(property_name),
         value=escape_js(property_value)
     ))
Ejemplo n.º 3
0
    def init_storage(self):
        frame = self.parent().web_page.mainFrame()
        eval_expr = u"eval({})".format(
            escape_js("""
        (function() {{
            var storage = window[{storage_name}];

            storage.events = {{}};

            storage.callMethod = function(methodName) {{
                return function(eventId) {{
                    var eventsStorage = window[{storage_name}].events;
                    eventsStorage[eventId][methodName].call(eventsStorage[eventId]);
                }};
            }}

            storage.preventDefault.connect(storage.callMethod('preventDefault'))
            storage.stopImmediatePropagation.connect(storage.callMethod('stopImmediatePropagation'))
            storage.stopPropagation.connect(storage.callMethod('stopPropagation'))

            storage.add = function(event) {{
                var id = storage.getId()
                storage.events[id] = event;
                return id;
            }}
        }})()
        """.format(storage_name=escape_js(self.name))))

        frame.evaluateJavaScript(eval_expr)
Ejemplo n.º 4
0
 def remove_event(self, event_id):
     js_func = """
     delete window[{storage_name}].events[{event_id}]
     """.format(
         storage_name=escape_js(self.name),
         event_id=escape_js(event_id),
     )
     escape_and_evaljs(self.parent().web_page.mainFrame(), js_func)
Ejemplo n.º 5
0
    def get_event_property(self, event_id, property_name):
        js_func = """
        window[{storage_name}].events[{event_id}][{property_name}]
        """.format(storage_name=escape_js(self.name),
                   event_id=escape_js(event_id),
                   property_name=escape_js(property_name))

        result = escape_and_evaljs(self.parent().web_page.mainFrame(), js_func)

        return result.get('result', None)
Ejemplo n.º 6
0
    def set_event_handler(self, event_name, handler):
        """ Set on-event type event listeners to the element """
        handler_id = self.event_handlers_storage.add(handler)

        func = u"window[{storage_name}][{func_id}]".format(
            storage_name=escape_js(self.event_handlers_storage.name),
            func_id=escape_js(handler_id),
        )

        self.tab.evaljs(u"{element}['on' + {event_name}] = {func}".format(
            element=self.element_js,
            event_name=escape_js(event_name),
            func=func))

        return handler_id
Ejemplo n.º 7
0
 def remove_event_handler(self, event_name, handler_id):
     """
     Remove event listeners from the element for the specified event
     and handler.
     """
     func = u"window[{storage_name}][{func_id}]".format(
         storage_name=escape_js(self.event_handlers_storage.name),
         func_id=escape_js(handler_id),
     )
     self.tab.evaljs(u"{element}.removeEventListener({event_name}, {func})".format(
         element=self.element_js,
         event_name=escape_js(event_name),
         func=func
     ))
     self.event_handlers_storage.remove(handler_id)
Ejemplo n.º 8
0
 def remove_event_handler(self, event_name, handler_id):
     """
     Remove event listeners from the element for the specified event
     and handler.
     """
     func = u"window[{storage_name}][{func_id}]".format(
         storage_name=escape_js(self.event_handlers_storage.name),
         func_id=escape_js(handler_id),
     )
     self.tab.evaljs(u"{element}.removeEventListener({event_name}, {func})".format(
         element=self.element_js,
         event_name=escape_js(event_name),
         func=func
     ))
     self.event_handlers_storage.remove(handler_id)
Ejemplo n.º 9
0
 def unset_event_handler(self, event_name, handler_id):
     """ Remove on-event type event listeners from the element """
     self.tab.evaljs(u"{element}['on' + {event_name}] = null".format(
         element=self.element_js,
         event_name=escape_js(event_name),
     ))
     self.event_handlers_storage.remove(handler_id)
Ejemplo n.º 10
0
    def set_event_handler(self, event_name, handler):
        """ Set on-event type event listeners to the element """
        handler_id = self.event_handlers_storage.add(handler)

        func = u"window[{storage_name}][{func_id}]".format(
            storage_name=escape_js(self.event_handlers_storage.name),
            func_id=escape_js(handler_id),
        )

        self.tab.evaljs(u"{element}['on' + {event_name}] = {func}".format(
            element=self.element_js,
            event_name=escape_js(event_name),
            func=func
        ))

        return handler_id
Ejemplo n.º 11
0
    def __call__(self, *args):
        expr = "eval('('+{func_text}+')')({args})".format(
            func_text=self.source,
            args=escape_js(*args)
        )
        wrapper_script = get_process_errors_js(expr)
        res = self.tab.evaljs(wrapper_script)

        if not isinstance(res, dict):
            raise ScriptError({
                'type': ScriptError.UNKNOWN_ERROR,
                'js_error_message': res,
                'message': "unknown error during JS function call: "
                           "{!r}; {!r}".format(res, wrapper_script)
            })

        if res.get("error", False):
            err_message = res.get('errorMessage')
            err_type = res.get('errorType', '<custom JS error>')
            err_repr = res.get('errorRepr', '<unknown JS error>')
            if err_message is None:
                err_message = err_repr
            raise ScriptError({
                'type': ScriptError.JS_ERROR,
                'js_error_type': err_type,
                'js_error_message': err_message,
                'js_error': err_repr,
                'message': "error during JS function call: "
                           "{!r}".format(err_repr)
            })

        return res.get("result")
Ejemplo n.º 12
0
 def unset_event_handler(self, event_name, handler_id):
     """ Remove on-event type event listeners from the element """
     self.tab.evaljs(u"{element}['on' + {event_name}] = null".format(
         element=self.element_js,
         event_name=escape_js(event_name),
     ))
     self.event_handlers_storage.remove(handler_id)
Ejemplo n.º 13
0
    def add_event_handler(self, event_name, handler, options=None):
        """ Add event listeners to the element for the specified event """
        handler_id = self.event_handlers_storage.add(handler)

        func = u"window[{storage_name}][{func_id}]".format(
            storage_name=escape_js(self.event_handlers_storage.name),
            func_id=escape_js(handler_id),
        )

        self.tab.evaljs(u"{element}.addEventListener({event_name}, {func}, {options})".format(
            element=self.element_js,
            event_name=escape_js(event_name),
            func=func,
            options=escape_js(options)
        ))

        return handler_id
Ejemplo n.º 14
0
 def fill(self, values):
     """ Fill the values of the element """
     return self.tab.evaljs(u"({fill_form_values_func})({element}, {values}, {set_field_value})".format(
         fill_form_values_func=FILL_FORM_VALUES_JS,
         element=self.element_js,
         values=escape_js(values),
         set_field_value=SET_FIELD_VALUE_JS
     ))
Ejemplo n.º 15
0
    def select_all(self, selector):
        """ Select DOM elements and return a list of instances of `HTMLElement`

        :param selector valid CSS selector
        :return list of elements
        """
        js_query = u"document.querySelectorAll({})".format(escape_js(selector))
        return self.evaljs(js_query)
Ejemplo n.º 16
0
    def add(self, func):
        func_id = get_id()

        event_wrapper = u"window[{storage_name}].add(event)".format(
            storage_name=escape_js(self.events_storage.name), )
        js_func = u"window[{storage_name}][{func_id}] = " \
                  u"function(event) {{ window[{storage_name}].run({func_id}, {event}, event) }}"\
            .format(
                storage_name=escape_js(self.name),
                func_id=escape_js(func_id),
                event=event_wrapper
            )

        escape_and_evaljs(self.parent().web_page.mainFrame(), js_func)

        self.storage[func_id] = func
        return func_id
Ejemplo n.º 17
0
    def add_event_handler(self, event_name, handler, options=None):
        """ Add event listeners to the element for the specified event """
        handler_id = self.event_handlers_storage.add(handler)

        func = u"window[{storage_name}][{func_id}]".format(
            storage_name=escape_js(self.event_handlers_storage.name),
            func_id=escape_js(handler_id),
        )

        self.tab.evaljs(u"{element}.addEventListener({event_name}, {func}, {options})".format(
            element=self.element_js,
            event_name=escape_js(event_name),
            func=func,
            options=escape_js(options)
        ))

        return handler_id
Ejemplo n.º 18
0
 def fill(self, values):
     """ Fill the values of the element """
     return self.tab.evaljs(u"({fill_form_values_func})({element}, {values}, {set_field_value})".format(
         fill_form_values_func=FILL_FORM_VALUES_JS,
         element=self.element_js,
         values=escape_js(values),
         set_field_value=SET_FIELD_VALUE_JS
     ))
Ejemplo n.º 19
0
 def __init__(self, splash, source):
     """
     :param splash.browser_tab.BrowserTab tab: BrowserTab object
     :param str source: function source code
     """
     self.lua = splash.lua
     self.tab = splash.tab
     self.source = escape_js(source)
     self.exceptions = splash.exceptions
Ejemplo n.º 20
0
    def form_values(self, values='auto'):
        """ Return all values of the element if it is a form"""
        self.assert_node_type('form')

        return self.tab.evaljs(u"({form_values_func})({element}, {values}, {field_value_func})".format(
            form_values_func=FORM_VALUES_JS,
            field_value_func=FIELD_VALUE_JS,
            values=escape_js(values),
            element=self.element_js
        ))
Ejemplo n.º 21
0
    def form_values(self, values='auto'):
        """ Return all values of the element if it is a form"""
        self.assert_node_type('form')

        return self.tab.evaljs(u"({form_values_func})({element}, {values}, {field_value_func})".format(
            form_values_func=FORM_VALUES_JS,
            field_value_func=FIELD_VALUE_JS,
            values=escape_js(values),
            element=self.element_js
        ))
Ejemplo n.º 22
0
    def node_method(self, method_name):
        """ Return function which calls the specified method of the element """
        method_name = escape_js(method_name)
        @empty_strings_as_none
        def call(*args):
            return self.tab.evaljs(u"{element}[{method}]({args})".format(
                element=self.element_js,
                method=method_name,
                args=escape_js_args(*args)
            ))

        return call
Ejemplo n.º 23
0
    def node_method(self, method_name):
        """ Return function which calls the specified method of the element """
        method_name = escape_js(method_name)
        @empty_strings_as_none
        def call(*args):
            return self.tab.evaljs(u"{element}[{method}]({args})".format(
                element=self.element_js,
                method=method_name,
                args=escape_js_args(*args)
            ))

        return call
Ejemplo n.º 24
0
    def select(self, selector):
        """ Select DOM element and return an instance of `HTMLElement`

        :param selector valid CSS selector
        :return element
        """
        js_query = u"document.querySelector({})".format(escape_js(selector))
        result = self.evaljs(js_query)

        if result == "":
            return None

        return result
Ejemplo n.º 25
0
    def evaljs(self, js_source, handle_errors=True, result_protection=True):
        """
        Run JS code in page context and return the result.

        If JavaScript exception or an syntax error happens
        and `handle_errors` is True then Python JsError
        exception is raised.

        When `result_protection` is True (default) protection against
        badly written or malicious scripts is activated. Disable it
        when the script result is known to be good, i.e. it only
        contains objects/arrays/primitives without circular references.
        """
        frame = self.web_page.mainFrame()
        eval_expr = u"eval({})".format(escape_js(js_source))

        if result_protection:
            eval_expr = get_sanitized_result_js(eval_expr)

        if not handle_errors:
            return qt2py(frame.evaluateJavaScript(eval_expr))

        res = frame.evaluateJavaScript(get_process_errors_js(eval_expr))

        if not isinstance(res, dict):
            raise JsError({
                'type': ScriptError.UNKNOWN_ERROR,
                'js_error_message': res,
                'message': "unknown JS error: {!r}".format(res)
            })

        if res.get("error", False):
            err_message = res.get('errorMessage')
            err_type = res.get('errorType', '<custom JS error>')
            err_repr = res.get('errorRepr', '<unknown JS error>')
            if err_message is None:
                err_message = err_repr
            raise JsError({
                'type': ScriptError.JS_ERROR,
                'js_error_type': err_type,
                'js_error_message': err_message,
                'js_error': err_repr,
                'message': "JS error: {!r}".format(err_repr)
            })

        return res.get("result", None)
Ejemplo n.º 26
0
    def evaljs(self, js_source, handle_errors=True, result_protection=True):
        """
        Run JS code in page context and return the result.

        If JavaScript exception or an syntax error happens
        and `handle_errors` is True then Python JsError
        exception is raised.

        When `result_protection` is True (default) protection against
        badly written or malicious scripts is activated. Disable it
        when the script result is known to be good, i.e. it only
        contains objects/arrays/primitives without circular references.
        """
        frame = self.web_page.mainFrame()
        eval_expr = u"eval({})".format(escape_js(js_source))

        if result_protection:
            eval_expr = get_sanitized_result_js(eval_expr)

        if not handle_errors:
            return qt2py(frame.evaluateJavaScript(eval_expr))

        res = frame.evaluateJavaScript(get_process_errors_js(eval_expr))

        if not isinstance(res, dict):
            raise JsError({
                'type': ScriptError.UNKNOWN_ERROR,
                'js_error_message': res,
                'message': "unknown JS error: {!r}".format(res)
            })

        if res.get("error", False):
            err_message = res.get('errorMessage')
            err_type = res.get('errorType', '<custom JS error>')
            err_repr = res.get('errorRepr', '<unknown JS error>')
            if err_message is None:
                err_message = err_repr
            raise JsError({
                'type': ScriptError.JS_ERROR,
                'js_error_type': err_type,
                'js_error_message': err_message,
                'js_error': err_repr,
                'message': "JS error: {!r}".format(err_repr)
            })

        return res.get("result", None)
Ejemplo n.º 27
0
    def evaljs(self,
               js_source,
               handle_errors=True,
               result_protection=True,
               dom_elements=True):
        """
        Run JS code in page context and return the result.

        If JavaScript exception or an syntax error happens
        and `handle_errors` is True then Python JsError
        exception is raised.

        When `result_protection` is True (default) protection against
        badly written or malicious scripts is activated. Disable it
        when the script result is known to be good, i.e. it only
        contains objects/arrays/primitives without circular references.

        When `dom_elements` is True (default) top-level DOM elements will be
        saved in JS field of window object under `self._elements_storage.name`
        key. The result of evaluation will be object with `type` property and
        `id` property. In JS the original DOM element can accessed through
        ``window[self._elements_storage.name][id]``.
        """
        frame = self.web_page.mainFrame()
        eval_expr = u"eval({})".format(escape_js(js_source))

        if dom_elements:
            self._init_js_objects_storage()
            eval_expr = store_dom_elements(eval_expr,
                                           self._elements_storage.name)
        if result_protection:
            eval_expr = get_sanitized_result_js(eval_expr)

        if handle_errors:
            res = frame.evaluateJavaScript(get_process_errors_js(eval_expr))

            if not isinstance(res, dict):
                raise JsError({
                    'type': ScriptError.UNKNOWN_ERROR,
                    'js_error_message': res,
                    'message': "unknown JS error: {!r}".format(res)
                })

            if res.get("error", False):
                err_message = res.get('errorMessage')
                err_type = res.get('errorType', '<custom JS error>')
                err_repr = res.get('errorRepr', '<unknown JS error>')
                if err_message is None:
                    err_message = err_repr
                raise JsError({
                    'type': ScriptError.JS_ERROR,
                    'js_error_type': err_type,
                    'js_error_message': err_message,
                    'js_error': err_repr,
                    'message': "JS error: {!r}".format(err_repr)
                })

            result = res.get("result", None)
        else:
            result = qt2py(frame.evaluateJavaScript(eval_expr))

        return self._process_js_result(result, allow_dom=dom_elements)
Ejemplo n.º 28
0
 def node_property(self, property_name):
     """ Return value of the specified property of the element """
     return self.tab.evaljs(u"{element}[{property}]".format(
         element=self.element_js,
         property=escape_js(property_name)
     ))
Ejemplo n.º 29
0
def escape_js_args(*args):
    return ','.join([
        arg.element_js if isinstance(arg, HTMLElement) else escape_js(arg)
        for arg in args
    ])
Ejemplo n.º 30
0
 def get_node_style(self, property_name):
     """ Get value of the style property of the element """
     return self.tab.evaljs(u"{element}.style[{property}]".format(
         element=self.element_js,
         property=escape_js(property_name),
     ))
Ejemplo n.º 31
0
def escape_and_evaljs(frame, js_func):
    eval_expr = u"eval({})".format(escape_js(js_func))
    return frame.evaluateJavaScript(get_process_errors_js(eval_expr))
Ejemplo n.º 32
0
 def call(*args):
     return self.tab.evaljs(u"{element}[{method}]({args})".format(
         element=self.element_js,
         method=escape_js(method_name),
         args=escape_js_args(*args)))
Ejemplo n.º 33
0
    def wait_for_resume(self, js_source, callback, errback, timeout):
        """
        Run some Javascript asynchronously.

        The JavaScript must contain a method called `main()` that accepts
        one argument. The first argument will be an object with `resume()`
        and `error()` methods. The code _must_ call one of these functions
        before the timeout or else it will be canceled.
        """

        frame = self.web_page.mainFrame()
        callback_proxy = OneShotCallbackProxy(self, callback, errback, timeout)
        self._callback_proxies_to_cancel.add(callback_proxy)
        frame.addToJavaScriptWindowObject(callback_proxy.name, callback_proxy)

        wrapped = u"""
        (function () {
            try {
                eval(%(script_text)s);
            } catch (err) {
                var main = function (splash) {
                    throw err;
                }
            }
            (function () {
                var sanitize = %(sanitize_func)s;
                var _result = {};
                var _splash = window["%(callback_name)s"];
                var splash = {
                    'error': function (message) {
                        _splash.error(message, false);
                    },
                    'resume': function (value) {
                        _result['value'] = value;
                        try {
                            _splash.resume(sanitize(_result));
                        } catch (err) {
                            _splash.error(err, true);
                        }
                    },
                    'set': function (key, value) {
                        _result[key] = value;
                    }
                };
                delete window["%(callback_name)s"];
                try {
                    if (typeof main === 'undefined') {
                        throw "wait_for_resume(): no main() function defined";
                    }
                    main(splash);
                } catch (err) {
                    _splash.error(err, true);
                }
            })();
        })();undefined
        """ % dict(
            sanitize_func=SANITIZE_FUNC_JS,
            script_text=escape_js(js_source),
            callback_name=callback_proxy.name
        )

        def cancel_callback():
            callback_proxy.cancel(reason='javascript window object cleared')

        self.logger.log("wait_for_resume wrapped script:\n%s" % wrapped,
                        min_level=3)
        frame.javaScriptWindowObjectCleared.connect(cancel_callback)
        frame.evaluateJavaScript(wrapped)
Ejemplo n.º 34
0
 def get_node_style(self, property_name):
     """ Get value of the style property of the element """
     return self.tab.evaljs(u"{element}.style[{property}]".format(
         element=self.element_js,
         property=escape_js(property_name),
     ))
Ejemplo n.º 35
0
 def node_property(self, property_name):
     """ Return value of the specified property of the element """
     return self.tab.evaljs(u"{element}[{property}]".format(
         element=self.element_js,
         property=escape_js(property_name)
     ))
Ejemplo n.º 36
0
def escape_js_args(*args):
    return ','.join([
        arg.element_js if isinstance(arg, HTMLElement) else escape_js(arg)
        for arg in args
    ])
Ejemplo n.º 37
0
    def wait_for_resume(self, js_source, callback, errback, timeout):
        """
        Run some Javascript asynchronously.

        The JavaScript must contain a method called `main()` that accepts
        one argument. The first argument will be an object with `resume()`
        and `error()` methods. The code _must_ call one of these functions
        before the timeout or else it will be canceled.
        """

        frame = self.web_page.mainFrame()
        callback_proxy = OneShotCallbackProxy(self, callback, errback, timeout)
        self._callback_proxies_to_cancel.add(callback_proxy)
        frame.addToJavaScriptWindowObject(callback_proxy.name, callback_proxy)

        wrapped = u"""
        (function () {
            try {
                eval(%(script_text)s);
            } catch (err) {
                var main = function (splash) {
                    throw err;
                }
            }
            (function () {
                var sanitize = %(sanitize_func)s;
                var _result = {};
                var _splash = window["%(callback_name)s"];
                var splash = {
                    'error': function (message) {
                        _splash.error(message, false);
                    },
                    'resume': function (value) {
                        _result['value'] = value;
                        try {
                            _splash.resume(sanitize(_result));
                        } catch (err) {
                            _splash.error(err, true);
                        }
                    },
                    'set': function (key, value) {
                        _result[key] = value;
                    }
                };
                delete window["%(callback_name)s"];
                try {
                    if (typeof main === 'undefined') {
                        throw "wait_for_resume(): no main() function defined";
                    }
                    main(splash);
                } catch (err) {
                    _splash.error(err, true);
                }
            })();
        })();undefined
        """ % dict(sanitize_func=SANITIZE_FUNC_JS,
                   script_text=escape_js(js_source),
                   callback_name=callback_proxy.name)

        def cancel_callback():
            callback_proxy.cancel(reason='javascript window object cleared')

        self.logger.log("wait_for_resume wrapped script:\n%s" % wrapped,
                        min_level=3)
        frame.javaScriptWindowObjectCleared.connect(cancel_callback)
        frame.evaluateJavaScript(wrapped)
Ejemplo n.º 38
0
 def call(*args):
     return self.tab.evaljs(u"{element}[{method}]({args})".format(
         element=self.element_js,
         method=escape_js(method_name),
         args=escape_js_args(*args)
     ))