Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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/. */
6 :
7 : #include "nsGkAtoms.h"
8 : #include "nsStyleConsts.h"
9 : #include "nsIDocument.h"
10 : #include "nsIURI.h"
11 : #include "nsNetUtil.h"
12 : #include "nsContentUtils.h"
13 : #include "nsUnicharUtils.h" // for nsCaseInsensitiveStringComparator()
14 : #include "nsIScriptContext.h"
15 : #include "nsIScriptGlobalObject.h"
16 : #include "nsIXPConnect.h"
17 : #include "nsServiceManagerUtils.h"
18 : #include "nsError.h"
19 : #include "nsIArray.h"
20 : #include "nsTArray.h"
21 : #include "nsDOMJSUtils.h"
22 : #include "nsIScriptError.h"
23 : #include "nsISupportsImpl.h"
24 : #include "mozilla/dom/HTMLScriptElement.h"
25 : #include "mozilla/dom/HTMLScriptElementBinding.h"
26 :
27 10 : NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Script)
28 :
29 : namespace mozilla {
30 : namespace dom {
31 :
32 : JSObject*
33 5 : HTMLScriptElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
34 : {
35 5 : return HTMLScriptElementBinding::Wrap(aCx, this, aGivenProto);
36 : }
37 :
38 5 : HTMLScriptElement::HTMLScriptElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
39 5 : FromParser aFromParser)
40 : : nsGenericHTMLElement(aNodeInfo)
41 5 : , ScriptElement(aFromParser)
42 : {
43 5 : AddMutationObserver(this);
44 5 : }
45 :
46 0 : HTMLScriptElement::~HTMLScriptElement()
47 : {
48 0 : }
49 :
50 864 : NS_IMPL_ISUPPORTS_INHERITED(HTMLScriptElement, nsGenericHTMLElement,
51 : nsIDOMHTMLScriptElement,
52 : nsIScriptLoaderObserver,
53 : nsIScriptElement,
54 : nsIMutationObserver)
55 :
56 : nsresult
57 5 : HTMLScriptElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
58 : nsIContent* aBindingParent,
59 : bool aCompileEventHandlers)
60 : {
61 5 : nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
62 : aBindingParent,
63 5 : aCompileEventHandlers);
64 5 : NS_ENSURE_SUCCESS(rv, rv);
65 :
66 5 : if (GetComposedDoc()) {
67 5 : MaybeProcessScript();
68 : }
69 :
70 5 : return NS_OK;
71 : }
72 :
73 : bool
74 14 : HTMLScriptElement::ParseAttribute(int32_t aNamespaceID,
75 : nsIAtom* aAttribute,
76 : const nsAString& aValue,
77 : nsAttrValue& aResult)
78 : {
79 14 : if (aNamespaceID == kNameSpaceID_None) {
80 14 : if (aAttribute == nsGkAtoms::crossorigin) {
81 0 : ParseCORSValue(aValue, aResult);
82 0 : return true;
83 : }
84 :
85 14 : if (aAttribute == nsGkAtoms::integrity) {
86 0 : aResult.ParseStringOrAtom(aValue);
87 0 : return true;
88 : }
89 : }
90 :
91 14 : return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
92 14 : aResult);
93 : }
94 :
95 : nsresult
96 0 : HTMLScriptElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
97 : bool aPreallocateChildren) const
98 : {
99 0 : *aResult = nullptr;
100 :
101 0 : already_AddRefed<mozilla::dom::NodeInfo> ni = RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
102 0 : HTMLScriptElement* it = new HTMLScriptElement(ni, NOT_FROM_PARSER);
103 :
104 0 : nsCOMPtr<nsINode> kungFuDeathGrip = it;
105 0 : nsresult rv = const_cast<HTMLScriptElement*>(this)->CopyInnerTo(it, aPreallocateChildren);
106 0 : NS_ENSURE_SUCCESS(rv, rv);
107 :
108 : // The clone should be marked evaluated if we are.
109 0 : it->mAlreadyStarted = mAlreadyStarted;
110 0 : it->mLineNumber = mLineNumber;
111 0 : it->mMalformed = mMalformed;
112 :
113 0 : kungFuDeathGrip.swap(*aResult);
114 :
115 0 : return NS_OK;
116 : }
117 :
118 : NS_IMETHODIMP
119 1 : HTMLScriptElement::GetText(nsAString& aValue)
120 : {
121 1 : if (!nsContentUtils::GetNodeTextContent(this, false, aValue, fallible)) {
122 0 : return NS_ERROR_OUT_OF_MEMORY;
123 : }
124 1 : return NS_OK;
125 : }
126 :
127 : NS_IMETHODIMP
128 0 : HTMLScriptElement::SetText(const nsAString& aValue)
129 : {
130 0 : ErrorResult rv;
131 0 : SetText(aValue, rv);
132 0 : return rv.StealNSResult();
133 : }
134 :
135 : void
136 0 : HTMLScriptElement::SetText(const nsAString& aValue, ErrorResult& rv)
137 : {
138 0 : rv = nsContentUtils::SetNodeTextContent(this, aValue, true);
139 0 : }
140 :
141 :
142 6 : NS_IMPL_STRING_ATTR(HTMLScriptElement, Charset, charset)
143 4 : NS_IMPL_BOOL_ATTR(HTMLScriptElement, Defer, defer)
144 : // If this ever gets changed to return "" if the attr value is "" (see
145 : // https://github.com/whatwg/html/issues/1739 for why it might not get changed),
146 : // it may be worth it to use GetSrc instead of GetAttr and manual
147 : // NewURIWithDocumentCharset in FreezeUriAsyncDefer.
148 0 : NS_IMPL_URI_ATTR(HTMLScriptElement, Src, src)
149 0 : NS_IMPL_STRING_ATTR(HTMLScriptElement, Type, type)
150 0 : NS_IMPL_STRING_ATTR(HTMLScriptElement, HtmlFor, _for)
151 0 : NS_IMPL_STRING_ATTR(HTMLScriptElement, Event, event)
152 :
153 : void
154 0 : HTMLScriptElement::SetCharset(const nsAString& aCharset, ErrorResult& rv)
155 : {
156 0 : SetHTMLAttr(nsGkAtoms::charset, aCharset, rv);
157 0 : }
158 :
159 : void
160 0 : HTMLScriptElement::SetDefer(bool aDefer, ErrorResult& rv)
161 : {
162 0 : SetHTMLBoolAttr(nsGkAtoms::defer, aDefer, rv);
163 0 : }
164 :
165 : bool
166 0 : HTMLScriptElement::Defer()
167 : {
168 0 : return GetBoolAttr(nsGkAtoms::defer);
169 : }
170 :
171 : void
172 0 : HTMLScriptElement::SetSrc(const nsAString& aSrc, ErrorResult& rv)
173 : {
174 0 : rv = SetAttrHelper(nsGkAtoms::src, aSrc);
175 0 : }
176 :
177 : void
178 0 : HTMLScriptElement::SetType(const nsAString& aType, ErrorResult& rv)
179 : {
180 0 : SetHTMLAttr(nsGkAtoms::type, aType, rv);
181 0 : }
182 :
183 : void
184 0 : HTMLScriptElement::SetHtmlFor(const nsAString& aHtmlFor, ErrorResult& rv)
185 : {
186 0 : SetHTMLAttr(nsGkAtoms::_for, aHtmlFor, rv);
187 0 : }
188 :
189 : void
190 0 : HTMLScriptElement::SetEvent(const nsAString& aEvent, ErrorResult& rv)
191 : {
192 0 : SetHTMLAttr(nsGkAtoms::event, aEvent, rv);
193 0 : }
194 :
195 : nsresult
196 4 : HTMLScriptElement::GetAsync(bool* aValue)
197 : {
198 4 : *aValue = Async();
199 4 : return NS_OK;
200 : }
201 :
202 : bool
203 4 : HTMLScriptElement::Async()
204 : {
205 4 : return mForceAsync || GetBoolAttr(nsGkAtoms::async);
206 : }
207 :
208 : nsresult
209 0 : HTMLScriptElement::SetAsync(bool aValue)
210 : {
211 0 : ErrorResult rv;
212 0 : SetAsync(aValue, rv);
213 0 : return rv.StealNSResult();
214 : }
215 :
216 : void
217 0 : HTMLScriptElement::SetAsync(bool aValue, ErrorResult& rv)
218 : {
219 0 : mForceAsync = false;
220 0 : SetHTMLBoolAttr(nsGkAtoms::async, aValue, rv);
221 0 : }
222 :
223 : bool
224 0 : HTMLScriptElement::NoModule()
225 : {
226 0 : return GetBoolAttr(nsGkAtoms::nomodule);
227 : }
228 :
229 : void
230 0 : HTMLScriptElement::SetNoModule(bool aValue, ErrorResult& aRv)
231 : {
232 0 : SetHTMLBoolAttr(nsGkAtoms::nomodule, aValue, aRv);
233 0 : }
234 :
235 : nsresult
236 14 : HTMLScriptElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
237 : const nsAttrValue* aValue,
238 : const nsAttrValue* aOldValue, bool aNotify)
239 : {
240 14 : if (nsGkAtoms::async == aName && kNameSpaceID_None == aNamespaceID) {
241 0 : mForceAsync = false;
242 : }
243 14 : return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
244 14 : aOldValue, aNotify);
245 : }
246 :
247 : NS_IMETHODIMP
248 0 : HTMLScriptElement::GetInnerHTML(nsAString& aInnerHTML)
249 : {
250 0 : if (!nsContentUtils::GetNodeTextContent(this, false, aInnerHTML, fallible)) {
251 0 : return NS_ERROR_OUT_OF_MEMORY;
252 : }
253 0 : return NS_OK;
254 : }
255 :
256 : void
257 0 : HTMLScriptElement::SetInnerHTML(const nsAString& aInnerHTML,
258 : ErrorResult& aError)
259 : {
260 0 : aError = nsContentUtils::SetNodeTextContent(this, aInnerHTML, true);
261 0 : }
262 :
263 : // variation of this code in nsSVGScriptElement - check if changes
264 : // need to be transfered when modifying
265 :
266 : bool
267 5 : HTMLScriptElement::GetScriptType(nsAString& type)
268 : {
269 5 : return GetAttr(kNameSpaceID_None, nsGkAtoms::type, type);
270 : }
271 :
272 : void
273 1 : HTMLScriptElement::GetScriptText(nsAString& text)
274 : {
275 1 : GetText(text);
276 1 : }
277 :
278 : void
279 6 : HTMLScriptElement::GetScriptCharset(nsAString& charset)
280 : {
281 6 : GetCharset(charset);
282 6 : }
283 :
284 : void
285 10 : HTMLScriptElement::FreezeUriAsyncDefer()
286 : {
287 10 : if (mFrozen) {
288 5 : return;
289 : }
290 :
291 : // variation of this code in nsSVGScriptElement - check if changes
292 : // need to be transfered when modifying. Note that we don't use GetSrc here
293 : // because it will return the base URL when the attr value is "".
294 10 : nsAutoString src;
295 5 : if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
296 : // Empty src should be treated as invalid URL.
297 4 : if (!src.IsEmpty()) {
298 8 : nsCOMPtr<nsIURI> baseURI = GetBaseURI();
299 8 : nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(mUri),
300 4 : src, OwnerDoc(), baseURI);
301 :
302 4 : if (!mUri) {
303 0 : const char16_t* params[] = { u"src", src.get() };
304 :
305 0 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
306 0 : NS_LITERAL_CSTRING("HTML"), OwnerDoc(),
307 : nsContentUtils::eDOM_PROPERTIES, "ScriptSourceInvalidUri",
308 0 : params, ArrayLength(params), nullptr,
309 0 : EmptyString(), GetScriptLineNumber());
310 : }
311 : } else {
312 0 : const char16_t* params[] = { u"src" };
313 :
314 0 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
315 0 : NS_LITERAL_CSTRING("HTML"), OwnerDoc(),
316 : nsContentUtils::eDOM_PROPERTIES, "ScriptSourceEmpty",
317 0 : params, ArrayLength(params), nullptr,
318 0 : EmptyString(), GetScriptLineNumber());
319 : }
320 :
321 : // At this point mUri will be null for invalid URLs.
322 4 : mExternal = true;
323 :
324 : bool defer, async;
325 4 : GetAsync(&async);
326 4 : GetDefer(&defer);
327 :
328 4 : mDefer = !async && defer;
329 4 : mAsync = async;
330 : }
331 :
332 5 : mFrozen = true;
333 : }
334 :
335 : CORSMode
336 4 : HTMLScriptElement::GetCORSMode() const
337 : {
338 4 : return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
339 : }
340 :
341 : bool
342 5 : HTMLScriptElement::HasScriptContent()
343 : {
344 6 : return (mFrozen ? mExternal : HasAttr(kNameSpaceID_None, nsGkAtoms::src)) ||
345 6 : nsContentUtils::HasNonEmptyTextContent(this);
346 : }
347 :
348 : } // namespace dom
349 : } // namespace mozilla
|