nsresult HTMLLabelElement::PostHandleEvent(EventChainPostVisitor& aVisitor) { WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); if (mHandlingEvent || (!(mouseEvent && mouseEvent->IsLeftClickEvent()) && aVisitor.mEvent->mMessage != eMouseDown) || aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault || !aVisitor.mPresContext || // Don't handle the event if it's already been handled by another label aVisitor.mEvent->mFlags.mMultipleActionsPrevented) { return NS_OK; } nsCOMPtr<nsIContent> target = do_QueryInterface(aVisitor.mEvent->target); if (InInteractiveHTMLContent(target, this)) { return NS_OK; } // Strong ref because event dispatch is going to happen. RefPtr<Element> content = GetLabeledElement(); if (content) { mHandlingEvent = true; switch (aVisitor.mEvent->mMessage) { case eMouseDown: if (mouseEvent->button == WidgetMouseEvent::eLeftButton) { // We reset the mouse-down point on every event because there is // no guarantee we will reach the eMouseClick code below. LayoutDeviceIntPoint* curPoint = new LayoutDeviceIntPoint(mouseEvent->refPoint); SetProperty(nsGkAtoms::labelMouseDownPtProperty, static_cast<void*>(curPoint), nsINode::DeleteProperty<LayoutDeviceIntPoint>); } break; case eMouseClick: if (mouseEvent->IsLeftClickEvent()) { LayoutDeviceIntPoint* mouseDownPoint = static_cast<LayoutDeviceIntPoint*>( GetProperty(nsGkAtoms::labelMouseDownPtProperty)); bool dragSelect = false; if (mouseDownPoint) { LayoutDeviceIntPoint dragDistance = *mouseDownPoint; DeleteProperty(nsGkAtoms::labelMouseDownPtProperty); dragDistance -= mouseEvent->refPoint; const int CLICK_DISTANCE = 2; dragSelect = dragDistance.x > CLICK_DISTANCE || dragDistance.x < -CLICK_DISTANCE || dragDistance.y > CLICK_DISTANCE || dragDistance.y < -CLICK_DISTANCE; } // Don't click the for-content if we did drag-select text or if we // have a kbd modifier (which adjusts a selection). if (dragSelect || mouseEvent->IsShift() || mouseEvent->IsControl() || mouseEvent->IsAlt() || mouseEvent->IsMeta()) { break; } // Only set focus on the first click of multiple clicks to prevent // to prevent immediate de-focus. if (mouseEvent->clickCount <= 1) { nsIFocusManager* fm = nsFocusManager::GetFocusManager(); if (fm) { // Use FLAG_BYMOVEFOCUS here so that the label is scrolled to. // Also, within HTMLInputElement::PostHandleEvent, inputs will // be selected only when focused via a key or when the navigation // flag is used and we want to select the text on label clicks as // well. // If the label has been clicked by the user, we also want to // pass FLAG_BYMOUSE so that we get correct focus ring behavior, // but we don't want to pass FLAG_BYMOUSE if this click event was // caused by the user pressing an accesskey. nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(content); bool byMouse = (mouseEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD); bool byTouch = (mouseEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH); fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOVEFOCUS | (byMouse ? nsIFocusManager::FLAG_BYMOUSE : 0) | (byTouch ? nsIFocusManager::FLAG_BYTOUCH : 0)); } } // Dispatch a new click event to |content| // (For compatibility with IE, we do only left click. If // we wanted to interpret the HTML spec very narrowly, we // would do nothing. If we wanted to do something // sensible, we might send more events through like // this.) See bug 7554, bug 49897, and bug 96813. nsEventStatus status = aVisitor.mEventStatus; // Ok to use aVisitor.mEvent as parameter because DispatchClickEvent // will actually create a new event. EventFlags eventFlags; eventFlags.mMultipleActionsPrevented = true; DispatchClickEvent(aVisitor.mPresContext, mouseEvent, content, false, &eventFlags, &status); // Do we care about the status this returned? I don't think we do... // Don't run another <label> off of this click mouseEvent->mFlags.mMultipleActionsPrevented = true; } break; default: break; } mHandlingEvent = false; } return NS_OK; }
nsresult HTMLLabelElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor) { if (mHandlingEvent || (!NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent) && aVisitor.mEvent->message != NS_MOUSE_BUTTON_DOWN) || aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault || !aVisitor.mPresContext || // Don't handle the event if it's already been handled by another label aVisitor.mEvent->mFlags.mMultipleActionsPrevented) { return NS_OK; } // Strong ref because event dispatch is going to happen. nsRefPtr<Element> content = GetLabeledElement(); if (content && !EventTargetIn(aVisitor.mEvent, content, this)) { mHandlingEvent = true; switch (aVisitor.mEvent->message) { case NS_MOUSE_BUTTON_DOWN: NS_ASSERTION(aVisitor.mEvent->eventStructType == NS_MOUSE_EVENT, "wrong event struct for event"); if (static_cast<nsMouseEvent*>(aVisitor.mEvent)->button == nsMouseEvent::eLeftButton) { // We reset the mouse-down point on every event because there is // no guarantee we will reach the NS_MOUSE_CLICK code below. nsIntPoint *curPoint = new nsIntPoint(aVisitor.mEvent->refPoint); SetProperty(nsGkAtoms::labelMouseDownPtProperty, static_cast<void *>(curPoint), DestroyMouseDownPoint); } break; case NS_MOUSE_CLICK: if (NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent)) { const nsMouseEvent* event = static_cast<const nsMouseEvent*>(aVisitor.mEvent); nsIntPoint *mouseDownPoint = static_cast<nsIntPoint *> (GetProperty(nsGkAtoms::labelMouseDownPtProperty)); bool dragSelect = false; if (mouseDownPoint) { nsIntPoint dragDistance = *mouseDownPoint; DeleteProperty(nsGkAtoms::labelMouseDownPtProperty); dragDistance -= aVisitor.mEvent->refPoint; const int CLICK_DISTANCE = 2; dragSelect = dragDistance.x > CLICK_DISTANCE || dragDistance.x < -CLICK_DISTANCE || dragDistance.y > CLICK_DISTANCE || dragDistance.y < -CLICK_DISTANCE; } // Don't click the for-content if we did drag-select text or if we // have a kbd modifier (which adjusts a selection), or if it's a // double click (we already forwarded the first click event). if (dragSelect || event->clickCount > 1 || event->IsShift() || event->IsControl() || event->IsAlt() || event->IsMeta()) { break; } nsIFocusManager* fm = nsFocusManager::GetFocusManager(); if (fm) { // Use FLAG_BYMOVEFOCUS here so that the label is scrolled to. // Also, within nsHTMLInputElement::PostHandleEvent, inputs will // be selected only when focused via a key or when the navigation // flag is used and we want to select the text on label clicks as // well. nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(content); fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOVEFOCUS); } // Dispatch a new click event to |content| // (For compatibility with IE, we do only left click. If // we wanted to interpret the HTML spec very narrowly, we // would do nothing. If we wanted to do something // sensible, we might send more events through like // this.) See bug 7554, bug 49897, and bug 96813. nsEventStatus status = aVisitor.mEventStatus; // Ok to use aVisitor.mEvent as parameter because DispatchClickEvent // will actually create a new event. widget::EventFlags eventFlags; eventFlags.Clear(); eventFlags.mMultipleActionsPrevented = true; DispatchClickEvent(aVisitor.mPresContext, static_cast<nsInputEvent*>(aVisitor.mEvent), content, false, &eventFlags, &status); // Do we care about the status this returned? I don't think we do... // Don't run another <label> off of this click aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true; } break; } mHandlingEvent = false; } return NS_OK; }