2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "core/inspector/DOMEditor.h"
34 #include "bindings/core/v8/ExceptionState.h"
35 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
36 #include "core/dom/DOMException.h"
37 #include "core/dom/Element.h"
38 #include "core/dom/Node.h"
39 #include "core/dom/Text.h"
40 #include "core/editing/markup.h"
41 #include "core/inspector/DOMPatchSupport.h"
42 #include "core/inspector/InspectorHistory.h"
43 #include "wtf/RefPtr.h"
47 class DOMEditor::RemoveChildAction final : public InspectorHistory::Action {
48 WTF_MAKE_NONCOPYABLE(RemoveChildAction);
50 RemoveChildAction(Node* parentNode, Node* node)
51 : InspectorHistory::Action("RemoveChild")
52 , m_parentNode(parentNode)
57 virtual bool perform(ExceptionState& exceptionState) override
59 m_anchorNode = m_node->nextSibling();
60 return redo(exceptionState);
63 virtual bool undo(ExceptionState& exceptionState) override
65 m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), exceptionState);
66 return !exceptionState.hadException();
69 virtual bool redo(ExceptionState& exceptionState) override
71 m_parentNode->removeChild(m_node.get(), exceptionState);
72 return !exceptionState.hadException();
75 virtual void trace(Visitor* visitor) override
77 visitor->trace(m_parentNode);
78 visitor->trace(m_node);
79 visitor->trace(m_anchorNode);
80 InspectorHistory::Action::trace(visitor);
84 RefPtrWillBeMember<Node> m_parentNode;
85 RefPtrWillBeMember<Node> m_node;
86 RefPtrWillBeMember<Node> m_anchorNode;
89 class DOMEditor::InsertBeforeAction final : public InspectorHistory::Action {
90 WTF_MAKE_NONCOPYABLE(InsertBeforeAction);
92 InsertBeforeAction(Node* parentNode, PassRefPtrWillBeRawPtr<Node> node, Node* anchorNode)
93 : InspectorHistory::Action("InsertBefore")
94 , m_parentNode(parentNode)
96 , m_anchorNode(anchorNode)
100 virtual bool perform(ExceptionState& exceptionState) override
102 if (m_node->parentNode()) {
103 m_removeChildAction = adoptRefWillBeNoop(new RemoveChildAction(m_node->parentNode(), m_node.get()));
104 if (!m_removeChildAction->perform(exceptionState))
107 m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), exceptionState);
108 return !exceptionState.hadException();
111 virtual bool undo(ExceptionState& exceptionState) override
113 m_parentNode->removeChild(m_node.get(), exceptionState);
114 if (exceptionState.hadException())
116 if (m_removeChildAction)
117 return m_removeChildAction->undo(exceptionState);
121 virtual bool redo(ExceptionState& exceptionState) override
123 if (m_removeChildAction && !m_removeChildAction->redo(exceptionState))
125 m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), exceptionState);
126 return !exceptionState.hadException();
129 virtual void trace(Visitor* visitor) override
131 visitor->trace(m_parentNode);
132 visitor->trace(m_node);
133 visitor->trace(m_anchorNode);
134 visitor->trace(m_removeChildAction);
135 InspectorHistory::Action::trace(visitor);
139 RefPtrWillBeMember<Node> m_parentNode;
140 RefPtrWillBeMember<Node> m_node;
141 RefPtrWillBeMember<Node> m_anchorNode;
142 RefPtrWillBeMember<RemoveChildAction> m_removeChildAction;
145 class DOMEditor::RemoveAttributeAction final : public InspectorHistory::Action {
146 WTF_MAKE_NONCOPYABLE(RemoveAttributeAction);
148 RemoveAttributeAction(Element* element, const AtomicString& name)
149 : InspectorHistory::Action("RemoveAttribute")
155 virtual bool perform(ExceptionState& exceptionState) override
157 m_value = m_element->getAttribute(m_name);
158 return redo(exceptionState);
161 virtual bool undo(ExceptionState& exceptionState) override
163 m_element->setAttribute(m_name, m_value, exceptionState);
167 virtual bool redo(ExceptionState&) override
169 m_element->removeAttribute(m_name);
173 virtual void trace(Visitor* visitor) override
175 visitor->trace(m_element);
176 InspectorHistory::Action::trace(visitor);
180 RefPtrWillBeMember<Element> m_element;
182 AtomicString m_value;
185 class DOMEditor::SetAttributeAction final : public InspectorHistory::Action {
186 WTF_MAKE_NONCOPYABLE(SetAttributeAction);
188 SetAttributeAction(Element* element, const AtomicString& name, const AtomicString& value)
189 : InspectorHistory::Action("SetAttribute")
193 , m_hadAttribute(false)
197 virtual bool perform(ExceptionState& exceptionState) override
199 const AtomicString& value = m_element->getAttribute(m_name);
200 m_hadAttribute = !value.isNull();
203 return redo(exceptionState);
206 virtual bool undo(ExceptionState& exceptionState) override
209 m_element->setAttribute(m_name, m_oldValue, exceptionState);
211 m_element->removeAttribute(m_name);
215 virtual bool redo(ExceptionState& exceptionState) override
217 m_element->setAttribute(m_name, m_value, exceptionState);
221 virtual void trace(Visitor* visitor) override
223 visitor->trace(m_element);
224 InspectorHistory::Action::trace(visitor);
228 RefPtrWillBeMember<Element> m_element;
230 AtomicString m_value;
232 AtomicString m_oldValue;
235 class DOMEditor::SetOuterHTMLAction final : public InspectorHistory::Action {
236 WTF_MAKE_NONCOPYABLE(SetOuterHTMLAction);
238 SetOuterHTMLAction(Node* node, const String& html)
239 : InspectorHistory::Action("SetOuterHTML")
241 , m_nextSibling(node->nextSibling())
244 , m_history(adoptPtrWillBeNoop(new InspectorHistory()))
245 , m_domEditor(adoptPtrWillBeNoop(new DOMEditor(m_history.get())))
249 virtual bool perform(ExceptionState& exceptionState) override
251 m_oldHTML = createMarkup(m_node.get());
252 ASSERT(m_node->ownerDocument());
253 DOMPatchSupport domPatchSupport(m_domEditor.get(), *m_node->ownerDocument());
254 m_newNode = domPatchSupport.patchNode(m_node.get(), m_html, exceptionState);
255 return !exceptionState.hadException();
258 virtual bool undo(ExceptionState& exceptionState) override
260 return m_history->undo(exceptionState);
263 virtual bool redo(ExceptionState& exceptionState) override
265 return m_history->redo(exceptionState);
273 virtual void trace(Visitor* visitor) override
275 visitor->trace(m_node);
276 visitor->trace(m_nextSibling);
277 visitor->trace(m_newNode);
278 visitor->trace(m_history);
279 visitor->trace(m_domEditor);
280 InspectorHistory::Action::trace(visitor);
284 RefPtrWillBeMember<Node> m_node;
285 RefPtrWillBeMember<Node> m_nextSibling;
288 RawPtrWillBeMember<Node> m_newNode;
289 OwnPtrWillBeMember<InspectorHistory> m_history;
290 OwnPtrWillBeMember<DOMEditor> m_domEditor;
293 class DOMEditor::ReplaceWholeTextAction final : public InspectorHistory::Action {
294 WTF_MAKE_NONCOPYABLE(ReplaceWholeTextAction);
296 ReplaceWholeTextAction(Text* textNode, const String& text)
297 : InspectorHistory::Action("ReplaceWholeText")
298 , m_textNode(textNode)
303 virtual bool perform(ExceptionState& exceptionState) override
305 m_oldText = m_textNode->wholeText();
306 return redo(exceptionState);
309 virtual bool undo(ExceptionState&) override
311 m_textNode->replaceWholeText(m_oldText);
315 virtual bool redo(ExceptionState&) override
317 m_textNode->replaceWholeText(m_text);
321 virtual void trace(Visitor* visitor) override
323 visitor->trace(m_textNode);
324 InspectorHistory::Action::trace(visitor);
328 RefPtrWillBeMember<Text> m_textNode;
333 class DOMEditor::ReplaceChildNodeAction final : public InspectorHistory::Action {
334 WTF_MAKE_NONCOPYABLE(ReplaceChildNodeAction);
336 ReplaceChildNodeAction(Node* parentNode, PassRefPtrWillBeRawPtr<Node> newNode, Node* oldNode)
337 : InspectorHistory::Action("ReplaceChildNode")
338 , m_parentNode(parentNode)
344 virtual bool perform(ExceptionState& exceptionState) override
346 return redo(exceptionState);
349 virtual bool undo(ExceptionState& exceptionState) override
351 m_parentNode->replaceChild(m_oldNode, m_newNode.get(), exceptionState);
352 return !exceptionState.hadException();
355 virtual bool redo(ExceptionState& exceptionState) override
357 m_parentNode->replaceChild(m_newNode, m_oldNode.get(), exceptionState);
358 return !exceptionState.hadException();
361 virtual void trace(Visitor* visitor) override
363 visitor->trace(m_parentNode);
364 visitor->trace(m_newNode);
365 visitor->trace(m_oldNode);
366 InspectorHistory::Action::trace(visitor);
370 RefPtrWillBeMember<Node> m_parentNode;
371 RefPtrWillBeMember<Node> m_newNode;
372 RefPtrWillBeMember<Node> m_oldNode;
375 class DOMEditor::SetNodeValueAction final : public InspectorHistory::Action {
376 WTF_MAKE_NONCOPYABLE(SetNodeValueAction);
378 SetNodeValueAction(Node* node, const String& value)
379 : InspectorHistory::Action("SetNodeValue")
385 virtual bool perform(ExceptionState&) override
387 m_oldValue = m_node->nodeValue();
388 return redo(IGNORE_EXCEPTION);
391 virtual bool undo(ExceptionState&) override
393 m_node->setNodeValue(m_oldValue);
397 virtual bool redo(ExceptionState&) override
399 m_node->setNodeValue(m_value);
403 virtual void trace(Visitor* visitor) override
405 visitor->trace(m_node);
406 InspectorHistory::Action::trace(visitor);
410 RefPtrWillBeMember<Node> m_node;
415 DOMEditor::DOMEditor(InspectorHistory* history) : m_history(history) { }
417 bool DOMEditor::insertBefore(Node* parentNode, PassRefPtrWillBeRawPtr<Node> node, Node* anchorNode, ExceptionState& exceptionState)
419 return m_history->perform(adoptRefWillBeNoop(new InsertBeforeAction(parentNode, node, anchorNode)), exceptionState);
422 bool DOMEditor::removeChild(Node* parentNode, Node* node, ExceptionState& exceptionState)
424 return m_history->perform(adoptRefWillBeNoop(new RemoveChildAction(parentNode, node)), exceptionState);
427 bool DOMEditor::setAttribute(Element* element, const String& name, const String& value, ExceptionState& exceptionState)
429 return m_history->perform(adoptRefWillBeNoop(new SetAttributeAction(element, AtomicString(name), AtomicString(value))), exceptionState);
432 bool DOMEditor::removeAttribute(Element* element, const String& name, ExceptionState& exceptionState)
434 return m_history->perform(adoptRefWillBeNoop(new RemoveAttributeAction(element, AtomicString(name))), exceptionState);
437 bool DOMEditor::setOuterHTML(Node* node, const String& html, Node** newNode, ExceptionState& exceptionState)
439 RefPtrWillBeRawPtr<SetOuterHTMLAction> action = adoptRefWillBeNoop(new SetOuterHTMLAction(node, html));
440 bool result = m_history->perform(action, exceptionState);
442 *newNode = action->newNode();
446 bool DOMEditor::replaceWholeText(Text* textNode, const String& text, ExceptionState& exceptionState)
448 return m_history->perform(adoptRefWillBeNoop(new ReplaceWholeTextAction(textNode, text)), exceptionState);
451 bool DOMEditor::replaceChild(Node* parentNode, PassRefPtrWillBeRawPtr<Node> newNode, Node* oldNode, ExceptionState& exceptionState)
453 return m_history->perform(adoptRefWillBeNoop(new ReplaceChildNodeAction(parentNode, newNode, oldNode)), exceptionState);
456 bool DOMEditor::setNodeValue(Node* node, const String& value, ExceptionState& exceptionState)
458 return m_history->perform(adoptRefWillBeNoop(new SetNodeValueAction(node, value)), exceptionState);
461 static void populateErrorString(ExceptionState& exceptionState, ErrorString* errorString)
463 if (exceptionState.hadException())
464 *errorString = DOMException::getErrorName(exceptionState.code());
467 bool DOMEditor::insertBefore(Node* parentNode, PassRefPtrWillBeRawPtr<Node> node, Node* anchorNode, ErrorString* errorString)
469 TrackExceptionState exceptionState;
470 bool result = insertBefore(parentNode, node, anchorNode, exceptionState);
471 populateErrorString(exceptionState, errorString);
475 bool DOMEditor::removeChild(Node* parentNode, Node* node, ErrorString* errorString)
477 TrackExceptionState exceptionState;
478 bool result = removeChild(parentNode, node, exceptionState);
479 populateErrorString(exceptionState, errorString);
483 bool DOMEditor::setAttribute(Element* element, const String& name, const String& value, ErrorString* errorString)
485 TrackExceptionState exceptionState;
486 bool result = setAttribute(element, name, value, exceptionState);
487 populateErrorString(exceptionState, errorString);
491 bool DOMEditor::removeAttribute(Element* element, const String& name, ErrorString* errorString)
493 TrackExceptionState exceptionState;
494 bool result = removeAttribute(element, name, exceptionState);
495 populateErrorString(exceptionState, errorString);
499 bool DOMEditor::setOuterHTML(Node* node, const String& html, Node** newNode, ErrorString* errorString)
501 TrackExceptionState exceptionState;
502 bool result = setOuterHTML(node, html, newNode, exceptionState);
503 populateErrorString(exceptionState, errorString);
507 bool DOMEditor::replaceWholeText(Text* textNode, const String& text, ErrorString* errorString)
509 TrackExceptionState exceptionState;
510 bool result = replaceWholeText(textNode, text, exceptionState);
511 populateErrorString(exceptionState, errorString);
515 void DOMEditor::trace(Visitor* visitor)
517 visitor->trace(m_history);