Diff
Modified: trunk/LayoutTests/ChangeLog (126391 => 126392)
--- trunk/LayoutTests/ChangeLog 2012-08-23 05:54:42 UTC (rev 126391)
+++ trunk/LayoutTests/ChangeLog 2012-08-23 05:58:10 UTC (rev 126392)
@@ -1,3 +1,13 @@
+2012-08-22 Sukolsak Sakshuwong <[email protected]>
+
+ Implement UndoManager's item() method
+ https://bugs.webkit.org/show_bug.cgi?id=94671
+
+ Reviewed by Ryosuke Niwa.
+
+ * editing/undomanager/undomanager-item-expected.txt: Added.
+ * editing/undomanager/undomanager-item.html: Added.
+
2012-08-22 Dominic Mazzoni <[email protected]>
AX: Focusable elements without a role should not be ignored
Added: trunk/LayoutTests/editing/undomanager/undomanager-item-expected.txt (0 => 126392)
--- trunk/LayoutTests/editing/undomanager/undomanager-item-expected.txt (rev 0)
+++ trunk/LayoutTests/editing/undomanager/undomanager-item-expected.txt 2012-08-23 05:58:10 UTC (rev 126392)
@@ -0,0 +1,11 @@
+This tests UndoManager's item() method.
+
+PASS undoManager has item property.
+PASS After two transact calls that are merged into one, item(0) returns an array of the two transactions in the correct order.
+PASS item(1) returns null because it's out of range.
+PASS After an undo call, item(0) stills return an array of the two transactions in the correct order.
+PASS After a redo call, undoManager's position is back to 0.
+PASS After executing an editing command, item(0) returns an array of an object with label property.
+PASS item(1) now returns an array of the two transactions.
+PASS item(1) returns a different object than item(1).
+
Added: trunk/LayoutTests/editing/undomanager/undomanager-item.html (0 => 126392)
--- trunk/LayoutTests/editing/undomanager/undomanager-item.html (rev 0)
+++ trunk/LayoutTests/editing/undomanager/undomanager-item.html 2012-08-23 05:58:10 UTC (rev 126392)
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>undoManager.item()</title>
+<script src=""
+<script src=""
+</head>
+<body>
+This tests UndoManager's item() method.
+
+<div id="edit" contentEditable>Hello</div>
+
+<script>
+var undoManager = document.undoManager;
+
+test(function() {
+ assert_idl_attribute(undoManager, "item");
+}, "undoManager has item property.");
+
+var transaction = {"executeAutomatic": function() { }};
+var transaction2 = {"executeAutomatic": function() { }};
+
+test(function() {
+ undoManager.transact(transaction);
+ undoManager.transact(transaction2, true);
+
+ var entry = undoManager.item(0);
+ assert_equals(entry.length, 2);
+ assert_equals(entry[0], transaction);
+ assert_equals(entry[1], transaction2);
+}, "After two transact calls that are merged into one, item(0) returns an array of "
+ + "the two transactions in the correct order.");
+
+test(function() {
+ var entry = undoManager.item(1);
+ assert_equals(entry, null);
+}, "item(1) returns null because it's out of range.");
+
+test(function() {
+ undoManager.undo();
+
+ var entry = undoManager.item(0);
+ assert_equals(entry.length, 2);
+ assert_equals(entry[0], transaction);
+ assert_equals(entry[1], transaction2);
+}, "After an undo call, item(0) stills return an array of the two transactions in the correct order.");
+
+test(function() {
+ undoManager.redo();
+ assert_equals(undoManager.position, 0);
+}, "After a redo call, undoManager's position is back to 0.");
+
+test(function() {
+ var range = document.createRange();
+ range.selectNodeContents(document.getElementById("edit"));
+ window.getSelection().addRange(range);
+ document.execCommand("Bold");
+
+ var entry = undoManager.item(0);
+ assert_equals(entry.length, 1);
+ assert_own_property(entry[0], "label");
+}, "After executing an editing command, item(0) returns an array of an object with label property.");
+
+test(function() {
+ var entry = undoManager.item(1);
+ assert_equals(entry.length, 2);
+ assert_equals(entry[0], transaction);
+ assert_equals(entry[1], transaction2);
+}, "item(1) now returns an array of the two transactions.");
+
+test(function() {
+ assert_not_equals(undoManager.item(1), undoManager.item(1));
+}, "item(1) returns a different object than item(1).");
+
+document.getElementById("edit").style.display = "none";
+</script>
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (126391 => 126392)
--- trunk/Source/WebCore/ChangeLog 2012-08-23 05:54:42 UTC (rev 126391)
+++ trunk/Source/WebCore/ChangeLog 2012-08-23 05:58:10 UTC (rev 126392)
@@ -1,3 +1,37 @@
+2012-08-22 Sukolsak Sakshuwong <[email protected]>
+
+ Implement UndoManager's item() method
+ https://bugs.webkit.org/show_bug.cgi?id=94671
+
+ Reviewed by Ryosuke Niwa.
+
+ This patch implements UndoManager's item() method and its V8 custom binding.
+ We need to use custom binding here because we need to return user objects
+ that are stored in a hidden property of DOMTransaction wrappers, not returning
+ the wrappers themselves.
+
+ Test: editing/undomanager/undomanager-item.html
+
+ * bindings/js/JSUndoManagerCustom.cpp:
+ (WebCore::JSUndoManager::item):
+ (WebCore):
+ * bindings/v8/DOMTransaction.cpp:
+ (WebCore::DOMTransaction::data):
+ (WebCore):
+ (WebCore::DOMTransaction::setData):
+ (WebCore::DOMTransaction::getFunction):
+ * bindings/v8/DOMTransaction.h:
+ * bindings/v8/custom/V8UndoManagerCustom.cpp:
+ (WebCore::V8UndoManager::transactCallback):
+ (WebCore::V8UndoManager::itemCallback):
+ (WebCore):
+ * editing/UndoManager.cpp:
+ (WebCore::UndoManager::item):
+ (WebCore):
+ * editing/UndoManager.h:
+ (UndoManager):
+ * editing/UndoManager.idl:
+
2012-08-22 Dominic Mazzoni <[email protected]>
AX: Focusable elements without a role should not be ignored
Modified: trunk/Source/WebCore/bindings/js/JSUndoManagerCustom.cpp (126391 => 126392)
--- trunk/Source/WebCore/bindings/js/JSUndoManagerCustom.cpp 2012-08-23 05:54:42 UTC (rev 126391)
+++ trunk/Source/WebCore/bindings/js/JSUndoManagerCustom.cpp 2012-08-23 05:58:10 UTC (rev 126392)
@@ -38,6 +38,12 @@
return jsUndefined();
}
+JSValue JSUndoManager::item(ExecState*)
+{
+ // FIXME: implement JSC bindings
+ return jsUndefined();
}
+}
+
#endif
Modified: trunk/Source/WebCore/bindings/v8/DOMTransaction.cpp (126391 => 126392)
--- trunk/Source/WebCore/bindings/v8/DOMTransaction.cpp 2012-08-23 05:54:42 UTC (rev 126391)
+++ trunk/Source/WebCore/bindings/v8/DOMTransaction.cpp 2012-08-23 05:58:10 UTC (rev 126392)
@@ -96,17 +96,29 @@
m_undoManager->registerUndoStep(this);
}
-v8::Handle<v8::Function> DOMTransaction::getFunction(const char* propertyName)
+v8::Handle<v8::Value> DOMTransaction::data()
{
v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(toV8(this));
if (wrapper.IsEmpty())
- return v8::Handle<v8::Function>();
+ return v8::Handle<v8::Value>();
+ return wrapper->GetHiddenValue(V8HiddenPropertyName::domTransactionData());
+}
- v8::Local<v8::Value> data = ""
- if (data.IsEmpty() || !data->IsObject())
+void DOMTransaction::setData(v8::Handle<v8::Value> newData)
+{
+ v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(toV8(this));
+ if (wrapper.IsEmpty())
+ return;
+ wrapper->SetHiddenValue(V8HiddenPropertyName::domTransactionData(), newData);
+}
+
+v8::Handle<v8::Function> DOMTransaction::getFunction(const char* propertyName)
+{
+ v8::Handle<v8::Value> dictionary = data();
+ if (dictionary.IsEmpty() || !dictionary->IsObject())
return v8::Handle<v8::Function>();
-
- v8::Local<v8::Value> function = v8::Local<v8::Object>::Cast(data)->Get(v8::String::NewSymbol(propertyName));
+
+ v8::Local<v8::Value> function = v8::Handle<v8::Object>::Cast(dictionary)->Get(v8::String::NewSymbol(propertyName));
if (function.IsEmpty() || !function->IsFunction())
return v8::Handle<v8::Function>();
Modified: trunk/Source/WebCore/bindings/v8/DOMTransaction.h (126391 => 126392)
--- trunk/Source/WebCore/bindings/v8/DOMTransaction.h 2012-08-23 05:54:42 UTC (rev 126391)
+++ trunk/Source/WebCore/bindings/v8/DOMTransaction.h 2012-08-23 05:58:10 UTC (rev 126392)
@@ -47,6 +47,9 @@
virtual EditAction editingAction() const OVERRIDE { return EditActionUnspecified; }
virtual bool isDOMTransaction() const OVERRIDE { return true; }
+ v8::Handle<v8::Value> data();
+ void setData(v8::Handle<v8::Value>);
+
UndoManager* undoManager() const { return m_undoManager; }
void setUndoManager(UndoManager* undoManager) { m_undoManager = undoManager; }
Modified: trunk/Source/WebCore/bindings/v8/custom/V8UndoManagerCustom.cpp (126391 => 126392)
--- trunk/Source/WebCore/bindings/v8/custom/V8UndoManagerCustom.cpp 2012-08-23 05:54:42 UTC (rev 126391)
+++ trunk/Source/WebCore/bindings/v8/custom/V8UndoManagerCustom.cpp 2012-08-23 05:58:10 UTC (rev 126392)
@@ -31,7 +31,6 @@
#include "DOMTransaction.h"
#include "ExceptionCode.h"
#include "V8DOMTransaction.h"
-#include "V8HiddenPropertyName.h"
namespace WebCore {
@@ -49,10 +48,8 @@
EXCEPTION_BLOCK(bool, merge, MAYBE_MISSING_PARAMETER(args, 1, DefaultIsUndefined)->BooleanValue());
RefPtr<DOMTransaction> transaction = DOMTransaction::create(WorldContextHandle(UseCurrentWorld));
- v8::Handle<v8::Object> transactionWrapper = v8::Handle<v8::Object>::Cast(toV8(transaction.get()));
+ transaction->setData(dictionary);
- transactionWrapper->SetHiddenValue(V8HiddenPropertyName::domTransactionData(), dictionary);
-
ExceptionCode ec = 0;
imp->transact(transaction, merge, ec);
if (ec)
@@ -60,6 +57,37 @@
return v8Undefined();
}
+v8::Handle<v8::Value> V8UndoManager::itemCallback(const v8::Arguments& args)
+{
+ INC_STATS("DOM.UndoManager.item");
+ if (args.Length() < 1)
+ return throwNotEnoughArgumentsError(args.GetIsolate());
+ UndoManager* imp = V8UndoManager::toNative(args.Holder());
+
+ EXCEPTION_BLOCK(unsigned, index, toUInt32(MAYBE_MISSING_PARAMETER(args, 0, DefaultIsUndefined)));
+
+ if (index >= imp->length())
+ return v8::Null(args.GetIsolate());
+
+ const UndoManagerEntry& entry = imp->item(index);
+
+ v8::Handle<v8::Array> result = v8::Array::New(entry.size());
+ v8::Isolate* isolate = args.GetIsolate();
+ for (size_t index = 0; index < entry.size(); ++index) {
+ UndoStep* step = entry[index].get();
+ if (step->isDOMTransaction())
+ result->Set(v8Integer(index, isolate), static_cast<DOMTransaction*>(step)->data());
+ else {
+ // FIXME: We shouldn't be creating new object each time we return.
+ // Object for the same native editing command should always be the same.
+ v8::Handle<v8::Object> object = v8::Object::New();
+ object->Set(v8::String::NewSymbol("label"), v8::String::New("[Editing command]"));
+ result->Set(v8Integer(index, isolate), object);
+ }
+ }
+ return result;
+}
+
} // namespace WebCore
#endif // ENABLE(UNDO_MANAGER)
Modified: trunk/Source/WebCore/editing/UndoManager.cpp (126391 => 126392)
--- trunk/Source/WebCore/editing/UndoManager.cpp 2012-08-23 05:54:42 UTC (rev 126391)
+++ trunk/Source/WebCore/editing/UndoManager.cpp 2012-08-23 05:58:10 UTC (rev 126392)
@@ -160,6 +160,17 @@
m_redoStack.removeLast();
}
+UndoManagerEntry UndoManager::item(unsigned index) const
+{
+ ASSERT(index < length());
+ if (index < m_redoStack.size()) {
+ UndoManagerEntry entry = *m_redoStack[index];
+ entry.reverse();
+ return entry;
+ }
+ return *m_undoStack[length() - index - 1];
+}
+
void UndoManager::registerUndoStep(PassRefPtr<UndoStep> step)
{
if (!m_isInProgress) {
Modified: trunk/Source/WebCore/editing/UndoManager.h (126391 => 126392)
--- trunk/Source/WebCore/editing/UndoManager.h 2012-08-23 05:54:42 UTC (rev 126391)
+++ trunk/Source/WebCore/editing/UndoManager.h 2012-08-23 05:58:10 UTC (rev 126392)
@@ -62,6 +62,8 @@
void undo(ExceptionCode& = ASSERT_NO_EXCEPTION);
void redo(ExceptionCode& = ASSERT_NO_EXCEPTION);
+ UndoManagerEntry item(unsigned index) const;
+
unsigned length() const { return m_undoStack.size() + m_redoStack.size(); }
unsigned position() const { return m_redoStack.size(); }
Modified: trunk/Source/WebCore/editing/UndoManager.idl (126391 => 126392)
--- trunk/Source/WebCore/editing/UndoManager.idl 2012-08-23 05:54:42 UTC (rev 126391)
+++ trunk/Source/WebCore/editing/UndoManager.idl 2012-08-23 05:58:10 UTC (rev 126392)
@@ -41,6 +41,8 @@
void redo()
raises(DOMException);
+ [Custom] sequence<DOMTransaction> item(in unsigned long index);
+
readonly attribute unsigned long length;
readonly attribute unsigned long position;