FireBreath  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Pages
JSObject.h
1 /**********************************************************\
2 Original Author: Richard Bateman (taxilian)
3 
4 Created: Oct 17, 2009
5 License: Dual license model; choose one of two:
6  New BSD License
7  http://www.opensource.org/licenses/bsd-license.php
8  - or -
9  GNU Lesser General Public License, version 2.1
10  http://www.gnu.org/licenses/lgpl-2.1.html
11 
12 Copyright 2009 Richard Bateman, Firebreath development team
13 \**********************************************************/
14 
15 #pragma once
16 #ifndef H_FB_JSObject
17 #define H_FB_JSObject
18 
19 #include "JSAPI.h"
20 #include "BrowserHost.h"
21 #include "variant_list.h"
22 #include "variant_map.h"
23 #include <iterator>
24 
25 namespace FB
26 {
27  FB_FORWARD_PTR(JSObject);
46  class JSObject : public FB::JSAPI
47  {
48  public:
49 
57  JSObject(const BrowserHostPtr& h) : m_host(h)
58  {
59  }
60 
66  virtual ~JSObject() {}
67 
68  virtual void *getEventId() const { return NULL; }
69  virtual void *getEventContext() const { return NULL; }
70 
71  virtual bool supportsOptimizedCalls() const { return false; }
72  virtual void callMultipleFunctions(const std::string& name, const FB::VariantList& args,
73  const std::vector<JSObjectPtr>& direct,
74  const std::vector<JSObjectPtr>& ifaces) {};
75  virtual bool isValid() = 0;
76 
77  JSObjectPtr shared_from_this() { return boost::static_pointer_cast<JSObject>(JSAPI::shared_from_this()); }
78  boost::shared_ptr<const JSObject> shared_from_this() const { return boost::static_pointer_cast<const JSObject>(JSAPI::shared_from_this()); }
79 
90  virtual void InvokeAsync(const std::string& methodName, const std::vector<variant>& args)
91  {
92  BrowserHostPtr host(m_host.lock());
93  if (!host) {
94  throw std::runtime_error("Cannot invoke asynchronously");
95  }
96  host->ScheduleOnMainThread(shared_from_this(), boost::bind(&JSObject::_invokeAsync, this, args, methodName));
97  }
98 
99  private:
100  virtual void _invokeAsync(const std::vector<variant>& args, const std::string& methodName)
101  {
102  BrowserHostPtr host(m_host.lock());
103  if (host) {
104  host->delayedInvoke(0, shared_from_this(), args, methodName);
105  }
106  }
107  public:
108 
118  virtual void SetPropertyAsync(const std::string& propertyName, const variant& value)
119  {
120  BrowserHostPtr host(m_host.lock());
121  if (!host) {
122  throw std::runtime_error("Cannot invoke asynchronously");
123  }
124  host->ScheduleOnMainThread(shared_from_this(), boost::bind((FB::SetPropertyType)&JSAPI::SetProperty, this, propertyName, value));
125  }
126  public:
139  template<class Cont>
140  static void GetArrayValues(const FB::JSObjectPtr& src, Cont& dst);
141 
151  template<class Dict>
152  static void GetObjectValues(const FB::JSObjectPtr& src, Dict& dst);
153 
154  public:
156  virtual JSAPIPtr getJSAPI() const = 0;
158  BrowserHostPtr getHost() { return BrowserHostPtr(m_host); }
159 
160  public:
161  BrowserHostWeakPtr m_host;
162  };
163 
164  template<class Cont>
165  void JSObject::GetArrayValues(const FB::JSObjectPtr& src, Cont& dst)
166  {
167  if (!src) {
168  return;
169  }
170  try {
171  FB::variant tmp = src->GetProperty("length");
172  long length = tmp.convert_cast<long>();
173  std::back_insert_iterator<Cont> inserter(dst);
174 
175  for(int i=0; i<length; ++i) {
176  tmp = src->GetProperty(i);
177  *inserter++ = tmp.convert_cast<typename Cont::value_type>();
178  }
179  } catch(const FB::script_error& e) {
180  throw e;
181  }
182  }
183 
184  template<class Dict>
185  void JSObject::GetObjectValues(const FB::JSObjectPtr& src, Dict& dst)
186  {
187  typedef typename Dict::key_type KeyType;
188  typedef typename Dict::mapped_type MappedType;
189  typedef std::pair<KeyType, MappedType> PairType;
190  typedef std::vector<std::string> StringVec;
191 
192  if (!src) return;
193  try {
194  StringVec fields;
195  src->getMemberNames(fields);
196  std::insert_iterator<Dict> inserter(dst, dst.begin());
197 
198  for(StringVec::iterator it = fields.begin(); it != fields.end(); it++) {
199  FB::variant tmp = src->GetProperty(*it);
200  *inserter++ = PairType(*it, tmp.convert_cast<MappedType>());
201  }
202  } catch (const FB::script_error& e) {
203  throw e;
204  }
205  }
206 
207  namespace variant_detail { namespace conversion {
208  // Convert in
209  template <class T>
210  typename boost::enable_if<
211  boost::mpl::and_<
212  boost::is_base_of<FB::JSAPI, T>,
213  boost::mpl::not_<boost::is_base_of<FB::JSObject, T> > >
214  ,variant>::type
215  make_variant(const boost::shared_ptr<T>& ptr) {
216  if (ptr)
217  return variant(FB::JSAPIPtr(ptr), true);
218  else
219  return variant(FB::FBNull());
220  }
221  template <class T>
222  typename boost::enable_if<boost::is_base_of<FB::JSObject, T>,variant>::type
223  make_variant(const boost::shared_ptr<T>& ptr) {
224  if (ptr)
225  return variant(FB::JSObjectPtr(ptr), true);
226  else
227  return variant(FB::FBNull());
228  }
229 
230  template<class Cont>
231  typename boost::enable_if<
232  boost::mpl::and_<
233  FB::meta::is_non_assoc_container<Cont>,
234  boost::mpl::not_<
235  boost::mpl::or_<
236  boost::mpl::or_<
237  boost::is_same<std::vector<variant>, Cont>,
238  boost::is_same<std::map<std::string, variant>, Cont>
239  >,
240  boost::mpl::or_<
241  boost::is_same<std::wstring, Cont>,
242  boost::is_same<std::string, Cont>
243  >
244  >
245  >
246  >
247  ,variant>::type
248  make_variant(const Cont& var) {
249  return make_variant_list(var);
250  }
251 
252  template<class Dict>
253  typename boost::enable_if<
254  boost::mpl::and_<
255  FB::meta::is_pair_assoc_container<Dict>,
256  boost::mpl::not_<
257  boost::is_same<std::map<std::string, variant>, Dict>
258  >
259  >
260  ,variant>::type
261  make_variant(const Dict& var) {
262  return make_variant_map(var);
263  }
264 
265  // Convert out
266  template<class T>
267  typename boost::enable_if<boost::is_base_of<FB::JSAPI, T>, boost::shared_ptr<T> >::type
268  convert_variant(const variant& var, type_spec< boost::shared_ptr<T> >)
269  {
270  FB::JSAPIPtr ptr;
271  // First of all, to succeed it *must* be a JSAPI object!
272  if (var.get_type() == typeid(FB::JSObjectPtr)) {
273  ptr = var.cast<FB::JSObjectPtr>();
274  } else if (var.get_type() == typeid(FB::JSAPIWeakPtr)) {
275  ptr = var.cast<FB::JSAPIWeakPtr>().lock();
276  } else if (var.empty() || var.is_null()) {
277  return boost::shared_ptr<T>();
278  } else {
279  ptr = var.cast<FB::JSAPIPtr>();
280  }
281  if (!ptr)
282  return boost::shared_ptr<T>();
283 
285  if (jso) {
286  FB::JSAPIPtr inner = jso->getJSAPI();
287  if (inner) {
288  boost::shared_ptr<T> tmp = FB::ptr_cast<T>(inner);
289  if (tmp) {
290  // Whew! We pulled the JSAPI object out of a JSObject and found what we were
291  // looking for; we always return the inner-most object. Keep that in mind!
292  return tmp;
293  }
294  // If there is an inner object, but it isn't the one we want, fall through
295  }
296  }
297  boost::shared_ptr<T> ret = FB::ptr_cast<T>(ptr);
298  if (ret)
299  return ret;
300  else
301  throw FB::bad_variant_cast(var.get_type(), typeid(T));
302  }
303  template<class T>
304  typename boost::enable_if<boost::is_base_of<FB::JSAPI, T>, boost::weak_ptr<T> >::type
305  convert_variant(const variant& var, type_spec< boost::weak_ptr<T> >)
306  {
307  boost::shared_ptr<T> sptr(var.convert_cast<boost::shared_ptr<T> >());
308  return boost::weak_ptr<T>(sptr);
309  }
310 
311  template<class Cont>
312  typename FB::meta::enable_for_non_assoc_containers<Cont, const Cont>::type
313  convert_variant(const variant& var, type_spec<Cont>)
314  {
315  typedef FB::JSObjectPtr JsObject;
316 
317  // if the held data is of type Cont just return it
318 
319  if(var.is_of_type<Cont>())
320  return var.cast<Cont>();
321 
322  // if the help data is not a JavaScript object throw
323 
324  if(!var.can_be_type<JsObject>())
325  throw bad_variant_cast(var.get_type(), typeid(JsObject));
326 
327  // if it is a JavaScript object try to treat it as an array
328 
329  Cont cont;
330  FB::JSObject::GetArrayValues(var.convert_cast<JsObject>(), cont);
331  return cont;
332  }
333 
334  template<class Dict>
335  typename FB::meta::enable_for_pair_assoc_containers<Dict, const Dict>::type
336  convert_variant(const variant& var, type_spec<Dict>)
337  {
338  typedef FB::JSObjectPtr JsObject;
339 
340  // if the held data is of type Dict just return it
341 
342  if(var.is_of_type<Dict>())
343  return var.cast<Dict>();
344 
345  // if the help data is not a JavaScript object throw
346 
347  if(!var.can_be_type<JsObject>())
348  throw bad_variant_cast(var.get_type(), typeid(JsObject));
349 
350  // if it is a JavaScript object try to treat it as an array
351 
352  Dict dict;
353  FB::JSObject::GetObjectValues(var.convert_cast<JsObject>(), dict);
354  return dict;
355  }
356  } }
357 
358  // TODO: this doesn't belong here
359 
373  template<class API>
374  boost::shared_ptr<API> get_jsapi(const FB::JSObjectPtr& jso)
375  {
376  typedef boost::shared_ptr<API> APIPtr;
377 
378  if (!jso) {
379  return APIPtr();
380  }
381 
382  if (FB::JSAPIPtr jsapi = jso->getJSAPI()) {
383  return FB::ptr_cast<API>(jsapi);
384  }
385 
386  return APIPtr();
387  }
388 };
389 
390 #endif
391 
virtual void SetProperty(const std::wstring &propertyName, const variant &value)
Definition: JSAPI.h:405
virtual void InvokeAsync(const std::string &methodName, const std::vector< variant > &args)
Just like Invoke, but works asynchronously. Useful for javascript callbacks and events. Can be safely called from any thread.
Definition: JSObject.h:90
boost::shared_ptr< FB::JSObject > JSObjectPtr
Defines an alias representing a JSObject shared_ptr (you should never use a JSObject* directly) ...
Definition: APITypes.h:109
boost::shared_ptr< API > get_jsapi(const FB::JSObjectPtr &jso)
Get a JSAPI-derived interface from a JSObject.
Definition: JSObject.h:374
Wraps a Javascript Object.
Definition: JSObject.h:46
const T convert_cast() const
Converts the stored value to the requested type if possible and returns the resulting value...
Definition: variant.h:667
Accepts any datatype, used in all interactions with javascript. Provides tools for getting back out t...
Definition: variant.h:198
static void GetArrayValues(const FB::JSObjectPtr &src, Cont &dst)
Gets Array values out of src and adds them to the STL container dst.
Definition: JSObject.h:165
FB::VariantList make_variant_list(const Cont &cont)
Create a FB::VariantList from any STL-style container (i.e. exposes begin() and end()) ...
Definition: variant_list.h:151
boost::shared_ptr< T > ptr_cast(boost::shared_ptr< U > const &r)
Convenience function for doing a dynamic cast of one boost::shared_ptr to another.
Definition: APITypes.h:339
std::vector< variant > VariantList
Defines an alias representing list of variants.
Definition: APITypes.h:64
JSObject(const BrowserHostPtr &h)
Constructor.
Definition: JSObject.h:57
boost::weak_ptr< FB::JSAPI > JSAPIWeakPtr
Defines an alias for a JSAPI weak_ptr (you should never use a JSAPI* directly)
Definition: APITypes.h:88
FB::VariantMap make_variant_map(const Dict &dict)
Create a FB::VariantMap from any STL-style dictionary (i.e. exposes begin() and end()) ...
Definition: variant_map.h:165
virtual void SetPropertyAsync(const std::string &propertyName, const variant &value)
Just like SetProperty, but works asynchronously. Useful if you are running on another thread and don'...
Definition: JSObject.h:118
Thrown when variant::cast<type> or variant::convert_cast<type> fails because the type of the value st...
Definition: variant.h:133
boost::shared_ptr< FB::JSAPI > JSAPIPtr
Defines an alias for a JSAPI shared_ptr (you should never use a JSAPI* directly)
Definition: APITypes.h:94
Exception type; when thrown in a JSAPI method, a javascript exception will be thrown.
Definition: JSExceptions.h:28
boost::shared_ptr< FB::BrowserHost > BrowserHostPtr
Defines an alias representing a BrowserHost shared_ptr (you should never use a BrowserHost* directly)...
Definition: APITypes.h:117
static void GetObjectValues(const FB::JSObjectPtr &src, Dict &dst)
Gets object values out of the javscript object src and adds them to the STL Dict container dst...
Definition: JSObject.h:185
void(JSAPI::* SetPropertyType)(const std::string &, const variant &)
Defines an alias representing a function pointer to JSAPI::SetProperty.
Definition: APITypes.h:176
virtual JSAPIPtr getJSAPI() const =0
Get associated FB::JSAPI.
JavaScript API class – provides a javascript interface that can be exposed to the browser...
Definition: JSAPI.h:56
virtual ~JSObject()
Finaliser.
Definition: JSObject.h:66
BrowserHostPtr getHost()
Get the associated FB::BrowserHost; may throw std::bad_cast.
Definition: JSObject.h:158