1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=78: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef NSREFERENCEDELEMENT_H_
8 #define NSREFERENCEDELEMENT_H_
10 #include "mozilla/Attributes.h"
11 #include "mozilla/dom/Element.h"
13 #include "nsIDocument.h"
14 #include "nsThreadUtils.h"
15 #include "nsAutoPtr.h"
18 class nsCycleCollectionCallback
;
21 * Class to track what element is referenced by a given ID.
23 * To use it, call Reset() to set it up to watch a given URI. Call get()
24 * anytime to determine the referenced element (which may be null if
25 * the element isn't found). When the element changes, ElementChanged
26 * will be called, so subclass this class if you want to receive that
27 * notification. ElementChanged runs at safe-for-script time, i.e. outside
28 * of the content update. Call Unlink() if you want to stop watching
29 * for changes (get() will then return null).
31 * By default this is a single-shot tracker --- i.e., when ElementChanged
32 * fires, we will automatically stop tracking. get() will continue to return
33 * the changed-to element.
34 * Override IsPersistent to return true if you want to keep tracking after
37 class nsReferencedElement
{
39 typedef mozilla::dom::Element Element
;
41 nsReferencedElement() {}
42 ~nsReferencedElement() {
47 * Find which element, if any, is referenced.
49 Element
* get() { return mElement
; }
52 * Set up the reference. This can be called multiple times to
53 * change which reference is being tracked, but these changes
54 * do not trigger ElementChanged.
55 * @param aFrom the source element for context
56 * @param aURI the URI containing a hash-reference to the element
57 * @param aWatch if false, then we do not set up the notifications to track
58 * changes, so ElementChanged won't fire and get() will always return the same
59 * value, the current element for the ID.
60 * @param aReferenceImage whether the ID references image elements which are
61 * subject to the document's mozSetImageElement overriding mechanism.
63 void Reset(nsIContent
* aFrom
, nsIURI
* aURI
, bool aWatch
= true,
64 bool aReferenceImage
= false);
67 * A variation on Reset() to set up a reference that consists of the ID of
68 * an element in the same document as aFrom.
69 * @param aFrom the source element for context
70 * @param aID the ID of the element
71 * @param aWatch if false, then we do not set up the notifications to track
72 * changes, so ElementChanged won't fire and get() will always return the same
73 * value, the current element for the ID.
75 void ResetWithID(nsIContent
* aFrom
, const nsString
& aID
,
79 * Clears the reference. ElementChanged is not triggered. get() will return
84 void Traverse(nsCycleCollectionTraversalCallback
* aCB
);
88 * Override this to be notified of element changes. Don't forget
89 * to call this superclass method to change mElement. This is called
90 * at script-runnable time.
92 virtual void ElementChanged(Element
* aFrom
, Element
* aTo
) {
97 * Override this to convert from a single-shot notification to
98 * a persistent notification.
100 virtual bool IsPersistent() { return false; }
103 * Set ourselves up with our new document. Note that aDocument might be
104 * null. Either aWatch must be false or aRef must be empty.
106 void HaveNewDocument(nsIDocument
* aDocument
, bool aWatch
,
107 const nsString
& aRef
);
110 static bool Observe(Element
* aOldElement
,
111 Element
* aNewElement
, void* aData
);
113 class Notification
: public nsISupports
{
115 virtual void SetTo(Element
* aTo
) = 0;
116 virtual void Clear() { mTarget
= nullptr; }
117 virtual ~Notification() {}
119 explicit Notification(nsReferencedElement
* aTarget
)
122 NS_PRECONDITION(aTarget
, "Must have a target");
124 nsReferencedElement
* mTarget
;
127 class ChangeNotification
: public nsRunnable
,
131 ChangeNotification(nsReferencedElement
* aTarget
,
132 Element
* aFrom
, Element
* aTo
)
133 : Notification(aTarget
), mFrom(aFrom
), mTo(aTo
)
136 NS_DECL_ISUPPORTS_INHERITED
137 NS_IMETHOD
Run() MOZ_OVERRIDE
{
139 mTarget
->mPendingNotification
= nullptr;
140 mTarget
->ElementChanged(mFrom
, mTo
);
144 virtual void SetTo(Element
* aTo
) MOZ_OVERRIDE
{ mTo
= aTo
; }
145 virtual void Clear() MOZ_OVERRIDE
147 Notification::Clear(); mFrom
= nullptr; mTo
= nullptr;
150 virtual ~ChangeNotification() {}
152 nsRefPtr
<Element
> mFrom
;
153 nsRefPtr
<Element
> mTo
;
155 friend class ChangeNotification
;
157 class DocumentLoadNotification
: public Notification
,
161 DocumentLoadNotification(nsReferencedElement
* aTarget
,
162 const nsString
& aRef
) :
163 Notification(aTarget
)
165 if (!mTarget
->IsPersistent()) {
173 virtual ~DocumentLoadNotification() {}
175 virtual void SetTo(Element
* aTo
) MOZ_OVERRIDE
{ }
179 friend class DocumentLoadNotification
;
181 nsCOMPtr
<nsIAtom
> mWatchID
;
182 nsCOMPtr
<nsIDocument
> mWatchDocument
;
183 nsRefPtr
<Element
> mElement
;
184 nsRefPtr
<Notification
> mPendingNotification
;
185 bool mReferencingImage
;
189 ImplCycleCollectionUnlink(nsReferencedElement
& aField
)
195 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback
& aCallback
,
196 nsReferencedElement
& aField
,
200 aField
.Traverse(&aCallback
);
203 #endif /*NSREFERENCEDELEMENT_H_*/