root/Source/core/inspector/DOMEditor.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. m_node
  2. perform
  3. undo
  4. redo
  5. m_anchorNode
  6. perform
  7. undo
  8. redo
  9. m_name
  10. perform
  11. undo
  12. redo
  13. m_hadAttribute
  14. perform
  15. undo
  16. redo
  17. m_domEditor
  18. perform
  19. undo
  20. redo
  21. newNode
  22. m_text
  23. perform
  24. undo
  25. redo
  26. m_oldNode
  27. perform
  28. undo
  29. redo
  30. m_value
  31. perform
  32. undo
  33. redo
  34. insertBefore
  35. removeChild
  36. setAttribute
  37. removeAttribute
  38. setOuterHTML
  39. replaceWholeText
  40. replaceChild
  41. setNodeValue
  42. populateErrorString
  43. insertBefore
  44. removeChild
  45. setAttribute
  46. removeAttribute
  47. setOuterHTML
  48. replaceWholeText

/*
 * Copyright (C) 2012 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "core/inspector/DOMEditor.h"

#include "bindings/v8/ExceptionState.h"
#include "bindings/v8/ExceptionStatePlaceholder.h"
#include "core/dom/DOMException.h"
#include "core/dom/Element.h"
#include "core/dom/Node.h"
#include "core/dom/Text.h"
#include "core/editing/markup.h"
#include "core/inspector/DOMPatchSupport.h"
#include "core/inspector/InspectorHistory.h"
#include "wtf/RefPtr.h"

using namespace std;

namespace WebCore {

class DOMEditor::RemoveChildAction FINAL : public InspectorHistory::Action {
    WTF_MAKE_NONCOPYABLE(RemoveChildAction);
public:
    RemoveChildAction(Node* parentNode, Node* node)
        : InspectorHistory::Action("RemoveChild")
        , m_parentNode(parentNode)
        , m_node(node)
    {
    }

    virtual bool perform(ExceptionState& exceptionState) OVERRIDE
    {
        m_anchorNode = m_node->nextSibling();
        return redo(exceptionState);
    }

    virtual bool undo(ExceptionState& exceptionState) OVERRIDE
    {
        m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), exceptionState);
        return !exceptionState.hadException();
    }

    virtual bool redo(ExceptionState& exceptionState) OVERRIDE
    {
        m_parentNode->removeChild(m_node.get(), exceptionState);
        return !exceptionState.hadException();
    }

private:
    RefPtr<Node> m_parentNode;
    RefPtr<Node> m_node;
    RefPtr<Node> m_anchorNode;
};

class DOMEditor::InsertBeforeAction FINAL : public InspectorHistory::Action {
    WTF_MAKE_NONCOPYABLE(InsertBeforeAction);
public:
    InsertBeforeAction(Node* parentNode, PassRefPtr<Node> node, Node* anchorNode)
        : InspectorHistory::Action("InsertBefore")
        , m_parentNode(parentNode)
        , m_node(node)
        , m_anchorNode(anchorNode)
    {
    }

    virtual bool perform(ExceptionState& exceptionState) OVERRIDE
    {
        if (m_node->parentNode()) {
            m_removeChildAction = adoptRef(new RemoveChildAction(m_node->parentNode(), m_node.get()));
            if (!m_removeChildAction->perform(exceptionState))
                return false;
        }
        m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), exceptionState);
        return !exceptionState.hadException();
    }

    virtual bool undo(ExceptionState& exceptionState) OVERRIDE
    {
        m_parentNode->removeChild(m_node.get(), exceptionState);
        if (exceptionState.hadException())
            return false;
        if (m_removeChildAction)
            return m_removeChildAction->undo(exceptionState);
        return true;
    }

    virtual bool redo(ExceptionState& exceptionState) OVERRIDE
    {
        if (m_removeChildAction && !m_removeChildAction->redo(exceptionState))
            return false;
        m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), exceptionState);
        return !exceptionState.hadException();
    }

private:
    RefPtr<Node> m_parentNode;
    RefPtr<Node> m_node;
    RefPtr<Node> m_anchorNode;
    RefPtr<RemoveChildAction> m_removeChildAction;
};

class DOMEditor::RemoveAttributeAction FINAL : public InspectorHistory::Action {
    WTF_MAKE_NONCOPYABLE(RemoveAttributeAction);
public:
    RemoveAttributeAction(Element* element, const AtomicString& name)
        : InspectorHistory::Action("RemoveAttribute")
        , m_element(element)
        , m_name(name)
    {
    }

    virtual bool perform(ExceptionState& exceptionState) OVERRIDE
    {
        m_value = m_element->getAttribute(m_name);
        return redo(exceptionState);
    }

    virtual bool undo(ExceptionState& exceptionState) OVERRIDE
    {
        m_element->setAttribute(m_name, m_value, exceptionState);
        return true;
    }

    virtual bool redo(ExceptionState&) OVERRIDE
    {
        m_element->removeAttribute(m_name);
        return true;
    }

private:
    RefPtr<Element> m_element;
    AtomicString m_name;
    AtomicString m_value;
};

class DOMEditor::SetAttributeAction FINAL : public InspectorHistory::Action {
    WTF_MAKE_NONCOPYABLE(SetAttributeAction);
public:
    SetAttributeAction(Element* element, const AtomicString& name, const AtomicString& value)
        : InspectorHistory::Action("SetAttribute")
        , m_element(element)
        , m_name(name)
        , m_value(value)
        , m_hadAttribute(false)
    {
    }

    virtual bool perform(ExceptionState& exceptionState) OVERRIDE
    {
        const AtomicString& value = m_element->getAttribute(m_name);
        m_hadAttribute = !value.isNull();
        if (m_hadAttribute)
            m_oldValue = value;
        return redo(exceptionState);
    }

    virtual bool undo(ExceptionState& exceptionState) OVERRIDE
    {
        if (m_hadAttribute)
            m_element->setAttribute(m_name, m_oldValue, exceptionState);
        else
            m_element->removeAttribute(m_name);
        return true;
    }

    virtual bool redo(ExceptionState& exceptionState) OVERRIDE
    {
        m_element->setAttribute(m_name, m_value, exceptionState);
        return true;
    }

private:
    RefPtr<Element> m_element;
    AtomicString m_name;
    AtomicString m_value;
    bool m_hadAttribute;
    AtomicString m_oldValue;
};

class DOMEditor::SetOuterHTMLAction FINAL : public InspectorHistory::Action {
    WTF_MAKE_NONCOPYABLE(SetOuterHTMLAction);
public:
    SetOuterHTMLAction(Node* node, const String& html)
        : InspectorHistory::Action("SetOuterHTML")
        , m_node(node)
        , m_nextSibling(node->nextSibling())
        , m_html(html)
        , m_newNode(0)
        , m_history(adoptPtr(new InspectorHistory()))
        , m_domEditor(adoptPtr(new DOMEditor(m_history.get())))
    {
    }

    virtual bool perform(ExceptionState& exceptionState) OVERRIDE
    {
        m_oldHTML = createMarkup(m_node.get());
        ASSERT(m_node->ownerDocument());
        DOMPatchSupport domPatchSupport(m_domEditor.get(), *m_node->ownerDocument());
        m_newNode = domPatchSupport.patchNode(m_node.get(), m_html, exceptionState);
        return !exceptionState.hadException();
    }

    virtual bool undo(ExceptionState& exceptionState) OVERRIDE
    {
        return m_history->undo(exceptionState);
    }

    virtual bool redo(ExceptionState& exceptionState) OVERRIDE
    {
        return m_history->redo(exceptionState);
    }

    Node* newNode()
    {
        return m_newNode;
    }

private:
    RefPtr<Node> m_node;
    RefPtr<Node> m_nextSibling;
    String m_html;
    String m_oldHTML;
    Node* m_newNode;
    OwnPtr<InspectorHistory> m_history;
    OwnPtr<DOMEditor> m_domEditor;
};

class DOMEditor::ReplaceWholeTextAction FINAL : public InspectorHistory::Action {
    WTF_MAKE_NONCOPYABLE(ReplaceWholeTextAction);
public:
    ReplaceWholeTextAction(Text* textNode, const String& text)
        : InspectorHistory::Action("ReplaceWholeText")
        , m_textNode(textNode)
        , m_text(text)
    {
    }

    virtual bool perform(ExceptionState& exceptionState) OVERRIDE
    {
        m_oldText = m_textNode->wholeText();
        return redo(exceptionState);
    }

    virtual bool undo(ExceptionState&) OVERRIDE
    {
        m_textNode->replaceWholeText(m_oldText);
        return true;
    }

    virtual bool redo(ExceptionState&) OVERRIDE
    {
        m_textNode->replaceWholeText(m_text);
        return true;
    }

private:
    RefPtr<Text> m_textNode;
    String m_text;
    String m_oldText;
};

class DOMEditor::ReplaceChildNodeAction FINAL : public InspectorHistory::Action {
    WTF_MAKE_NONCOPYABLE(ReplaceChildNodeAction);
public:
    ReplaceChildNodeAction(Node* parentNode, PassRefPtr<Node> newNode, Node* oldNode)
        : InspectorHistory::Action("ReplaceChildNode")
        , m_parentNode(parentNode)
        , m_newNode(newNode)
        , m_oldNode(oldNode)
    {
    }

    virtual bool perform(ExceptionState& exceptionState) OVERRIDE
    {
        return redo(exceptionState);
    }

    virtual bool undo(ExceptionState& exceptionState) OVERRIDE
    {
        m_parentNode->replaceChild(m_oldNode, m_newNode.get(), exceptionState);
        return !exceptionState.hadException();
    }

    virtual bool redo(ExceptionState& exceptionState) OVERRIDE
    {
        m_parentNode->replaceChild(m_newNode, m_oldNode.get(), exceptionState);
        return !exceptionState.hadException();
    }

private:
    RefPtr<Node> m_parentNode;
    RefPtr<Node> m_newNode;
    RefPtr<Node> m_oldNode;
};

class DOMEditor::SetNodeValueAction FINAL : public InspectorHistory::Action {
    WTF_MAKE_NONCOPYABLE(SetNodeValueAction);
public:
    SetNodeValueAction(Node* node, const String& value)
        : InspectorHistory::Action("SetNodeValue")
        , m_node(node)
        , m_value(value)
    {
    }

    virtual bool perform(ExceptionState&) OVERRIDE
    {
        m_oldValue = m_node->nodeValue();
        return redo(IGNORE_EXCEPTION);
    }

    virtual bool undo(ExceptionState&) OVERRIDE
    {
        m_node->setNodeValue(m_oldValue);
        return true;
    }

    virtual bool redo(ExceptionState&) OVERRIDE
    {
        m_node->setNodeValue(m_value);
        return true;
    }

private:
    RefPtr<Node> m_node;
    String m_value;
    String m_oldValue;
};

DOMEditor::DOMEditor(InspectorHistory* history) : m_history(history) { }

DOMEditor::~DOMEditor() { }

bool DOMEditor::insertBefore(Node* parentNode, PassRefPtr<Node> node, Node* anchorNode, ExceptionState& exceptionState)
{
    return m_history->perform(adoptRef(new InsertBeforeAction(parentNode, node, anchorNode)), exceptionState);
}

bool DOMEditor::removeChild(Node* parentNode, Node* node, ExceptionState& exceptionState)
{
    return m_history->perform(adoptRef(new RemoveChildAction(parentNode, node)), exceptionState);
}

bool DOMEditor::setAttribute(Element* element, const String& name, const String& value, ExceptionState& exceptionState)
{
    return m_history->perform(adoptRef(new SetAttributeAction(element, AtomicString(name), AtomicString(value))), exceptionState);
}

bool DOMEditor::removeAttribute(Element* element, const String& name, ExceptionState& exceptionState)
{
    return m_history->perform(adoptRef(new RemoveAttributeAction(element, AtomicString(name))), exceptionState);
}

bool DOMEditor::setOuterHTML(Node* node, const String& html, Node** newNode, ExceptionState& exceptionState)
{
    RefPtr<SetOuterHTMLAction> action = adoptRef(new SetOuterHTMLAction(node, html));
    bool result = m_history->perform(action, exceptionState);
    if (result)
        *newNode = action->newNode();
    return result;
}

bool DOMEditor::replaceWholeText(Text* textNode, const String& text, ExceptionState& exceptionState)
{
    return m_history->perform(adoptRef(new ReplaceWholeTextAction(textNode, text)), exceptionState);
}

bool DOMEditor::replaceChild(Node* parentNode, PassRefPtr<Node> newNode, Node* oldNode, ExceptionState& exceptionState)
{
    return m_history->perform(adoptRef(new ReplaceChildNodeAction(parentNode, newNode, oldNode)), exceptionState);
}

bool DOMEditor::setNodeValue(Node* node, const String& value, ExceptionState& exceptionState)
{
    return m_history->perform(adoptRef(new SetNodeValueAction(node, value)), exceptionState);
}

static void populateErrorString(ExceptionState& exceptionState, ErrorString* errorString)
{
    if (exceptionState.hadException())
        *errorString = DOMException::getErrorName(exceptionState.code());
}

bool DOMEditor::insertBefore(Node* parentNode, PassRefPtr<Node> node, Node* anchorNode, ErrorString* errorString)
{
    TrackExceptionState exceptionState;
    bool result = insertBefore(parentNode, node, anchorNode, exceptionState);
    populateErrorString(exceptionState, errorString);
    return result;
}

bool DOMEditor::removeChild(Node* parentNode, Node* node, ErrorString* errorString)
{
    TrackExceptionState exceptionState;
    bool result = removeChild(parentNode, node, exceptionState);
    populateErrorString(exceptionState, errorString);
    return result;
}

bool DOMEditor::setAttribute(Element* element, const String& name, const String& value, ErrorString* errorString)
{
    TrackExceptionState exceptionState;
    bool result = setAttribute(element, name, value, exceptionState);
    populateErrorString(exceptionState, errorString);
    return result;
}

bool DOMEditor::removeAttribute(Element* element, const String& name, ErrorString* errorString)
{
    TrackExceptionState exceptionState;
    bool result = removeAttribute(element, name, exceptionState);
    populateErrorString(exceptionState, errorString);
    return result;
}

bool DOMEditor::setOuterHTML(Node* node, const String& html, Node** newNode, ErrorString* errorString)
{
    TrackExceptionState exceptionState;
    bool result = setOuterHTML(node, html, newNode, exceptionState);
    populateErrorString(exceptionState, errorString);
    return result;
}

bool DOMEditor::replaceWholeText(Text* textNode, const String& text, ErrorString* errorString)
{
    TrackExceptionState exceptionState;
    bool result = replaceWholeText(textNode, text, exceptionState);
    populateErrorString(exceptionState, errorString);
    return result;
}

} // namespace WebCore


/* [<][>][^][v][top][bottom][index][help] */