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