| Index: src/GlobalJsObject.cpp |
| =================================================================== |
| --- a/src/GlobalJsObject.cpp |
| +++ b/src/GlobalJsObject.cpp |
| @@ -1,7 +1,87 @@ |
| +#include <vector> |
| +#include <stdexcept> |
| + |
| #include "GlobalJsObject.h" |
| +#include "Thread.h" |
| using namespace AdblockPlus; |
| +namespace |
| +{ |
| + class TimeoutThread : public Thread |
| + { |
| + public: |
| + TimeoutThread(v8::Isolate* const isolate, const v8::Arguments& arguments) |
| + : isolate(isolate) |
| + { |
| + if (arguments.Length() < 2) |
| + throw std::runtime_error("setTimeout requires at least 2 parameters"); |
| + |
| + const v8::Local<v8::Value> functionValue = arguments[0]; |
| + if (!functionValue->IsFunction()) |
| + throw std::runtime_error("No valid function passed to setTimeout"); |
|
Wladimir Palant
2013/04/08 14:03:47
Nit: I think the canonical message is: "First argu
|
| + |
| + const v8::Local<v8::Value> delayValue = arguments[1]; |
| + if (!delayValue->IsNumber()) |
| + throw std::runtime_error("No valid delay passed to setTimeout"); |
|
Wladimir Palant
2013/04/08 14:03:47
Nit: I think the canonical message is: "Second arg
|
| + |
| + function = v8::Persistent<v8::Function>::New( |
| + isolate, v8::Local<v8::Function>::Cast(functionValue)); |
| + delay = delayValue->ToNumber()->Value(); |
| + for (int i = 2; i < arguments.Length(); i++) |
| + { |
| + const Value argument = Value::New(isolate, arguments[i]); |
| + functionArguments.push_back(argument); |
| + } |
| + } |
| + |
| + ~TimeoutThread() |
| + { |
| + function.Dispose(isolate); |
| + for (Values::iterator it = functionArguments.begin(); |
| + it != functionArguments.end(); it++) |
| + it->Dispose(isolate); |
| + } |
| + |
| + void Run() |
| + { |
| + Sleep(delay); |
| + const v8::Locker locker(isolate); |
| + const v8::HandleScope handleScope; |
| + function->Call(function, functionArguments.size(), &functionArguments[0]); |
| + delete this; |
| + } |
| + |
| + private: |
| + typedef v8::Persistent<v8::Value> Value; |
| + typedef std::vector<Value> Values; |
| + |
| + v8::Isolate* const isolate; |
| + v8::Persistent<v8::Function> function; |
| + int delay; |
| + Values functionArguments; |
| + }; |
| + |
| + v8::Handle<v8::Value> SetTimeoutCallback(const v8::Arguments& arguments) |
| + { |
| + TimeoutThread* timeoutThread; |
| + try |
| + { |
| + timeoutThread = new TimeoutThread(v8::Isolate::GetCurrent(), arguments); |
| + } |
| + catch (const std::exception& e) |
| + { |
| + return v8::ThrowException(v8::String::New(e.what())); |
| + } |
| + timeoutThread->Start(); |
| + |
| + // We should actually return the timer ID here, which could be |
| + // used via clearTimeout(). But since we don't seem to need |
| + // clearTimeout(), we can save that for later. |
| + return v8::Undefined(); |
| + } |
| +} |
| + |
| v8::Handle<v8::ObjectTemplate> GlobalJsObject::Create( |
| ErrorCallback& errorCallback) |
| { |
| @@ -11,5 +91,8 @@ |
| const v8::Handle<v8::ObjectTemplate> console = |
| AdblockPlus::ConsoleJsObject::Create(errorCallback); |
| global->Set(v8::String::New("console"), console); |
| + const v8::Handle<v8::FunctionTemplate> setTimeoutFunction = |
| + v8::FunctionTemplate::New(SetTimeoutCallback); |
| + global->Set(v8::String::New("setTimeout"), setTimeoutFunction); |
| return handleScope.Close(global); |
| } |