Page tree
Skip to end of metadata
Go to start of metadata

JSAPIAuto provides convenience facilities for writing scriptable objects.

Overview

While JSAPI and JSAPISimple provide all you need to implement scriptable classes, you might get annoyed by the amount of code needed for converting the data that comes in from JavaScript - thats where JSAPIAuto comes to the rescue.

See Also: FireBreath Tips: Dealing with JSAPI objects

Consider adding a simple method to your class that adds two numbers:

FB::variant add(const FB::VariantList& values)
{
    if(values.size() != 2)
        throw FB::script_error("wrong number of arguments");
    try {
        long a = values[0].convert_cast<long>();
        long b = values[1].convert_cast<long>();
        return a+b;
    } catch(FB::bad_variant_cast& e) {
        throw FB::script_error("conversion failed :(");
    }
}

Thats quite verbose and annoying to do in every method. JSAPIAuto allows you the following instead:

long add(long a, long b)
{
    return a+b;
}

That is made possible by introducing helper functions for methods and properties, FB::make_method() and FB::make_property() that you use when registering:

registerMethod("add", FB::make_method(this, &MyClass::add));

make_method() inspects the arguments your methods expect and generates the neccessary code for conversion and checking the argument count.

Basic usage

To make your class scriptable with JSAPIAuto, derive from it and register your methods and properties, e.g. in the constructor:

MyObject.h
#include "JSAPIAuto.h"
 
class MyObject : public FB::JSAPIAuto
{
    std::string m_message;
public:
    MyObject()
    {
        registerMethod("add", FB::make_method(this, &MyObject::add));
        registerProperty("message",
                         FB::make_property(this,
                             &MyObject::getMessage,
                             &MyObject::setMessage));
    }

    long add(long a, long b) { return a+b; }
    void setMessage(const std::string& s) { m_message = s; }
    std::string getMessage() const { return m_message; }
};

Properties

For property registration, combine registerProperty() with make_property().

make_property() supports two forms of properties:

Read-only properties

make_property(this, &MyClass::getter), where getter is a function that takes no arguments and returns a type that FB::variant can be constructed from.

Read-write properties

make_property(this, &MyClass::getter, &MyClass::setter), where getter is of the same form as before and setter is a function that takes one argument that FB::variant can convert to and has a return type of void.

Supported types

For property functions, the same types are supported as for methods - except that property setters can only take one argument and getters none.

Methods

For method registration, combine registerMethod() with make_method(), which takes a pointer to the class' instance as its first argument and a pointer to a class method as its second.

The argument types the member function expects will be discovered at compile time and code be generated that checks the number of arguments and tries to convert the FB::variant arguments to the argument types the function expects.

Catching basic types

Most basic types (numeric, string, bool) are already supported through FB::variant convert cast:

std::string MyAPI::test(long l, double d, const std::string& s, bool b)
{
    std::ostringstream os;
    os << "got " << l << ", " << d << ", '" << s << "', " << b;
    return os.str();
}

Catching containers

To receive arrays from JavaScript you can either use FB::VariantList as the arguments type or directly any STL-style container with the value-type of choice.

Take for example the following JavaScript-call:

plugin.foo(new Array(1, "2", 3.0));

We can catch the argument either as a variant array:

bool foo(const FB::VariantList& array);

Alternatively we can try to catch it as a container of strings:

bool foo(const std::vector<std::string>& array);

Catching associative containers

Catching objects

To catch scriptable objects, use FB::JSObjectPtr:

void MyAPI::doFoo(const FB::JSObjectPtr& obj, const FB::Variant& arg)
{
    obj->Invoke("foo", FB::variant_list_of(arg));
}

Catching JavaScript functions

JavaScript functions are objects too, so use FB::JSObjectPtr and use "" as the method name to invoke the default method:

void MyAPI::doFoo(const FB::JSObjectPtr& function)
{
    function->Invoke("", FB::variant_list_of("hi")("there"));
}

Catching a variable number of arguments

In some cases we still want the users to pass a variable number of arguments to our plugin.

Lets take the following for example:

plugin.addStuff('my stuff', 1, "2", 3.0);

We could either catch them all as a VariantList:

bool MyAPI::addStuff(const FB::CatchAll& args)
{
    const FB::VariantList& values = args.value;
    // ... values contains "my stuff",1,"2",3.0
    return true;
}

