1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Netscape Public License
6
* Version 1.1 (the "License"); you may not use this file except in
7
* compliance with the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/NPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is Mozilla Communicator client code.
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 1998
20
* the Initial Developer. All Rights Reserved.
25
* Alternatively, the contents of this file may be used under the terms of
26
* either the GNU General Public License Version 2 or later (the "GPL"), or
27
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
* in which case the provisions of the GPL or the LGPL are applicable instead
29
* of those above. If you wish to allow use of your version of this file only
30
* under the terms of either the GPL or the LGPL, and not to allow others to
31
* use your version of this file under the terms of the NPL, indicate your
32
* decision by deleting the provisions above and replace them with the notice
33
* and other provisions required by the GPL or the LGPL. If you do not delete
34
* the provisions above, a recipient may use your version of this file under
35
* the terms of any one of the NPL, the GPL or the LGPL.
37
* ***** END LICENSE BLOCK ***** */
38
#include "nsIDOMHTMLLinkElement.h"
39
#include "nsIDOMLinkStyle.h"
40
#include "nsIDOMEventReceiver.h"
41
#include "nsIHTMLContent.h"
42
#include "nsGenericHTMLElement.h"
44
#include "nsHTMLAtoms.h"
45
#include "nsStyleConsts.h"
46
#include "nsIPresContext.h"
47
#include "nsIDOMStyleSheet.h"
48
#include "nsIStyleSheet.h"
49
#include "nsIStyleSheetLinkingElement.h"
50
#include "nsStyleLinkElement.h"
51
#include "nsReadableUtils.h"
52
#include "nsUnicharUtils.h"
54
#include "nsNetUtil.h"
55
#include "nsIDocument.h"
56
#include "nsIDOMEvent.h"
57
#include "nsIDOMDocumentEvent.h"
58
#include "nsIDOMEventTarget.h"
59
#include "nsParserUtils.h"
61
class nsHTMLLinkElement : public nsGenericHTMLElement,
62
public nsIDOMHTMLLinkElement,
64
public nsStyleLinkElement
68
virtual ~nsHTMLLinkElement();
71
NS_DECL_ISUPPORTS_INHERITED
74
NS_FORWARD_NSIDOMNODE_NO_CLONENODE(nsGenericHTMLElement::)
77
NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
80
NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
82
// nsIDOMHTMLLinkElement
83
NS_DECL_NSIDOMHTMLLINKELEMENT
86
NS_IMETHOD GetLinkState(nsLinkState &aState);
87
NS_IMETHOD SetLinkState(nsLinkState aState);
88
NS_IMETHOD GetHrefURI(nsIURI** aURI);
90
virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep,
91
PRBool aCompileEventHandlers);
92
void CreateAndDispatchEvent(nsIDocument* aDoc, const nsString& aRel,
94
const nsAString& aEventName);
95
nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
96
const nsAString& aValue, PRBool aNotify)
98
return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
100
virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
101
nsIAtom* aPrefix, const nsAString& aValue,
103
virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
106
virtual nsresult HandleDOMEvent(nsIPresContext* aPresContext,
107
nsEvent* aEvent, nsIDOMEvent** aDOMEvent,
109
nsEventStatus* aEventStatus);
112
virtual void GetStyleSheetURL(PRBool* aIsInline,
114
virtual void GetStyleSheetInfo(nsAString& aTitle,
117
PRBool* aIsAlternate);
119
// The cached visited state
120
nsLinkState mLinkState;
124
NS_NewHTMLLinkElement(nsIHTMLContent** aInstancePtrResult,
125
nsINodeInfo *aNodeInfo, PRBool aFromParser)
127
NS_ENSURE_ARG_POINTER(aInstancePtrResult);
129
nsHTMLLinkElement* it = new nsHTMLLinkElement();
132
return NS_ERROR_OUT_OF_MEMORY;
135
nsresult rv = it->Init(aNodeInfo);
143
*aInstancePtrResult = NS_STATIC_CAST(nsIHTMLContent *, it);
144
NS_ADDREF(*aInstancePtrResult);
150
nsHTMLLinkElement::nsHTMLLinkElement()
151
: mLinkState(eLinkState_Unknown)
155
nsHTMLLinkElement::~nsHTMLLinkElement()
160
NS_IMPL_ADDREF_INHERITED(nsHTMLLinkElement, nsGenericElement)
161
NS_IMPL_RELEASE_INHERITED(nsHTMLLinkElement, nsGenericElement)
164
// QueryInterface implementation for nsHTMLLinkElement
165
NS_HTML_CONTENT_INTERFACE_MAP_BEGIN(nsHTMLLinkElement, nsGenericHTMLElement)
166
NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLLinkElement)
167
NS_INTERFACE_MAP_ENTRY(nsIDOMLinkStyle)
168
NS_INTERFACE_MAP_ENTRY(nsILink)
169
NS_INTERFACE_MAP_ENTRY(nsIStyleSheetLinkingElement)
170
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(HTMLLinkElement)
171
NS_HTML_CONTENT_INTERFACE_MAP_END
175
nsHTMLLinkElement::CloneNode(PRBool aDeep, nsIDOMNode** aReturn)
177
NS_ENSURE_ARG_POINTER(aReturn);
180
nsHTMLLinkElement* it = new nsHTMLLinkElement();
183
return NS_ERROR_OUT_OF_MEMORY;
186
nsCOMPtr<nsIDOMNode> kungFuDeathGrip(it);
188
nsresult rv = it->Init(mNodeInfo);
193
CopyInnerTo(it, aDeep);
195
*aReturn = NS_STATIC_CAST(nsIDOMNode *, it);
204
nsHTMLLinkElement::GetDisabled(PRBool* aDisabled)
206
nsCOMPtr<nsIDOMStyleSheet> ss(do_QueryInterface(mStyleSheet));
207
nsresult result = NS_OK;
210
result = ss->GetDisabled(aDisabled);
212
*aDisabled = PR_FALSE;
219
nsHTMLLinkElement::SetDisabled(PRBool aDisabled)
221
nsCOMPtr<nsIDOMStyleSheet> ss(do_QueryInterface(mStyleSheet));
222
nsresult result = NS_OK;
225
result = ss->SetDisabled(aDisabled);
232
NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Charset, charset)
233
NS_IMPL_URI_ATTR(nsHTMLLinkElement, Href, href)
234
NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Hreflang, hreflang)
235
NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Media, media)
236
NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Rel, rel)
237
NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Rev, rev)
238
NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Target, target)
239
NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Type, type)
242
nsHTMLLinkElement::SetDocument(nsIDocument* aDocument, PRBool aDeep,
243
PRBool aCompileEventHandlers)
245
nsCOMPtr<nsIDocument> oldDoc = mDocument;
249
GetAttr(kNameSpaceID_None, nsHTMLAtoms::rel, rel);
250
GetAttr(kNameSpaceID_None, nsHTMLAtoms::rev, rev);
252
CreateAndDispatchEvent(oldDoc, rel, rev,
253
NS_LITERAL_STRING("DOMLinkRemoved"));
255
// Do the removal and addition into the new doc.
256
nsGenericHTMLElement::SetDocument(aDocument, aDeep, aCompileEventHandlers);
257
UpdateStyleSheet(oldDoc);
259
CreateAndDispatchEvent(mDocument, rel, rev,
260
NS_LITERAL_STRING("DOMLinkAdded"));
264
nsHTMLLinkElement::CreateAndDispatchEvent(nsIDocument* aDoc,
265
const nsString& aRel,
266
const nsString& aRev,
267
const nsAString& aEventName)
272
// In the unlikely case that both rev is specified *and* rel=stylesheet,
273
// this code will cause the event to fire, on the principle that maybe the
274
// page really does want to specify that it's author is a stylesheet. Since
275
// this should never actually happen and the performance hit is minimal,
276
// doing the "right" thing costs virtually nothing here, even if it doesn't
278
if (aRev.IsEmpty() &&
279
(aRel.IsEmpty() || aRel.EqualsIgnoreCase("stylesheet")))
282
nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(aDoc));
283
nsCOMPtr<nsIDOMEvent> event;
284
docEvent->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
286
event->InitEvent(aEventName, PR_TRUE, PR_TRUE);
288
nsCOMPtr<nsIDOMEventTarget> target =
289
do_QueryInterface(NS_STATIC_CAST(nsIDOMNode*, this));
291
target->DispatchEvent(event, &noDefault);
296
nsHTMLLinkElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
297
nsIAtom* aPrefix, const nsAString& aValue,
300
if (aName == nsHTMLAtoms::href && kNameSpaceID_None == aNameSpaceID) {
301
SetLinkState(eLinkState_Unknown);
304
nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
306
if (NS_SUCCEEDED(rv)) {
314
nsHTMLLinkElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
317
nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute,
319
if (NS_SUCCEEDED(rv)) {
327
nsHTMLLinkElement::HandleDOMEvent(nsIPresContext* aPresContext,
329
nsIDOMEvent** aDOMEvent,
331
nsEventStatus* aEventStatus)
333
return HandleDOMEventForAnchors(aPresContext, aEvent, aDOMEvent,
334
aFlags, aEventStatus);
338
nsHTMLLinkElement::GetLinkState(nsLinkState &aState)
345
nsHTMLLinkElement::SetLinkState(nsLinkState aState)
352
nsHTMLLinkElement::GetHrefURI(nsIURI** aURI)
354
return GetHrefURIForAnchors(aURI);
358
nsHTMLLinkElement::GetStyleSheetURL(PRBool* aIsInline,
361
*aIsInline = PR_FALSE;
362
GetHrefURIForAnchors(aURI);
367
nsHTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle,
370
PRBool* aIsAlternate)
375
*aIsAlternate = PR_FALSE;
378
nsStringArray linkTypes(4);
379
GetAttr(kNameSpaceID_None, nsHTMLAtoms::rel, rel);
380
nsStyleLinkElement::ParseLinkTypes(rel, linkTypes);
381
// Is it a stylesheet link?
382
if (linkTypes.IndexOf(NS_LITERAL_STRING("stylesheet")) < 0) {
387
GetAttr(kNameSpaceID_None, nsHTMLAtoms::title, title);
388
title.CompressWhitespace();
389
aTitle.Assign(title);
391
// If alternate, does it have title?
392
if (-1 != linkTypes.IndexOf(NS_LITERAL_STRING("alternate"))) {
393
if (aTitle.IsEmpty()) { // alternates must have title
396
*aIsAlternate = PR_TRUE;
400
GetAttr(kNameSpaceID_None, nsHTMLAtoms::media, aMedia);
401
ToLowerCase(aMedia); // HTML4.0 spec is inconsistent, make it case INSENSITIVE
403
nsAutoString mimeType;
404
nsAutoString notUsed;
405
GetAttr(kNameSpaceID_None, nsHTMLAtoms::type, aType);
406
nsParserUtils::SplitMimeType(aType, mimeType, notUsed);
407
if (!mimeType.IsEmpty() && !mimeType.EqualsIgnoreCase("text/css")) {
411
// If we get here we assume that we're loading a css file, so set the
412
// type to 'text/css'
413
aType.Assign(NS_LITERAL_STRING("text/css"));