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 "DOMEditor.h"
34 #include "DOMException.h"
35 #include "DOMPatchSupport.h"
38 #include "InspectorHistory.h"
42 #include <wtf/RefPtr.h>
46 class DOMEditor::RemoveChildAction final : public InspectorHistory::Action {
47 WTF_MAKE_NONCOPYABLE(RemoveChildAction);
49 RemoveChildAction(Node& parentNode, Node& node)
50 : InspectorHistory::Action()
51 , m_parentNode(parentNode)
56 ExceptionOr<void> perform() final
58 m_anchorNode = m_node->nextSibling();
62 ExceptionOr<void> undo() final
64 return m_parentNode->insertBefore(m_node, m_anchorNode.get());
67 ExceptionOr<void> redo() final
69 return m_parentNode->removeChild(m_node);
73 Ref<Node> m_parentNode;
75 RefPtr<Node> m_anchorNode;
78 class DOMEditor::InsertBeforeAction final : public InspectorHistory::Action {
80 InsertBeforeAction(Node& parentNode, Ref<Node>&& node, Node* anchorNode)
81 : InspectorHistory::Action()
82 , m_parentNode(parentNode)
83 , m_node(WTFMove(node))
84 , m_anchorNode(anchorNode)
89 ExceptionOr<void> perform() final
91 if (m_node->parentNode()) {
92 m_removeChildAction = std::make_unique<RemoveChildAction>(*m_node->parentNode(), m_node);
93 auto result = m_removeChildAction->perform();
94 if (result.hasException())
95 return result.releaseException();
97 return m_parentNode->insertBefore(m_node, m_anchorNode.get());
100 ExceptionOr<void> undo() final
102 auto result = m_parentNode->removeChild(m_node);
103 if (result.hasException())
104 return result.releaseException();
105 if (!m_removeChildAction)
107 return m_removeChildAction->undo();
110 ExceptionOr<void> redo() final
112 if (m_removeChildAction) {
113 auto result = m_removeChildAction->redo();
114 if (result.hasException())
115 return result.releaseException();
117 return m_parentNode->insertBefore(m_node, m_anchorNode.get());
120 Ref<Node> m_parentNode;
122 RefPtr<Node> m_anchorNode;
123 std::unique_ptr<RemoveChildAction> m_removeChildAction;
126 class DOMEditor::RemoveAttributeAction final : public InspectorHistory::Action {
127 WTF_MAKE_NONCOPYABLE(RemoveAttributeAction);
129 RemoveAttributeAction(Element& element, const String& name)
130 : InspectorHistory::Action()
137 ExceptionOr<void> perform() final
139 m_value = m_element->getAttribute(m_name);
143 ExceptionOr<void> undo() final
145 return m_element->setAttribute(m_name, m_value);
148 ExceptionOr<void> redo() final
150 m_element->removeAttribute(m_name);
154 Ref<Element> m_element;
159 class DOMEditor::SetAttributeAction final : public InspectorHistory::Action {
160 WTF_MAKE_NONCOPYABLE(SetAttributeAction);
162 SetAttributeAction(Element& element, const AtomicString& name, const AtomicString& value)
163 : InspectorHistory::Action()
171 ExceptionOr<void> perform() final
173 m_oldValue = m_element->getAttribute(m_name);
177 ExceptionOr<void> undo() final
179 if (m_oldValue.isNull()) {
180 m_element->removeAttribute(m_name);
183 return m_element->setAttribute(m_name, m_oldValue);
186 ExceptionOr<void> redo() final
188 return m_element->setAttribute(m_name, m_value);
191 Ref<Element> m_element;
193 AtomicString m_value;
194 AtomicString m_oldValue;
197 class DOMEditor::SetOuterHTMLAction final : public InspectorHistory::Action {
199 SetOuterHTMLAction(Node& node, const String& html)
200 : InspectorHistory::Action()
202 , m_nextSibling(node.nextSibling())
207 Node* newNode() const
209 return m_newNode.get();
213 ExceptionOr<void> perform() final
215 m_oldHTML = createMarkup(m_node.get());
216 auto result = DOMPatchSupport { m_domEditor, m_node->document() }.patchNode(m_node, m_html);
217 if (result.hasException())
218 return result.releaseException();
219 m_newNode = result.releaseReturnValue();
223 ExceptionOr<void> undo() final
225 return m_history.undo();
228 ExceptionOr<void> redo() final
230 return m_history.redo();
234 RefPtr<Node> m_nextSibling;
237 RefPtr<Node> m_newNode { nullptr };
238 InspectorHistory m_history;
239 DOMEditor m_domEditor { m_history };
242 class DOMEditor::InsertAdjacentHTMLAction final : public InspectorHistory::Action {
243 WTF_MAKE_NONCOPYABLE(InsertAdjacentHTMLAction);
245 InsertAdjacentHTMLAction(Element& element, const String& position, const String& html)
246 : InspectorHistory::Action()
248 , m_position(position)
254 ExceptionOr<void> perform() final
259 ExceptionOr<void> undo() final
261 for (auto& addedNode : m_addedNodes)
263 m_addedNodes.clear();
267 ExceptionOr<void> redo() final
269 auto result = m_element->insertAdjacentHTML(m_position, m_html, m_addedNodes);
270 if (result.hasException())
271 return result.releaseException();
275 Ref<Element> m_element;
276 NodeVector m_addedNodes;
281 class DOMEditor::ReplaceWholeTextAction final : public InspectorHistory::Action {
282 WTF_MAKE_NONCOPYABLE(ReplaceWholeTextAction);
284 ReplaceWholeTextAction(Text& textNode, const String& text)
285 : InspectorHistory::Action()
286 , m_textNode(textNode)
292 ExceptionOr<void> perform() final
294 m_oldText = m_textNode->wholeText();
298 ExceptionOr<void> undo() final
300 m_textNode->replaceWholeText(m_oldText);
304 ExceptionOr<void> redo() final
306 m_textNode->replaceWholeText(m_text);
310 Ref<Text> m_textNode;
315 class DOMEditor::ReplaceChildNodeAction final: public InspectorHistory::Action {
316 WTF_MAKE_NONCOPYABLE(ReplaceChildNodeAction);
318 ReplaceChildNodeAction(Node& parentNode, Ref<Node>&& newNode, Node& oldNode)
319 : InspectorHistory::Action()
320 , m_parentNode(parentNode)
321 , m_newNode(WTFMove(newNode))
327 ExceptionOr<void> perform() final
332 ExceptionOr<void> undo() final
334 return m_parentNode->replaceChild(m_oldNode, m_newNode);
337 ExceptionOr<void> redo() final
339 return m_parentNode->replaceChild(m_newNode, m_oldNode);
342 Ref<Node> m_parentNode;
347 class DOMEditor::SetNodeValueAction final : public InspectorHistory::Action {
348 WTF_MAKE_NONCOPYABLE(SetNodeValueAction);
350 SetNodeValueAction(Node& node, const String& value)
351 : InspectorHistory::Action()
358 ExceptionOr<void> perform() final
360 m_oldValue = m_node->nodeValue();
364 ExceptionOr<void> undo() final
366 return m_node->setNodeValue(m_oldValue);
369 ExceptionOr<void> redo() final
371 return m_node->setNodeValue(m_value);
379 DOMEditor::DOMEditor(InspectorHistory& history)
384 DOMEditor::~DOMEditor() = default;
386 ExceptionOr<void> DOMEditor::insertBefore(Node& parentNode, Ref<Node>&& node, Node* anchorNode)
388 return m_history.perform(std::make_unique<InsertBeforeAction>(parentNode, WTFMove(node), anchorNode));
391 ExceptionOr<void> DOMEditor::removeChild(Node& parentNode, Node& node)
393 return m_history.perform(std::make_unique<RemoveChildAction>(parentNode, node));
396 ExceptionOr<void> DOMEditor::setAttribute(Element& element, const String& name, const String& value)
398 return m_history.perform(std::make_unique<SetAttributeAction>(element, name, value));
401 ExceptionOr<void> DOMEditor::removeAttribute(Element& element, const String& name)
403 return m_history.perform(std::make_unique<RemoveAttributeAction>(element, name));
406 ExceptionOr<void> DOMEditor::setOuterHTML(Node& node, const String& html, Node*& newNode)
408 auto action = std::make_unique<SetOuterHTMLAction>(node, html);
409 auto& rawAction = *action;
410 auto result = m_history.perform(WTFMove(action));
411 if (!result.hasException())
412 newNode = rawAction.newNode();
416 ExceptionOr<void> DOMEditor::insertAdjacentHTML(Element& element, const String& where, const String& html)
418 return m_history.perform(std::make_unique<InsertAdjacentHTMLAction>(element, where, html));
421 ExceptionOr<void> DOMEditor::replaceWholeText(Text& textNode, const String& text)
423 return m_history.perform(std::make_unique<ReplaceWholeTextAction>(textNode, text));
426 ExceptionOr<void> DOMEditor::replaceChild(Node& parentNode, Ref<Node>&& newNode, Node& oldNode)
428 return m_history.perform(std::make_unique<ReplaceChildNodeAction>(parentNode, WTFMove(newNode), oldNode));
431 ExceptionOr<void> DOMEditor::setNodeValue(Node& node, const String& value)
433 return m_history.perform(std::make_unique<SetNodeValueAction>(node, value));
436 static bool populateErrorString(ExceptionOr<void>&& result, ErrorString& errorString)
438 if (!result.hasException())
440 errorString = DOMException::name(result.releaseException().code());
444 bool DOMEditor::insertBefore(Node& parentNode, Ref<Node>&& node, Node* anchorNode, ErrorString& errorString)
446 return populateErrorString(insertBefore(parentNode, WTFMove(node), anchorNode), errorString);
449 bool DOMEditor::removeChild(Node& parentNode, Node& node, ErrorString& errorString)
451 return populateErrorString(removeChild(parentNode, node), errorString);
454 bool DOMEditor::setAttribute(Element& element, const String& name, const String& value, ErrorString& errorString)
456 return populateErrorString(setAttribute(element, name, value), errorString);
459 bool DOMEditor::removeAttribute(Element& element, const String& name, ErrorString& errorString)
461 return populateErrorString(removeAttribute(element, name), errorString);
464 bool DOMEditor::setOuterHTML(Node& node, const String& html, Node*& newNode, ErrorString& errorString)
466 return populateErrorString(setOuterHTML(node, html, newNode), errorString);
469 bool DOMEditor::insertAdjacentHTML(Element& element, const String& where, const String& html, ErrorString& errorString)
471 return populateErrorString(insertAdjacentHTML(element, where, html), errorString);
474 bool DOMEditor::replaceWholeText(Text& textNode, const String& text, ErrorString& errorString)
476 return populateErrorString(replaceWholeText(textNode, text), errorString);
479 } // namespace WebCore