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, 2010 Apple Inc. All rights reserv
ed. | 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 |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 double m_tapDownTimestamp; | 102 double m_tapDownTimestamp; |
103 bool m_hadHREFChanged; | 103 bool m_hadHREFChanged; |
104 bool m_hadTapUnconfirmed; | 104 bool m_hadTapUnconfirmed; |
105 bool m_hasIssuedPreconnect; | 105 bool m_hasIssuedPreconnect; |
106 }; | 106 }; |
107 | 107 |
108 using namespace HTMLNames; | 108 using namespace HTMLNames; |
109 | 109 |
110 HTMLAnchorElement::HTMLAnchorElement(const QualifiedName& tagName, Document& doc
ument) | 110 HTMLAnchorElement::HTMLAnchorElement(const QualifiedName& tagName, Document& doc
ument) |
111 : HTMLElement(tagName, document) | 111 : HTMLElement(tagName, document) |
112 , m_hasRootEditableElementForSelectionOnMouseDown(false) | |
113 , m_wasShiftKeyDownOnMouseDown(false) | |
114 , m_linkRelations(0) | 112 , m_linkRelations(0) |
115 , m_cachedVisitedLinkHash(0) | 113 , m_cachedVisitedLinkHash(0) |
116 { | 114 { |
117 ScriptWrappable::init(this); | 115 ScriptWrappable::init(this); |
118 } | 116 } |
119 | 117 |
120 PassRefPtr<HTMLAnchorElement> HTMLAnchorElement::create(Document& document) | 118 PassRefPtr<HTMLAnchorElement> HTMLAnchorElement::create(Document& document) |
121 { | 119 { |
122 return adoptRef(new HTMLAnchorElement(aTag, document)); | 120 return adoptRef(new HTMLAnchorElement(aTag, document)); |
123 } | 121 } |
124 | 122 |
125 PassRefPtr<HTMLAnchorElement> HTMLAnchorElement::create(const QualifiedName& tag
Name, Document& document) | 123 PassRefPtr<HTMLAnchorElement> HTMLAnchorElement::create(const QualifiedName& tag
Name, Document& document) |
126 { | 124 { |
127 return adoptRef(new HTMLAnchorElement(tagName, document)); | 125 return adoptRef(new HTMLAnchorElement(tagName, document)); |
128 } | 126 } |
129 | 127 |
130 HTMLAnchorElement::~HTMLAnchorElement() | 128 HTMLAnchorElement::~HTMLAnchorElement() |
131 { | 129 { |
132 clearRootEditableElementForSelectionOnMouseDown(); | |
133 } | 130 } |
134 | 131 |
135 bool HTMLAnchorElement::supportsFocus() const | 132 bool HTMLAnchorElement::supportsFocus() const |
136 { | 133 { |
137 if (rendererIsEditable()) | 134 if (rendererIsEditable()) |
138 return HTMLElement::supportsFocus(); | 135 return HTMLElement::supportsFocus(); |
139 // If not a link we should still be able to focus the element if it has tabI
ndex. | 136 // If not a link we should still be able to focus the element if it has tabI
ndex. |
140 return isLink() || HTMLElement::supportsFocus(); | 137 return isLink() || HTMLElement::supportsFocus(); |
141 } | 138 } |
142 | 139 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 int y = absolutePosition.y(); | 184 int y = absolutePosition.y(); |
188 url.append('?'); | 185 url.append('?'); |
189 url.appendNumber(x); | 186 url.appendNumber(x); |
190 url.append(','); | 187 url.append(','); |
191 url.appendNumber(y); | 188 url.appendNumber(y); |
192 } | 189 } |
193 | 190 |
194 void HTMLAnchorElement::defaultEventHandler(Event* event) | 191 void HTMLAnchorElement::defaultEventHandler(Event* event) |
195 { | 192 { |
196 if (isLink()) { | 193 if (isLink()) { |
197 if (focused() && isEnterKeyKeydownEvent(event) && treatLinkAsLiveForEven
tType(NonMouseEvent)) { | 194 if (focused() && isEnterKeyKeydownEvent(event) && isLiveLink()) { |
198 event->setDefaultHandled(); | 195 event->setDefaultHandled(); |
199 dispatchSimulatedClick(event); | 196 dispatchSimulatedClick(event); |
200 return; | 197 return; |
201 } | 198 } |
202 | 199 |
203 prefetchEventHandler()->handleEvent(event); | 200 prefetchEventHandler()->handleEvent(event); |
204 | 201 |
205 if (isLinkClick(event) && treatLinkAsLiveForEventType(eventType(event)))
{ | 202 if (isLinkClick(event) && isLiveLink()) { |
206 handleClick(event); | 203 handleClick(event); |
207 prefetchEventHandler()->reset(); | 204 prefetchEventHandler()->reset(); |
208 return; | 205 return; |
209 } | 206 } |
210 | |
211 if (rendererIsEditable()) { | |
212 // This keeps track of the editable block that the selection was in
(if it was in one) just before the link was clicked | |
213 // for the LiveWhenNotFocused editable link behavior | |
214 if (event->type() == EventTypeNames::mousedown && event->isMouseEven
t() && toMouseEvent(event)->button() != RightButton && document().frame()) { | |
215 setRootEditableElementForSelectionOnMouseDown(document().frame()
->selection().rootEditableElement()); | |
216 m_wasShiftKeyDownOnMouseDown = toMouseEvent(event)->shiftKey(); | |
217 } else if (event->type() == EventTypeNames::mouseover) { | |
218 // These are cleared on mouseover and not mouseout because their
values are needed for drag events, | |
219 // but drag events happen after mouse out events. | |
220 clearRootEditableElementForSelectionOnMouseDown(); | |
221 m_wasShiftKeyDownOnMouseDown = false; | |
222 } | |
223 } | |
224 } | 207 } |
225 | 208 |
226 HTMLElement::defaultEventHandler(event); | 209 HTMLElement::defaultEventHandler(event); |
227 } | 210 } |
228 | 211 |
229 void HTMLAnchorElement::setActive(bool down) | 212 void HTMLAnchorElement::setActive(bool down) |
230 { | 213 { |
231 if (rendererIsEditable()) { | 214 if (rendererIsEditable()) |
232 EditableLinkBehavior editableLinkBehavior = EditableLinkDefaultBehavior; | 215 return; |
233 if (Settings* settings = document().settings()) | |
234 editableLinkBehavior = settings->editableLinkBehavior(); | |
235 | |
236 switch (editableLinkBehavior) { | |
237 default: | |
238 case EditableLinkDefaultBehavior: | |
239 case EditableLinkAlwaysLive: | |
240 break; | |
241 | |
242 case EditableLinkNeverLive: | |
243 return; | |
244 | |
245 // Don't set the link to be active if the current selection is in th
e same editable block as | |
246 // this link | |
247 case EditableLinkLiveWhenNotFocused: | |
248 if (down && document().frame() && document().frame()->selection(
).rootEditableElement() == rootEditableElement()) | |
249 return; | |
250 break; | |
251 | |
252 case EditableLinkOnlyLiveWithShiftKey: | |
253 return; | |
254 } | |
255 | |
256 } | |
257 | 216 |
258 ContainerNode::setActive(down); | 217 ContainerNode::setActive(down); |
259 } | 218 } |
260 | 219 |
261 void HTMLAnchorElement::parseAttribute(const QualifiedName& name, const AtomicSt
ring& value) | 220 void HTMLAnchorElement::parseAttribute(const QualifiedName& name, const AtomicSt
ring& value) |
262 { | 221 { |
263 if (name == hrefAttr) { | 222 if (name == hrefAttr) { |
264 bool wasLink = isLink(); | 223 bool wasLink = isLink(); |
265 setIsLink(!value.isNull()); | 224 setIsLink(!value.isNull()); |
266 if (wasLink != isLink()) { | 225 if (wasLink != isLink()) { |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 } | 344 } |
386 | 345 |
387 | 346 |
388 String HTMLAnchorElement::text() | 347 String HTMLAnchorElement::text() |
389 { | 348 { |
390 return innerText(); | 349 return innerText(); |
391 } | 350 } |
392 | 351 |
393 bool HTMLAnchorElement::isLiveLink() const | 352 bool HTMLAnchorElement::isLiveLink() const |
394 { | 353 { |
395 return isLink() && treatLinkAsLiveForEventType(m_wasShiftKeyDownOnMouseDown
? MouseEventWithShiftKey : MouseEventWithoutShiftKey); | 354 return isLink() && !rendererIsEditable(); |
396 } | 355 } |
397 | 356 |
398 void HTMLAnchorElement::sendPings(const KURL& destinationURL) | 357 void HTMLAnchorElement::sendPings(const KURL& destinationURL) |
399 { | 358 { |
400 const AtomicString& pingValue = getAttribute(pingAttr); | 359 const AtomicString& pingValue = getAttribute(pingAttr); |
401 if (pingValue.isNull() || !document().settings() || !document().settings()->
hyperlinkAuditingEnabled()) | 360 if (pingValue.isNull() || !document().settings() || !document().settings()->
hyperlinkAuditingEnabled()) |
402 return; | 361 return; |
403 | 362 |
404 UseCounter::count(document(), UseCounter::HTMLAnchorElementPingAttribute); | 363 UseCounter::count(document(), UseCounter::HTMLAnchorElementPingAttribute); |
405 | 364 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
438 frame->loader().client()->loadURLExternally(request, NavigationPolicyDow
nload, fastGetAttribute(downloadAttr)); | 397 frame->loader().client()->loadURLExternally(request, NavigationPolicyDow
nload, fastGetAttribute(downloadAttr)); |
439 } else { | 398 } else { |
440 FrameLoadRequest frameRequest(&document(), request, target()); | 399 FrameLoadRequest frameRequest(&document(), request, target()); |
441 frameRequest.setTriggeringEvent(event); | 400 frameRequest.setTriggeringEvent(event); |
442 if (hasRel(RelationNoReferrer)) | 401 if (hasRel(RelationNoReferrer)) |
443 frameRequest.setShouldSendReferrer(NeverSendReferrer); | 402 frameRequest.setShouldSendReferrer(NeverSendReferrer); |
444 frame->loader().load(frameRequest); | 403 frame->loader().load(frameRequest); |
445 } | 404 } |
446 } | 405 } |
447 | 406 |
448 HTMLAnchorElement::EventType HTMLAnchorElement::eventType(Event* event) | |
449 { | |
450 if (!event->isMouseEvent()) | |
451 return NonMouseEvent; | |
452 return toMouseEvent(event)->shiftKey() ? MouseEventWithShiftKey : MouseEvent
WithoutShiftKey; | |
453 } | |
454 | |
455 bool HTMLAnchorElement::treatLinkAsLiveForEventType(EventType eventType) const | |
456 { | |
457 if (!rendererIsEditable()) | |
458 return true; | |
459 | |
460 Settings* settings = document().settings(); | |
461 if (!settings) | |
462 return true; | |
463 | |
464 switch (settings->editableLinkBehavior()) { | |
465 case EditableLinkDefaultBehavior: | |
466 case EditableLinkAlwaysLive: | |
467 return true; | |
468 | |
469 case EditableLinkNeverLive: | |
470 return false; | |
471 | |
472 // If the selection prior to clicking on this link resided in the same edita
ble block as this link, | |
473 // and the shift key isn't pressed, we don't want to follow the link. | |
474 case EditableLinkLiveWhenNotFocused: | |
475 return eventType == MouseEventWithShiftKey || (eventType == MouseEventWi
thoutShiftKey && rootEditableElementForSelectionOnMouseDown() != rootEditableEle
ment()); | |
476 | |
477 case EditableLinkOnlyLiveWithShiftKey: | |
478 return eventType == MouseEventWithShiftKey; | |
479 } | |
480 | |
481 ASSERT_NOT_REACHED(); | |
482 return false; | |
483 } | |
484 | |
485 bool isEnterKeyKeydownEvent(Event* event) | 407 bool isEnterKeyKeydownEvent(Event* event) |
486 { | 408 { |
487 return event->type() == EventTypeNames::keydown && event->isKeyboardEvent()
&& toKeyboardEvent(event)->keyIdentifier() == "Enter"; | 409 return event->type() == EventTypeNames::keydown && event->isKeyboardEvent()
&& toKeyboardEvent(event)->keyIdentifier() == "Enter"; |
488 } | 410 } |
489 | 411 |
490 bool isLinkClick(Event* event) | 412 bool isLinkClick(Event* event) |
491 { | 413 { |
492 return event->type() == EventTypeNames::click && (!event->isMouseEvent() ||
toMouseEvent(event)->button() != RightButton); | 414 return event->type() == EventTypeNames::click && (!event->isMouseEvent() ||
toMouseEvent(event)->button() != RightButton); |
493 } | 415 } |
494 | 416 |
495 bool HTMLAnchorElement::willRespondToMouseClickEvents() | 417 bool HTMLAnchorElement::willRespondToMouseClickEvents() |
496 { | 418 { |
497 return isLink() || HTMLElement::willRespondToMouseClickEvents(); | 419 return isLink() || HTMLElement::willRespondToMouseClickEvents(); |
498 } | 420 } |
499 | 421 |
500 typedef HashMap<const HTMLAnchorElement*, RefPtr<Element> > RootEditableElementM
ap; | |
501 | |
502 static RootEditableElementMap& rootEditableElementMap() | |
503 { | |
504 DEFINE_STATIC_LOCAL(RootEditableElementMap, map, ()); | |
505 return map; | |
506 } | |
507 | |
508 Element* HTMLAnchorElement::rootEditableElementForSelectionOnMouseDown() const | |
509 { | |
510 if (!m_hasRootEditableElementForSelectionOnMouseDown) | |
511 return 0; | |
512 return rootEditableElementMap().get(this); | |
513 } | |
514 | |
515 void HTMLAnchorElement::clearRootEditableElementForSelectionOnMouseDown() | |
516 { | |
517 if (!m_hasRootEditableElementForSelectionOnMouseDown) | |
518 return; | |
519 rootEditableElementMap().remove(this); | |
520 m_hasRootEditableElementForSelectionOnMouseDown = false; | |
521 } | |
522 | |
523 void HTMLAnchorElement::setRootEditableElementForSelectionOnMouseDown(Element* e
lement) | |
524 { | |
525 if (!element) { | |
526 clearRootEditableElementForSelectionOnMouseDown(); | |
527 return; | |
528 } | |
529 | |
530 rootEditableElementMap().set(this, element); | |
531 m_hasRootEditableElementForSelectionOnMouseDown = true; | |
532 } | |
533 | |
534 HTMLAnchorElement::PrefetchEventHandler* HTMLAnchorElement::prefetchEventHandler
() | 422 HTMLAnchorElement::PrefetchEventHandler* HTMLAnchorElement::prefetchEventHandler
() |
535 { | 423 { |
536 if (!m_prefetchEventHandler) | 424 if (!m_prefetchEventHandler) |
537 m_prefetchEventHandler = PrefetchEventHandler::create(this); | 425 m_prefetchEventHandler = PrefetchEventHandler::create(this); |
538 | 426 |
539 return m_prefetchEventHandler.get(); | 427 return m_prefetchEventHandler.get(); |
540 } | 428 } |
541 | 429 |
542 HTMLAnchorElement::PrefetchEventHandler::PrefetchEventHandler(HTMLAnchorElement*
anchorElement) | 430 HTMLAnchorElement::PrefetchEventHandler::PrefetchEventHandler(HTMLAnchorElement*
anchorElement) |
543 : m_anchorElement(anchorElement) | 431 : m_anchorElement(anchorElement) |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
697 preconnectToURL(url, motivation); | 585 preconnectToURL(url, motivation); |
698 m_hasIssuedPreconnect = true; | 586 m_hasIssuedPreconnect = true; |
699 } | 587 } |
700 | 588 |
701 bool HTMLAnchorElement::isInteractiveContent() const | 589 bool HTMLAnchorElement::isInteractiveContent() const |
702 { | 590 { |
703 return isLink(); | 591 return isLink(); |
704 } | 592 } |
705 | 593 |
706 } | 594 } |
OLD | NEW |