Upstream version 11.39.264.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / extension / application_widget_extension.cc
index af28a65..fb94b01 100644 (file)
@@ -4,10 +4,15 @@
 
 #include "xwalk/application/extension/application_widget_extension.h"
 
+#include <vector>
+
 #include "base/bind.h"
 #include "base/path_service.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 using content::BrowserThread;
 
 namespace {
+
 const char kCommandKey[] = "cmd";
 const char kWidgetAttributeKey[] = "widgetKey";
 const char kPreferencesItemKey[] = "preferencesItemKey";
 const char kPreferencesItemValue[] = "preferencesItemValue";
+
+void DispatchStorageEvent(
+    base::DictionaryValue* msg,
+    content::WebContents* web_contents,
+    content::RenderFrameHost* frame) {
+  if (frame == web_contents->GetFocusedFrame())
+    return;
+
+  std::string key, oldValue, newValue;
+  msg->GetString("key", &key);
+  msg->GetString("oldValue", &oldValue);
+  msg->GetString("newValue", &newValue);
+
+  std::string code = base::StringPrintf(
+      "(function() {"
+      "  var old_value = '%s' == '' ? null : '%s';"
+      "  var new_value = '%s' == '' ? null : '%s';"
+      "  var event = {"
+      "    key: '%s',"
+      "    oldValue: old_value,"
+      "    newValue: new_value,"
+      "    url: window.location.href,"
+      "    storageArea: widget.preferences"
+      "  };"
+      "  for (var key in event) {"
+      "    Object.defineProperty(event, key, {"
+      "      value: event[key],"
+      "      writable: false"
+      "    });"
+      "  }"
+      "  for (var i = 0; i < window.eventListenerList.length; i++)"
+      "    window.eventListenerList[i](event);"
+      "})();", oldValue.c_str(), oldValue.c_str(),
+      newValue.c_str(), newValue.c_str(), key.c_str());
+
+  frame->ExecuteJavaScript(base::UTF8ToUTF16(code));
 }
 
+}  // namespace
+
 namespace xwalk {
 namespace application {
 
@@ -52,8 +96,7 @@ XWalkExtensionInstance* ApplicationWidgetExtension::CreateInstance() {
 
 AppWidgetExtensionInstance::AppWidgetExtensionInstance(
     Application* application)
-  : application_(application),
-    handler_(this) {
+  : application_(application) {
   DCHECK(application_);
   base::ThreadRestrictions::SetIOAllowed(true);
 
@@ -68,7 +111,6 @@ AppWidgetExtensionInstance::AppWidgetExtensionInstance(
 AppWidgetExtensionInstance::~AppWidgetExtensionInstance() {}
 
 void AppWidgetExtensionInstance::HandleMessage(scoped_ptr<base::Value> msg) {
-  handler_.HandleMessage(msg.Pass());
 }
 
 void AppWidgetExtensionInstance::HandleSyncMessage(
@@ -94,6 +136,8 @@ void AppWidgetExtensionInstance::HandleSyncMessage(
     result = ClearAllItems(msg.Pass());
   } else if (command == "GetAllItems") {
     result = GetAllItems(msg.Pass());
+  } else if (command == "GetItemValueByKey") {
+    result = GetItemValueByKey(msg.Pass());
   } else if (command == "KeyExists") {
     result = KeyExists(msg.Pass());
   } else {
@@ -140,9 +184,26 @@ AppWidgetExtensionInstance::SetPreferencesItem(scoped_ptr<base::Value> msg) {
     return result.Pass();
   }
 
-  if (widget_storage_->AddEntry(key, value, false))
+  std::string old_value;
+  if (!widget_storage_->GetValueByKey(key, &old_value)) {
+    old_value = "";
+  }
+  if (old_value == value) {
+    LOG(WARNING) << "You are trying to set the same value."
+                 << " Nothing will be done.";
+    result.reset(new base::FundamentalValue(true));
+    return result.Pass();
+  }
+  if (widget_storage_->AddEntry(key, value, false)) {
     result.reset(new base::FundamentalValue(true));
 
+    scoped_ptr<base::DictionaryValue> event(new base::DictionaryValue());
+    event->SetString("key", key);
+    event->SetString("oldValue", old_value);
+    event->SetString("newValue", value);
+    PostMessageToOtherFrames(event.Pass());
+  }
+
   return result.Pass();
 }
 
@@ -159,8 +220,23 @@ AppWidgetExtensionInstance::RemovePreferencesItem(scoped_ptr<base::Value> msg) {
     return result.Pass();
   }
 
-  if (widget_storage_->RemoveEntry(key))
+  std::string old_value;
+  if (!widget_storage_->GetValueByKey(key, &old_value)) {
+    LOG(WARNING) << "You are trying to remove an entry which doesn't exist."
+                 << " Nothing will be done.";
     result.reset(new base::FundamentalValue(true));
+    return result.Pass();
+  }
+
+  if (widget_storage_->RemoveEntry(key)) {
+    result.reset(new base::FundamentalValue(true));
+
+    scoped_ptr<base::DictionaryValue> event(new base::DictionaryValue());
+    event->SetString("key", key);
+    event->SetString("oldValue", old_value);
+    event->SetString("newValue", "");
+    PostMessageToOtherFrames(event.Pass());
+  }
 
   return result.Pass();
 }
@@ -170,9 +246,27 @@ scoped_ptr<base::FundamentalValue> AppWidgetExtensionInstance::ClearAllItems(
   scoped_ptr<base::FundamentalValue> result(
       new base::FundamentalValue(false));
 
-  if (widget_storage_->Clear())
-    result.reset(new base::FundamentalValue(true));
+  scoped_ptr<base::DictionaryValue> entries(new base::DictionaryValue());
+  widget_storage_->GetAllEntries(entries.get());
 
+  if (!widget_storage_->Clear())
+    return result.Pass();
+
+  for (base::DictionaryValue::Iterator it(*(entries.get()));
+      !it.IsAtEnd(); it.Advance()) {
+    std::string key = it.key();
+    if (!widget_storage_->EntryExists(key)) {
+      std::string old_value;
+      it.value().GetAsString(&old_value);
+      scoped_ptr<base::DictionaryValue> event(new base::DictionaryValue());
+      event->SetString("key", key);
+      event->SetString("oldValue", old_value);
+      event->SetString("newValue", "");
+      PostMessageToOtherFrames(event.Pass());
+    }
+  }
+
+  result.reset(new base::FundamentalValue(true));
   return result.Pass();
 }
 
@@ -184,6 +278,20 @@ scoped_ptr<base::DictionaryValue> AppWidgetExtensionInstance::GetAllItems(
   return result.Pass();
 }
 
+scoped_ptr<base::StringValue> AppWidgetExtensionInstance::GetItemValueByKey(
+    scoped_ptr<base::Value> msg) {
+  base::DictionaryValue* dict;
+  msg->GetAsDictionary(&dict);
+
+  std::string key;
+  std::string value;
+  if (!dict->GetString(kPreferencesItemKey, &key) ||
+      !widget_storage_->GetValueByKey(key, &value))
+    value = "";
+  scoped_ptr<base::StringValue> result(new base::StringValue(value));
+  return result.Pass();
+}
+
 scoped_ptr<base::FundamentalValue> AppWidgetExtensionInstance::KeyExists(
     scoped_ptr<base::Value> msg) const {
   scoped_ptr<base::FundamentalValue> result(
@@ -203,5 +311,17 @@ scoped_ptr<base::FundamentalValue> AppWidgetExtensionInstance::KeyExists(
   return result.Pass();
 }
 
+void AppWidgetExtensionInstance::PostMessageToOtherFrames(
+    scoped_ptr<base::DictionaryValue> msg) {
+  const std::vector<Runtime*>& runtime_set = application_->runtimes();
+  std::vector<Runtime*>::const_iterator it;
+  for (it = runtime_set.begin(); it != runtime_set.end(); ++it) {
+    content::WebContents* web_contents = (*it)->web_contents();
+    web_contents->ForEachFrame(base::Bind(&DispatchStorageEvent,
+                                          msg.get(),
+                                          web_contents));
+  }
+}
+
 }  // namespace application
 }  // namespace xwalk