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