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