void HTMLStyleElementImp::handleMutation(EventListenerImp* listener, events::Event event) { // TODO: update type, media, and scoped. Then check type. events::MutationEvent mutation(interface_cast<events::MutationEvent>(event)); DocumentImp* document = getOwnerDocumentImp(); if (!document) return; if (mutation.getType() == u"DOMNodeRemoved" && event.getTarget().self() == this) styleSheet = 0; else { std::u16string content; for (Node node = getFirstChild(); node; node = node.getNextSibling()) { if (TextImp* text = dynamic_cast<TextImp*>(node.self())) // TODO better to avoid imp call? content += text->getData(); } CSSParser parser; styleSheet = parser.parse(document, content); if (auto imp = dynamic_cast<CSSStyleSheetImp*>(styleSheet.self())) { imp->setOwnerNode(this); if (4 <= getLogLevel()) dumpStyleSheet(std::cerr, imp); } } if (WindowImp* view = document->getDefaultWindow()) view->setFlags(Box::NEED_SELECTOR_REMATCHING); document->resetStyleSheets(); }
bool EventTargetImp::dispatchEvent(events::Event evt) { EventImp* event = dynamic_cast<EventImp*>(evt.self()); if (!event) return false; event->setDispatchFlag(true); if (auto documentWindow = dynamic_cast<DocumentWindow*>(this)) event->setTarget(documentWindow->getWindowImp()); else event->setTarget(this); if (NodeImp* node = dynamic_cast<NodeImp*>(this)) { DocumentImp* document = dynamic_cast<DocumentImp*>(node); if (!document) document = node->getOwnerDocumentImp(); assert(document); document->enter(); std::list<EventTargetImp*> eventPath; for (NodeImp* ancestor = node->parentNode; ancestor; ancestor = ancestor->parentNode) { if (auto shadowTree = dynamic_cast<HTMLTemplateElementImp*>(ancestor)) { if (NodeImp* host = dynamic_cast<NodeImp*>(shadowTree->getHost().self())) { // TODO: Fix 'target' of the event as well. // TODO: Check the mouseover and mouseout events. ancestor = host; if (!dynamic_cast<UIEventImp*>(event)) { // To repaint the window, we still need to notify the bound document // of the event. // TODO: Support nesting of bound elements. eventPath.push_front(ancestor->getOwnerDocumentImp()); break; } } } eventPath.push_front(ancestor); } // cf. http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#events-and-the-window-object if (document && event->getType() != u"load") { if (WindowImp* view = document->getDefaultWindow()) eventPath.push_front(view->getDocumentWindow().get()); } event->setEventPhase(events::Event::CAPTURING_PHASE); for (auto i = eventPath.begin(); i != eventPath.end(); ++i) { if (event->getStopPropagationFlag()) break; event->setCurrentTarget(*i); (*i)->invoke(event); } event->setEventPhase(events::Event::AT_TARGET); if (!event->getStopPropagationFlag()) { event->setCurrentTarget(node); node->invoke(event); } if (event->getBubbles()) { event->setEventPhase(events::Event::BUBBLING_PHASE); for (auto i = eventPath.rbegin(); i != eventPath.rend(); ++i) { if (event->getStopPropagationFlag()) break; event->setCurrentTarget(*i); (*i)->invoke(event); } } if (!event->getDefaultPrevented()) { // TODO: Call default actions; // cf. http://www.w3.org/TR/DOM-Level-3-Events/#event-flow-default-cancel // cf. http://www.w3.org/TR/xbl/#the-default-phase0 event->setEventPhase(EventImp::DEFAULT_PHASE); event->setCurrentTarget(node); node->invoke(event); if (event->getBubbles()) { for (auto i = eventPath.rbegin(); i != eventPath.rend(); ++i) { if (event->getDefaultPrevented()) break; event->setCurrentTarget(*i); (*i)->invoke(event); } } } document->exit(); } else if (DocumentWindow* window = dynamic_cast<DocumentWindow*>(this)) { auto proxy = dynamic_cast<WindowImp*>(window->getDocument().getDefaultView().self()); window->enter(proxy); event->setEventPhase(events::Event::AT_TARGET); event->setCurrentTarget(this); invoke(event); window->exit(proxy); } event->setDispatchFlag(false); event->setEventPhase(events::Event::AT_TARGET); event->setCurrentTarget(0); return !event->getDefaultPrevented(); }