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 |