Or, if we always expect some arguments just use CatchAll as the last argument:

bool MyAPI::addStuff(const std::string& what, const FB::CatchAll& args)
{
    const FB::VariantList& values = args.value;
    // ... values contains 1,"2",3.0
    return true;
}

Returning basic types

Everything directly supported by FB::variant (long, double, std::string, bool) can simply be used as a return type:

std::string MyAPI::concat(const std::string& a, const std::string& b)
{
    return a+b;
}

Returning containers

You can directly return FB::VariantList and FB::VariantMap:

FB::VariantList MyAPI::numbers()
{
    return FB::variant_list_of(1)(2)(3);
}

FB::VariantMap MyAPI::squares()
{
    return FB::variant_map_of(1,1)(2,4)(3,9);
}

Returning objects

For objects to be returned, they have to implement FB::JSAPI and FB::JSAPIPtr should be used as the return type:

FB::JSAPIPtr MyAPI::createSomeObject()
{
    return boost::make_shared<SomeObject>(m_browserHost); // SomeObject implements JSAPI
}

Remember that all JSAPIAuto-derived classes qualify.

Events

To allow events to work in Internet Explorer as well, you tell JSAPIAuto what events you support by registering them with registerEvent(const std::string& name) in the constructor.

Events can be fired using FireEvent(const std::string& name, FB::VariantList& arguments).

Example:

MyPluginAPI::MyPluginAPI(FB::BrowserHostPtr host)
  // ...
{
    // ...
    registerEvent("onready");
}

void MyPluginAPI::doSomething()
{
    // ...
    FireEvent("onready", FB::variant_list_of("hi")("there"));
}

Callbacks from Scripts

To ease working with callbacks from the scripts, make_callback() can be used to create an opaque wrapper:

#include "JSCallback.h"

void MyPluginAPI::onAlert(const std::string& message) { /* ... */ }

void MyPluginAPI::doStuff()
{
    someJsObject->Invoke("addEventListener", variant_list_of("alert", make_callback(this, &MyPluginAPI::onAlert)));
}

Class generated docs

class FB JSAPIAuto

JSAPIAuto Class Diagram

JSAPIAutoClassDiagram
  • No labels

2 Comments

  1. Hi everybody!

    I'm sorry because posting here. (I cannot log into forum).

    I'm learning FireBreath again. I have created a plugin (VS2010) well. I'm adding some mothods and properties well. But when adding square method about:

    FB::VariantMap MyAPI::squares()
    {
        return FB::variant_map_of(1,1)(2,4)(3,9);
    }
    I cannot build: error C2664: 'std::map<_Kty,_Ty>::map(const std::map<_Kty,_Ty> &)' : cannot convert parameter 1 from 'FB::detail::VariantMapInserter<T>' to 'const std::map<_Kty,_Ty> &'
    Because cannot convert from 'FB::detail::VariantMapInserter to FB::VariantMap (const std::map).

    Can you help me to fix that error?
    Thanks!
  2. Unknown User (pnd1305)

    JSAPIJSAPISimple对象提供  了所需要脚本类,把JavaScript数据转换成JSAPI可识别的数据类型需要编写大量代码,可是不必这样,因为有 JSAPIAuto 对象.

    如例子所示,为每个函数编写这样的语句是很烦的. 但JSAPIAuto允许这样编写:

    make_method()为你考虑了你的方法参数类型和参数数量,并自动生成必要的代码.

    属性使用 registerProperty() 结合 make_property()  登记属性.

    make_property()支持两类格式:只读和读写

    make_property(this, &MyClass::getter)getter 是无参数函数,返回值 FB::variant .

    make_property(this, &MyClass::getter, &MyClass::setter),  getter 同上, setter 是有一个参数 FB::variant ,无返回值.

    支持类型

    参数支持的类型,属性相关的函数等同方法相关的函数。

    方法

    结合 registerMethod()make_method() 来登记方法, 首个参数是本类实例的指针this,第二个参数才是本方法.方法的参数是在编码时候才自动编译.

    类型转换 JS的 array -->JSAPI 的const FB::VariantList&const std::vector<std::string>&

    JS的 object --->JSAPI 的const FB::JSObjectPtr&