| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * (C) 2000 Simon Hausmann <hausmann@kde.org> | 4 * (C) 2000 Simon Hausmann <hausmann@kde.org> |
| 5 * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. | 5 * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserv
ed. |
| 6 * (C) 2006 Graham Dennis (graham.dennis@gmail.com) | 6 * (C) 2006 Graham Dennis (graham.dennis@gmail.com) |
| 7 * | 7 * |
| 8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
| 9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
| 10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
| 11 * version 2 of the License, or (at your option) any later version. | 11 * version 2 of the License, or (at your option) any later version. |
| 12 * | 12 * |
| 13 * This library is distributed in the hope that it will be useful, | 13 * This library is distributed in the hope that it will be useful, |
| 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 98 | 98 |
| 99 if (!document()->frame()) | 99 if (!document()->frame()) |
| 100 return false; | 100 return false; |
| 101 | 101 |
| 102 if (!document()->frame()->eventHandler()->tabsToLinks(event)) | 102 if (!document()->frame()->eventHandler()->tabsToLinks(event)) |
| 103 return false; | 103 return false; |
| 104 | 104 |
| 105 return hasNonEmptyBoundingBox(); | 105 return hasNonEmptyBoundingBox(); |
| 106 } | 106 } |
| 107 | 107 |
| 108 void HTMLAnchorElement::defaultEventHandler(Event* evt) | 108 static void appendServerMapMousePosition(String& url, Event* event) |
| 109 { | 109 { |
| 110 // React on clicks and on keypresses. | 110 if (!event->isMouseEvent()) |
| 111 // Don't make this KEYUP_EVENT again, it makes khtml follow links it shouldn
't, | 111 return; |
| 112 // when pressing Enter in the combo. | |
| 113 if (isLink() && (evt->type() == eventNames().clickEvent || (evt->type() == e
ventNames().keydownEvent && focused()))) { | |
| 114 MouseEvent* e = 0; | |
| 115 if (evt->type() == eventNames().clickEvent && evt->isMouseEvent()) | |
| 116 e = static_cast<MouseEvent*>(evt); | |
| 117 | 112 |
| 118 KeyboardEvent* k = 0; | 113 ASSERT(event->target()); |
| 119 if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent()) | 114 Node* target = event->target()->toNode(); |
| 120 k = static_cast<KeyboardEvent*>(evt); | 115 ASSERT(target); |
| 116 if (!target->hasTagName(imgTag)) |
| 117 return; |
| 121 | 118 |
| 122 if (e && e->button() == RightButton) { | 119 HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(event->targe
t()->toNode()); |
| 123 HTMLElement::defaultEventHandler(evt); | 120 if (!imageElement || !imageElement->isServerMap()) |
| 121 return; |
| 122 |
| 123 RenderImage* renderer = toRenderImage(imageElement->renderer()); |
| 124 if (!renderer) |
| 125 return; |
| 126 |
| 127 // FIXME: This should probably pass true for useTransforms. |
| 128 FloatPoint absolutePosition = renderer->absoluteToLocal(FloatPoint(static_ca
st<MouseEvent*>(event)->pageX(), static_cast<MouseEvent*>(event)->pageY())); |
| 129 int x = absolutePosition.x(); |
| 130 int y = absolutePosition.y(); |
| 131 url += "?"; |
| 132 url += String::number(x); |
| 133 url += ","; |
| 134 url += String::number(y); |
| 135 } |
| 136 |
| 137 void HTMLAnchorElement::defaultEventHandler(Event* event) |
| 138 { |
| 139 if (isLink()) { |
| 140 if (focused() && isEnterKeyKeydownEvent(event) && treatLinkAsLiveForEven
tType(NonMouseEvent)) { |
| 141 event->setDefaultHandled(); |
| 142 dispatchSimulatedClick(event); |
| 124 return; | 143 return; |
| 125 } | 144 } |
| 126 | 145 |
| 127 // If the link is editable, then we need to check the settings to see wh
ether or not to follow the link | 146 if (isLinkClick(event) && treatLinkAsLiveForEventType(eventType(event)))
{ |
| 128 if (isContentEditable()) { | 147 String url = deprecatedParseURL(getAttribute(hrefAttr)); |
| 129 EditableLinkBehavior editableLinkBehavior = EditableLinkDefaultBehav
ior; | 148 appendServerMapMousePosition(url, event); |
| 130 if (Settings* settings = document()->settings()) | 149 handleLinkClick(event, document(), url, getAttribute(targetAttr), ha
sRel(RelationNoReferrer)); |
| 131 editableLinkBehavior = settings->editableLinkBehavior(); | |
| 132 | |
| 133 switch (editableLinkBehavior) { | |
| 134 // Always follow the link (Safari 2.0 behavior) | |
| 135 default: | |
| 136 case EditableLinkDefaultBehavior: | |
| 137 case EditableLinkAlwaysLive: | |
| 138 break; | |
| 139 | |
| 140 case EditableLinkNeverLive: | |
| 141 HTMLElement::defaultEventHandler(evt); | |
| 142 return; | |
| 143 | |
| 144 // If the selection prior to clicking on this link resided in th
e same editable block as this link, | |
| 145 // and the shift key isn't pressed, we don't want to follow the
link | |
| 146 case EditableLinkLiveWhenNotFocused: | |
| 147 if (e && !e->shiftKey() && m_rootEditableElementForSelection
OnMouseDown == rootEditableElement()) { | |
| 148 HTMLElement::defaultEventHandler(evt); | |
| 149 return; | |
| 150 } | |
| 151 break; | |
| 152 | |
| 153 // Only follow the link if the shift key is down (WinIE/Firefox
behavior) | |
| 154 case EditableLinkOnlyLiveWithShiftKey: | |
| 155 if (e && !e->shiftKey()) { | |
| 156 HTMLElement::defaultEventHandler(evt); | |
| 157 return; | |
| 158 } | |
| 159 break; | |
| 160 } | |
| 161 } | |
| 162 | |
| 163 if (k) { | |
| 164 if (k->keyIdentifier() != "Enter") { | |
| 165 HTMLElement::defaultEventHandler(evt); | |
| 166 return; | |
| 167 } | |
| 168 evt->setDefaultHandled(); | |
| 169 dispatchSimulatedClick(evt); | |
| 170 return; | 150 return; |
| 171 } | 151 } |
| 172 | 152 |
| 173 String url = deprecatedParseURL(getAttribute(hrefAttr)); | 153 if (isContentEditable()) { |
| 174 | 154 // This keeps track of the editable block that the selection was in
(if it was in one) just before the link was clicked |
| 175 ASSERT(evt->target()); | 155 // for the LiveWhenNotFocused editable link behavior |
| 176 ASSERT(evt->target()->toNode()); | 156 if (event->type() == eventNames().mousedownEvent && event->isMouseEv
ent() && static_cast<MouseEvent*>(event)->button() != RightButton && document()-
>frame() && document()->frame()->selection()) { |
| 177 if (evt->target()->toNode()->hasTagName(imgTag)) { | 157 m_rootEditableElementForSelectionOnMouseDown = document()->frame
()->selection()->rootEditableElement(); |
| 178 HTMLImageElement* img = static_cast<HTMLImageElement*>(evt->target()
->toNode()); | 158 m_wasShiftKeyDownOnMouseDown = static_cast<MouseEvent*>(event)->
shiftKey(); |
| 179 if (img && img->isServerMap()) { | 159 } else if (event->type() == eventNames().mouseoverEvent) { |
| 180 RenderImage* r = toRenderImage(img->renderer()); | 160 // These are cleared on mouseover and not mouseout because their
values are needed for drag events, |
| 181 if (r && e) { | 161 // but drag events happen after mouse out events. |
| 182 // FIXME: broken with transforms | 162 m_rootEditableElementForSelectionOnMouseDown = 0; |
| 183 FloatPoint absPos = r->localToAbsolute(); | 163 m_wasShiftKeyDownOnMouseDown = false; |
| 184 int x = e->pageX() - absPos.x(); | |
| 185 int y = e->pageY() - absPos.y(); | |
| 186 url += "?"; | |
| 187 url += String::number(x); | |
| 188 url += ","; | |
| 189 url += String::number(y); | |
| 190 } else { | |
| 191 evt->setDefaultHandled(); | |
| 192 HTMLElement::defaultEventHandler(evt); | |
| 193 return; | |
| 194 } | |
| 195 } | 164 } |
| 196 } | 165 } |
| 197 | |
| 198 if (!evt->defaultPrevented() && document()->frame()) | |
| 199 document()->frame()->loader()->urlSelected(document()->completeURL(u
rl), getAttribute(targetAttr), evt, false, false, true, hasRel(RelationNoReferre
r) ? NoReferrer : SendReferrer); | |
| 200 | |
| 201 evt->setDefaultHandled(); | |
| 202 } else if (isLink() && isContentEditable()) { | |
| 203 // This keeps track of the editable block that the selection was in (if
it was in one) just before the link was clicked | |
| 204 // for the LiveWhenNotFocused editable link behavior | |
| 205 if (evt->type() == eventNames().mousedownEvent && evt->isMouseEvent() &&
static_cast<MouseEvent*>(evt)->button() != RightButton && document()->frame() &
& document()->frame()->selection()) { | |
| 206 MouseEvent* e = static_cast<MouseEvent*>(evt); | |
| 207 | |
| 208 m_rootEditableElementForSelectionOnMouseDown = document()->frame()->
selection()->rootEditableElement(); | |
| 209 m_wasShiftKeyDownOnMouseDown = e && e->shiftKey(); | |
| 210 } else if (evt->type() == eventNames().mouseoverEvent) { | |
| 211 // These are cleared on mouseover and not mouseout because their val
ues are needed for drag events, but these happen | |
| 212 // after mouse out events. | |
| 213 m_rootEditableElementForSelectionOnMouseDown = 0; | |
| 214 m_wasShiftKeyDownOnMouseDown = false; | |
| 215 } | |
| 216 } | 166 } |
| 217 | 167 |
| 218 HTMLElement::defaultEventHandler(evt); | 168 HTMLElement::defaultEventHandler(event); |
| 219 } | 169 } |
| 220 | 170 |
| 221 void HTMLAnchorElement::setActive(bool down, bool pause) | 171 void HTMLAnchorElement::setActive(bool down, bool pause) |
| 222 { | 172 { |
| 223 if (isContentEditable()) { | 173 if (isContentEditable()) { |
| 224 EditableLinkBehavior editableLinkBehavior = EditableLinkDefaultBehavior; | 174 EditableLinkBehavior editableLinkBehavior = EditableLinkDefaultBehavior; |
| 225 if (Settings* settings = document()->settings()) | 175 if (Settings* settings = document()->settings()) |
| 226 editableLinkBehavior = settings->editableLinkBehavior(); | 176 editableLinkBehavior = settings->editableLinkBehavior(); |
| 227 | 177 |
| 228 switch (editableLinkBehavior) { | 178 switch (editableLinkBehavior) { |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 505 return innerText(); | 455 return innerText(); |
| 506 } | 456 } |
| 507 | 457 |
| 508 String HTMLAnchorElement::toString() const | 458 String HTMLAnchorElement::toString() const |
| 509 { | 459 { |
| 510 return href().string(); | 460 return href().string(); |
| 511 } | 461 } |
| 512 | 462 |
| 513 bool HTMLAnchorElement::isLiveLink() const | 463 bool HTMLAnchorElement::isLiveLink() const |
| 514 { | 464 { |
| 515 if (!isLink()) | 465 return isLink() && treatLinkAsLiveForEventType(m_wasShiftKeyDownOnMouseDown
? MouseEventWithShiftKey : MouseEventWithoutShiftKey); |
| 516 return false; | 466 } |
| 467 |
| 468 HTMLAnchorElement::EventType HTMLAnchorElement::eventType(Event* event) |
| 469 { |
| 470 if (!event->isMouseEvent()) |
| 471 return NonMouseEvent; |
| 472 return static_cast<MouseEvent*>(event)->shiftKey() ? MouseEventWithShiftKey
: MouseEventWithoutShiftKey; |
| 473 } |
| 474 |
| 475 bool HTMLAnchorElement::treatLinkAsLiveForEventType(EventType eventType) const |
| 476 { |
| 517 if (!isContentEditable()) | 477 if (!isContentEditable()) |
| 518 return true; | 478 return true; |
| 519 | |
| 520 EditableLinkBehavior editableLinkBehavior = EditableLinkDefaultBehavior; | |
| 521 if (Settings* settings = document()->settings()) | |
| 522 editableLinkBehavior = settings->editableLinkBehavior(); | |
| 523 | |
| 524 switch (editableLinkBehavior) { | |
| 525 default: | |
| 526 case EditableLinkDefaultBehavior: | |
| 527 case EditableLinkAlwaysLive: | |
| 528 return true; | |
| 529 | 479 |
| 530 case EditableLinkNeverLive: | 480 Settings* settings = document()->settings(); |
| 531 return false; | 481 if (!settings) |
| 482 return true; |
| 532 | 483 |
| 533 // Don't set the link to be live if the current selection is in the same
editable block as | 484 switch (settings->editableLinkBehavior()) { |
| 534 // this link or if the shift key is down | 485 case EditableLinkDefaultBehavior: |
| 535 case EditableLinkLiveWhenNotFocused: | 486 case EditableLinkAlwaysLive: |
| 536 return m_wasShiftKeyDownOnMouseDown || m_rootEditableElementForSelec
tionOnMouseDown != rootEditableElement(); | 487 return true; |
| 537 | 488 |
| 538 case EditableLinkOnlyLiveWithShiftKey: | 489 case EditableLinkNeverLive: |
| 539 return m_wasShiftKeyDownOnMouseDown; | 490 return false; |
| 491 |
| 492 // If the selection prior to clicking on this link resided in the same edita
ble block as this link, |
| 493 // and the shift key isn't pressed, we don't want to follow the link. |
| 494 case EditableLinkLiveWhenNotFocused: |
| 495 return eventType == MouseEventWithShiftKey || (eventType == MouseEventWi
thoutShiftKey && m_rootEditableElementForSelectionOnMouseDown != rootEditableEle
ment()); |
| 496 |
| 497 case EditableLinkOnlyLiveWithShiftKey: |
| 498 return eventType == MouseEventWithShiftKey; |
| 540 } | 499 } |
| 500 |
| 501 ASSERT_NOT_REACHED(); |
| 502 return false; |
| 503 } |
| 504 |
| 505 bool isEnterKeyKeydownEvent(Event* event) |
| 506 { |
| 507 return event->type() == eventNames().keydownEvent && event->isKeyboardEvent(
) && static_cast<KeyboardEvent*>(event)->keyIdentifier() == "Enter"; |
| 508 } |
| 509 |
| 510 bool isMiddleMouseButtonEvent(Event* event) |
| 511 { |
| 512 return event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() ==
MiddleButton; |
| 513 } |
| 514 |
| 515 bool isLinkClick(Event* event) |
| 516 { |
| 517 return event->type() == eventNames().clickEvent && (!event->isMouseEvent() |
| static_cast<MouseEvent*>(event)->button() != RightButton); |
| 518 } |
| 519 |
| 520 void handleLinkClick(Event* event, Document* document, const String& url, const
String& target, bool hideReferrer) |
| 521 { |
| 522 event->setDefaultHandled(); |
| 523 |
| 524 Frame* frame = document->frame(); |
| 525 if (!frame) |
| 526 return; |
| 527 frame->loader()->urlSelected(document->completeURL(url), target, event, fals
e, false, true, hideReferrer ? NoReferrer : SendReferrer); |
| 541 } | 528 } |
| 542 | 529 |
| 543 } | 530 } |
| OLD | NEW |