Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / inspector / DOMEditor.cpp
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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
13  * distribution.
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.
17  *
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.
29  */
30
31 #include "config.h"
32 #include "DOMEditor.h"
33
34 #include "DOMException.h"
35 #include "DOMPatchSupport.h"
36 #include "Document.h"
37 #include "Element.h"
38 #include "InspectorHistory.h"
39 #include "Node.h"
40 #include "Text.h"
41 #include "markup.h"
42 #include <wtf/RefPtr.h>
43
44 namespace WebCore {
45
46 class DOMEditor::RemoveChildAction final : public InspectorHistory::Action {
47     WTF_MAKE_NONCOPYABLE(RemoveChildAction);
48 public:
49     RemoveChildAction(Node& parentNode, Node& node)
50         : Action("RemoveChild")
51         , m_parentNode(parentNode)
52         , m_node(node)
53     {
54     }
55
56     ExceptionOr<void> perform() final
57     {
58         m_anchorNode = m_node->nextSibling();
59         return redo();
60     }
61
62     ExceptionOr<void> undo() final
63     {
64         return m_parentNode->insertBefore(m_node, m_anchorNode.get());
65     }
66
67     ExceptionOr<void> redo() final
68     {
69         return m_parentNode->removeChild(m_node);
70     }
71
72 private:
73     Ref<Node> m_parentNode;
74     Ref<Node> m_node;
75     RefPtr<Node> m_anchorNode;
76 };
77
78 class DOMEditor::InsertBeforeAction final : public InspectorHistory::Action {
79 public:
80     InsertBeforeAction(Node& parentNode, Ref<Node>&& node, Node* anchorNode)
81         : Action("InsertBefore")
82         , m_parentNode(parentNode)
83         , m_node(WTFMove(node))
84         , m_anchorNode(anchorNode)
85     {
86     }
87
88 private:
89     ExceptionOr<void> perform() final
90     {
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();
96         }
97         return m_parentNode->insertBefore(m_node, m_anchorNode.get());
98     }
99
100     ExceptionOr<void> undo() final
101     {
102         auto result = m_parentNode->removeChild(m_node);
103         if (result.hasException())
104             return result.releaseException();
105         if (!m_removeChildAction)
106             return { };
107         return m_removeChildAction->undo();
108     }
109
110     ExceptionOr<void> redo() final
111     {
112         if (m_removeChildAction) {
113             auto result = m_removeChildAction->redo();
114             if (result.hasException())
115                 return result.releaseException();
116         }
117         return m_parentNode->insertBefore(m_node, m_anchorNode.get());
118     }
119
120     Ref<Node> m_parentNode;
121     Ref<Node> m_node;
122     RefPtr<Node> m_anchorNode;
123     std::unique_ptr<RemoveChildAction> m_removeChildAction;
124 };
125
126 class DOMEditor::RemoveAttributeAction final : public InspectorHistory::Action {
127     WTF_MAKE_NONCOPYABLE(RemoveAttributeAction);
128 public:
129     RemoveAttributeAction(Element& element, const String& name)
130         : Action("RemoveAttribute")
131         , m_element(element)
132         , m_name(name)
133     {
134     }
135
136 private:
137     ExceptionOr<void> perform() final
138     {
139         m_value = m_element->getAttribute(m_name);
140         return redo();
141     }
142
143     ExceptionOr<void> undo() final
144     {
145         return m_element->setAttribute(m_name, m_value);
146     }
147
148     ExceptionOr<void> redo() final
149     {
150         m_element->removeAttribute(m_name);
151         return { };
152     }
153
154     Ref<Element> m_element;
155     String m_name;
156     String m_value;
157 };
158
159 class DOMEditor::SetAttributeAction final : public InspectorHistory::Action {
160     WTF_MAKE_NONCOPYABLE(SetAttributeAction);
161 public:
162     SetAttributeAction(Element& element, const AtomicString& name, const AtomicString& value)
163         : Action("SetAttribute")
164         , m_element(element)
165         , m_name(name)
166         , m_value(value)
167     {
168     }
169
170 private:
171     ExceptionOr<void> perform() final
172     {
173         m_oldValue = m_element->getAttribute(m_name);
174         return redo();
175     }
176
177     ExceptionOr<void> undo() final
178     {
179         if (m_oldValue.isNull()) {
180             m_element->removeAttribute(m_name);
181             return { };
182         }
183         return m_element->setAttribute(m_name, m_oldValue);
184     }
185
186     ExceptionOr<void> redo() final
187     {
188         return m_element->setAttribute(m_name, m_value);
189     }
190
191     Ref<Element> m_element;
192     AtomicString m_name;
193     AtomicString m_value;
194     AtomicString m_oldValue;
195 };
196
197 class DOMEditor::SetOuterHTMLAction final : public InspectorHistory::Action {
198 public:
199     SetOuterHTMLAction(Node& node, const String& html)
200         : Action("SetOuterHTML")
201         , m_node(node)
202         , m_nextSibling(node.nextSibling())
203         , m_html(html)
204     {
205     }
206
207     Node* newNode() const
208     {
209         return m_newNode.get();
210     }
211
212 private:
213     ExceptionOr<void> perform() final
214     {
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();
220         return { };
221     }
222
223     ExceptionOr<void> undo() final
224     {
225         return m_history.undo();
226     }
227
228     ExceptionOr<void> redo() final
229     {
230         return m_history.redo();
231     }
232
233     Ref<Node> m_node;
234     RefPtr<Node> m_nextSibling;
235     String m_html;
236     String m_oldHTML;
237     RefPtr<Node> m_newNode { nullptr };
238     InspectorHistory m_history;
239     DOMEditor m_domEditor { m_history };
240 };
241
242 class DOMEditor::ReplaceWholeTextAction final : public InspectorHistory::Action {
243     WTF_MAKE_NONCOPYABLE(ReplaceWholeTextAction);
244 public:
245     ReplaceWholeTextAction(Text& textNode, const String& text)
246         : Action("ReplaceWholeText")
247         , m_textNode(textNode)
248         , m_text(text)
249     {
250     }
251
252 private:
253     ExceptionOr<void> perform() final
254     {
255         m_oldText = m_textNode->wholeText();
256         return redo();
257     }
258
259     ExceptionOr<void> undo() final
260     {
261         m_textNode->replaceWholeText(m_oldText);
262         return { };
263     }
264
265     ExceptionOr<void> redo() final
266     {
267         m_textNode->replaceWholeText(m_text);
268         return { };
269     }
270
271     Ref<Text> m_textNode;
272     String m_text;
273     String m_oldText;
274 };
275
276 class DOMEditor::ReplaceChildNodeAction final: public InspectorHistory::Action {
277     WTF_MAKE_NONCOPYABLE(ReplaceChildNodeAction);
278 public:
279     ReplaceChildNodeAction(Node& parentNode, Ref<Node>&& newNode, Node& oldNode)
280         : Action("ReplaceChildNode")
281         , m_parentNode(parentNode)
282         , m_newNode(WTFMove(newNode))
283         , m_oldNode(oldNode)
284     {
285     }
286
287 private:
288     ExceptionOr<void> perform() final
289     {
290         return redo();
291     }
292
293     ExceptionOr<void> undo() final
294     {
295         return m_parentNode->replaceChild(m_oldNode, m_newNode);
296     }
297
298     ExceptionOr<void> redo() final
299     {
300         return m_parentNode->replaceChild(m_newNode, m_oldNode);
301     }
302
303     Ref<Node> m_parentNode;
304     Ref<Node> m_newNode;
305     Ref<Node> m_oldNode;
306 };
307
308 class DOMEditor::SetNodeValueAction final : public InspectorHistory::Action {
309     WTF_MAKE_NONCOPYABLE(SetNodeValueAction);
310 public:
311     SetNodeValueAction(Node& node, const String& value)
312         : Action("SetNodeValue")
313         , m_node(node)
314         , m_value(value)
315     {
316     }
317
318 private:
319     ExceptionOr<void> perform() final
320     {
321         m_oldValue = m_node->nodeValue();
322         return redo();
323     }
324
325     ExceptionOr<void> undo() final
326     {
327         return m_node->setNodeValue(m_oldValue);
328     }
329
330     ExceptionOr<void> redo() final
331     {
332         return m_node->setNodeValue(m_value);
333     }
334
335     Ref<Node> m_node;
336     String m_value;
337     String m_oldValue;
338 };
339
340 DOMEditor::DOMEditor(InspectorHistory& history)
341     : m_history(history)
342 {
343 }
344
345 DOMEditor::~DOMEditor() = default;
346
347 ExceptionOr<void> DOMEditor::insertBefore(Node& parentNode, Ref<Node>&& node, Node* anchorNode)
348 {
349     return m_history.perform(std::make_unique<InsertBeforeAction>(parentNode, WTFMove(node), anchorNode));
350 }
351
352 ExceptionOr<void> DOMEditor::removeChild(Node& parentNode, Node& node)
353 {
354     return m_history.perform(std::make_unique<RemoveChildAction>(parentNode, node));
355 }
356
357 ExceptionOr<void> DOMEditor::setAttribute(Element& element, const String& name, const String& value)
358 {
359     return m_history.perform(std::make_unique<SetAttributeAction>(element, name, value));
360 }
361
362 ExceptionOr<void> DOMEditor::removeAttribute(Element& element, const String& name)
363 {
364     return m_history.perform(std::make_unique<RemoveAttributeAction>(element, name));
365 }
366
367 ExceptionOr<void> DOMEditor::setOuterHTML(Node& node, const String& html, Node*& newNode)
368 {
369     auto action = std::make_unique<SetOuterHTMLAction>(node, html);
370     auto& rawAction = *action;
371     auto result = m_history.perform(WTFMove(action));
372     if (!result.hasException())
373         newNode = rawAction.newNode();
374     return result;
375 }
376
377 ExceptionOr<void> DOMEditor::replaceWholeText(Text& textNode, const String& text)
378 {
379     return m_history.perform(std::make_unique<ReplaceWholeTextAction>(textNode, text));
380 }
381
382 ExceptionOr<void> DOMEditor::replaceChild(Node& parentNode, Ref<Node>&& newNode, Node& oldNode)
383 {
384     return m_history.perform(std::make_unique<ReplaceChildNodeAction>(parentNode, WTFMove(newNode), oldNode));
385 }
386
387 ExceptionOr<void> DOMEditor::setNodeValue(Node& node, const String& value)
388 {
389     return m_history.perform(std::make_unique<SetNodeValueAction>(node, value));
390 }
391
392 static bool populateErrorString(ExceptionOr<void>&& result, ErrorString& errorString)
393 {
394     if (!result.hasException())
395         return true;
396     errorString = DOMException::name(result.releaseException().code());
397     return false;
398 }
399
400 bool DOMEditor::insertBefore(Node& parentNode, Ref<Node>&& node, Node* anchorNode, ErrorString& errorString)
401 {
402     return populateErrorString(insertBefore(parentNode, WTFMove(node), anchorNode), errorString);
403 }
404
405 bool DOMEditor::removeChild(Node& parentNode, Node& node, ErrorString& errorString)
406 {
407     return populateErrorString(removeChild(parentNode, node), errorString);
408 }
409
410 bool DOMEditor::setAttribute(Element& element, const String& name, const String& value, ErrorString& errorString)
411 {
412     return populateErrorString(setAttribute(element, name, value), errorString);
413 }
414
415 bool DOMEditor::removeAttribute(Element& element, const String& name, ErrorString& errorString)
416 {
417     return populateErrorString(removeAttribute(element, name), errorString);
418 }
419
420 bool DOMEditor::setOuterHTML(Node& node, const String& html, Node*& newNode, ErrorString& errorString)
421 {
422     return populateErrorString(setOuterHTML(node, html, newNode), errorString);
423 }
424
425 bool DOMEditor::replaceWholeText(Text& textNode, const String& text, ErrorString& errorString)
426 {
427     return populateErrorString(replaceWholeText(textNode, text), errorString);
428 }
429
430 } // namespace WebCore