// Copyright (c) 2019 GitHub, Inc. // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. #ifndef SHELL_COMMON_GIN_HELPER_EVENT_EMITTER_H_ #define SHELL_COMMON_GIN_HELPER_EVENT_EMITTER_H_ #include #include #include "base/optional.h" #include "electron/shell/common/api/api.mojom.h" #include "shell/common/gin_helper/event_emitter_caller.h" namespace gin_helper { namespace internal { v8::Local CreateEventObject(v8::Isolate* isolate); v8::Local CreateCustomEvent(v8::Isolate* isolate, v8::Local object, v8::Local event); v8::Local CreateEventFromFlags(v8::Isolate* isolate, int flags); } // namespace internal // Provide helperers to emit event in JavaScript. // // TODO(zcbenz): Inherit from Wrappable directly after removing native_mate. template class EventEmitter : public Base { public: typedef std::vector> ValueArray; // Make the convinient methods visible: // https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members v8::Isolate* isolate() const { return Base::isolate(); } v8::Local GetWrapper() const { return Base::GetWrapper(); } v8::MaybeLocal GetWrapper(v8::Isolate* isolate) const { return Base::GetWrapper(isolate); } // this.emit(name, event, args...); template bool EmitCustomEvent(base::StringPiece name, v8::Local event, Args&&... args) { return EmitWithEvent( name, internal::CreateCustomEvent(isolate(), GetWrapper(), event), std::forward(args)...); } // this.emit(name, new Event(flags), args...); template bool EmitWithFlags(base::StringPiece name, int flags, Args&&... args) { return EmitCustomEvent(name, internal::CreateEventFromFlags(isolate(), flags), std::forward(args)...); } // this.emit(name, new Event(), args...); template bool Emit(base::StringPiece name, Args&&... args) { v8::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); v8::Local wrapper = GetWrapper(); if (wrapper.IsEmpty()) { return false; } v8::Local event = internal::CreateEventObject(isolate()); event ->Set(isolate()->GetCurrentContext(), gin::StringToV8(isolate(), "sender"), wrapper) .IsJust(); return EmitWithEvent(name, event, std::forward(args)...); } protected: EventEmitter() {} private: // this.emit(name, event, args...); template bool EmitWithEvent(base::StringPiece name, v8::Local event, Args&&... args) { // It's possible that |this| will be deleted by EmitEvent, so save anything // we need from |this| before calling EmitEvent. auto* isolate = this->isolate(); v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); auto context = isolate->GetCurrentContext(); EmitEvent(isolate, GetWrapper(), name, event, std::forward(args)...); v8::Local defaultPrevented; if (event->Get(context, gin::StringToV8(isolate, "defaultPrevented")) .ToLocal(&defaultPrevented)) { return defaultPrevented->BooleanValue(isolate); } return false; } DISALLOW_COPY_AND_ASSIGN(EventEmitter); }; } // namespace gin_helper #endif // SHELL_COMMON_GIN_HELPER_EVENT_EMITTER_H_