#include "config.h"
#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
#include "Notification.h"
#include "DOMWindow.h"
#include "DOMWindowNotifications.h"
#include "Document.h"
#include "Event.h"
#include "EventNames.h"
#include "NotificationCenter.h"
#include "NotificationController.h"
#include "NotificationPermissionCallback.h"
#include "VoidCallback.h"
#include "WindowFocusAllowedIndicator.h"
namespace WebCore {
#if ENABLE(LEGACY_NOTIFICATIONS)
Notification::Notification(const String& title, const String& body, const String& iconURI, ScriptExecutionContext& context, ExceptionCode& ec, NotificationCenter& notificationCenter)
: ActiveDOMObject(&context)
, m_title(title)
, m_body(body)
, m_notificationCenter(¬ificationCenter)
{
if (m_notificationCenter->checkPermission() != NotificationClient::PermissionAllowed) {
ec = SECURITY_ERR;
return;
}
m_icon = iconURI.isEmpty() ? URL() : scriptExecutionContext()->completeURL(iconURI);
if (!m_icon.isEmpty() && !m_icon.isValid()) {
ec = SYNTAX_ERR;
return;
}
}
#endif
#if ENABLE(NOTIFICATIONS)
Notification::Notification(Document& document, const String& title)
: ActiveDOMObject(&document)
, m_title(title)
, m_state(Idle)
, m_notificationCenter(DOMWindowNotifications::webkitNotifications(*document.domWindow()))
, m_taskTimer(std::make_unique<Timer>([this] () { show(); }))
{
ASSERT(m_notificationCenter->client());
m_taskTimer->startOneShot(0);
}
#endif
Notification::~Notification()
{
}
#if ENABLE(LEGACY_NOTIFICATIONS)
Ref<Notification> Notification::create(const String& title, const String& body, const String& iconURI, ScriptExecutionContext& context, ExceptionCode& ec, NotificationCenter& provider)
{
auto notification = adoptRef(*new Notification(title, body, iconURI, context, ec, provider));
notification.get().suspendIfNeeded();
return notification;
}
#endif
#if ENABLE(NOTIFICATIONS)
static String directionString(Notification::Direction direction)
{
switch (direction) {
case Notification::Direction::Auto:
return ASCIILiteral("auto");
case Notification::Direction::Ltr:
return ASCIILiteral("ltr");
case Notification::Direction::Rtl:
return ASCIILiteral("rtl");
}
ASSERT_NOT_REACHED();
return { };
}
Ref<Notification> Notification::create(Document& context, const String& title, const Options& options)
{
auto notification = adoptRef(*new Notification(context, title));
notification.get().m_body = options.body;
notification.get().m_tag = options.tag;
notification.get().m_lang = options.lang;
notification.get().m_direction = directionString(options.dir);
if (!options.icon.isEmpty()) {
auto iconURL = context.completeURL(options.icon);
if (iconURL.isValid())
notification.get().m_icon = iconURL;
}
notification.get().suspendIfNeeded();
return notification;
}
#endif
void Notification::show()
{
if (m_state == Idle && m_notificationCenter->client()) {
#if ENABLE(NOTIFICATIONS)
auto* page = downcast<Document>(*scriptExecutionContext()).page();
if (!page)
return;
if (NotificationController::from(page)->client()->checkPermission(scriptExecutionContext()) != NotificationClient::PermissionAllowed) {
dispatchErrorEvent();
return;
}
#endif
if (m_notificationCenter->client()->show(this)) {
m_state = Showing;
setPendingActivity(this);
}
}
}
void Notification::close()
{
switch (m_state) {
case Idle:
break;
case Showing:
if (m_notificationCenter->client())
m_notificationCenter->client()->cancel(this);
break;
case Closed:
break;
}
}
void Notification::contextDestroyed()
{
ActiveDOMObject::contextDestroyed();
if (m_notificationCenter->client())
m_notificationCenter->client()->notificationObjectDestroyed(this);
}
const char* Notification::activeDOMObjectName() const
{
return "Notification";
}
bool Notification::canSuspendForDocumentSuspension() const
{
return m_state == Idle || m_state == Closed;
}
void Notification::finalize()
{
if (m_state == Closed)
return;
m_state = Closed;
unsetPendingActivity(this);
}
void Notification::dispatchShowEvent()
{
dispatchEvent(Event::create(eventNames().showEvent, false, false));
}
void Notification::dispatchClickEvent()
{
WindowFocusAllowedIndicator windowFocusAllowed;
dispatchEvent(Event::create(eventNames().clickEvent, false, false));
}
void Notification::dispatchCloseEvent()
{
dispatchEvent(Event::create(eventNames().closeEvent, false, false));
finalize();
}
void Notification::dispatchErrorEvent()
{
dispatchEvent(Event::create(eventNames().errorEvent, false, false));
}
#if ENABLE(NOTIFICATIONS)
String Notification::permission(Document& document)
{
return permissionString(NotificationController::from(document.page())->client()->checkPermission(&document));
}
String Notification::permissionString(NotificationClient::Permission permission)
{
switch (permission) {
case NotificationClient::PermissionAllowed:
return ASCIILiteral("granted");
case NotificationClient::PermissionDenied:
return ASCIILiteral("denied");
case NotificationClient::PermissionNotAllowed:
return ASCIILiteral("default");
}
ASSERT_NOT_REACHED();
return { };
}
void Notification::requestPermission(Document& document, RefPtr<NotificationPermissionCallback>&& callback)
{
NotificationController::from(document.page())->client()->requestPermission(&document, WTFMove(callback));
}
#endif
}
#endif // ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)