Implement UndoManager's item() method
[WebKit-https.git] / Source / WebCore / bindings / v8 / DOMTransaction.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
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26 #include "DOMTransaction.h"
27
28 #if ENABLE(UNDO_MANAGER)
29
30 #include "Frame.h"
31 #include "UndoManager.h"
32 #include "V8DOMTransaction.h"
33 #include "V8HiddenPropertyName.h"
34 #include "V8UndoManager.h"
35
36 namespace WebCore {
37
38 class DOMTransactionScope {
39 public:
40     DOMTransactionScope(DOMTransaction* transaction)
41     {
42         UndoManager::setRecordingDOMTransaction(transaction);
43     }
44     
45     ~DOMTransactionScope()
46     {
47         UndoManager::setRecordingDOMTransaction(0);
48     }
49 };
50
51 DOMTransaction::DOMTransaction(const WorldContextHandle& worldContext)
52     : m_worldContext(worldContext)
53     , m_undoManager(0)
54 {
55 }
56
57 PassRefPtr<DOMTransaction> DOMTransaction::create(const WorldContextHandle& worldContext)
58 {
59     return adoptRef(new DOMTransaction(worldContext));
60 }
61
62 void DOMTransaction::apply()
63 {
64     m_isAutomatic = !getFunction("executeAutomatic").IsEmpty();
65     if (!m_isAutomatic)
66         callFunction("execute");
67     else {
68         DOMTransactionScope scope(this);
69         callFunction("executeAutomatic");
70     }
71 }
72
73 void DOMTransaction::unapply()
74 {
75     if (!m_isAutomatic)
76         callFunction("undo");
77     else {
78         for (size_t i = m_transactionSteps.size(); i > 0; --i)
79             m_transactionSteps[i - 1]->unapply();
80     }
81
82     if (m_undoManager)
83         m_undoManager->registerRedoStep(this);
84 }
85
86 void DOMTransaction::reapply()
87 {
88     if (!m_isAutomatic)
89         callFunction("redo");
90     else {
91         for (size_t i = 0; i < m_transactionSteps.size(); ++i)
92             m_transactionSteps[i]->reapply();
93     }
94
95     if (m_undoManager)
96         m_undoManager->registerUndoStep(this);
97 }
98
99 v8::Handle<v8::Value> DOMTransaction::data()
100 {
101     v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(toV8(this));
102     if (wrapper.IsEmpty())
103         return v8::Handle<v8::Value>();
104     return wrapper->GetHiddenValue(V8HiddenPropertyName::domTransactionData());
105 }
106
107 void DOMTransaction::setData(v8::Handle<v8::Value> newData)
108 {
109     v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(toV8(this));
110     if (wrapper.IsEmpty())
111         return;
112     wrapper->SetHiddenValue(V8HiddenPropertyName::domTransactionData(), newData);
113 }
114
115 v8::Handle<v8::Function> DOMTransaction::getFunction(const char* propertyName)
116 {
117     v8::Handle<v8::Value> dictionary = data();
118     if (dictionary.IsEmpty() || !dictionary->IsObject())
119         return v8::Handle<v8::Function>();
120     
121     v8::Local<v8::Value> function = v8::Handle<v8::Object>::Cast(dictionary)->Get(v8::String::NewSymbol(propertyName));
122     if (function.IsEmpty() || !function->IsFunction())
123         return v8::Handle<v8::Function>();
124
125     return v8::Handle<v8::Function>::Cast(function);
126 }
127
128 void DOMTransaction::callFunction(const char* propertyName)
129 {
130     if (!m_undoManager || !m_undoManager->document())
131         return;
132
133     Frame* frame = m_undoManager->document()->frame();
134     if (!frame || !frame->script()->canExecuteScripts(AboutToExecuteScript))
135         return;
136
137     v8::Handle<v8::Function> function = getFunction(propertyName);
138     if (function.IsEmpty())
139         return;
140
141     v8::Local<v8::Context> v8Context = m_worldContext.adjustedContext(frame->script());
142     if (v8Context.IsEmpty())
143         return;
144
145     v8::Handle<v8::Object> receiver = v8::Handle<v8::Object>::Cast(toV8(m_undoManager));
146     if (receiver.IsEmpty())
147         return;
148     v8::Handle<v8::Value> parameters[0] = { };
149     frame->script()->callFunction(function, receiver, 0, parameters);
150 }
151
152 }
153
154 #endif