summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/browser_resources.grd1
-rw-r--r--chrome/browser/resources/collected_cookies.css16
-rw-r--r--chrome/browser/resources/collected_cookies.html35
-rw-r--r--chrome/browser/resources/collected_cookies.js79
-rw-r--r--chrome/browser/resources/cookies_tree.js224
-rw-r--r--chrome/browser/ui/gtk/constrained_html_delegate_gtk.cc2
-rw-r--r--chrome/browser/ui/gtk/constrained_window_gtk.cc13
-rw-r--r--chrome/browser/ui/gtk/constrained_window_gtk.h3
-rw-r--r--chrome/browser/ui/views/constrained_html_delegate_gtk.cc3
-rw-r--r--chrome/browser/ui/views/dialog_stubs_gtk.cc5
-rw-r--r--chrome/browser/ui/webui/collected_cookies_ui_delegate.cc288
-rw-r--r--chrome/browser/ui/webui/collected_cookies_ui_delegate.h89
-rw-r--r--chrome/browser/ui/webui/cookies_tree_model_adapter.cc135
-rw-r--r--chrome/browser/ui/webui/cookies_tree_model_adapter.h71
-rw-r--r--chrome/chrome_browser.gypi8
-rw-r--r--chrome/common/url_constants.cc2
-rw-r--r--chrome/common/url_constants.h2
-rw-r--r--content/browser/webui/web_ui_factory.cc4
18 files changed, 975 insertions, 5 deletions
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 5850728..a1f4e6d 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -84,6 +84,7 @@ without changes to the corresponding grd file. etaa -->
<include name="IDR_WEBSTORE_MANIFEST" file="resources\webstore_app\manifest.json" type="BINDATA" />
<if expr="pp_ifdef('chromeos')">
<include name="IDR_ABOUT_SYS_HTML" file="resources\about_sys.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_COLLECTED_COOKIES_HTML" file="resources\collected_cookies.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_GUEST_SESSION_TAB_HTML" file="resources\guest_session_tab.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_FILEBROWSE_HTML" file="resources\filebrowse.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_HOST_REGISTRATION_PAGE_HTML" file="resources\host_registration_page.html" flattenhtml="true" type="BINDATA" />
diff --git a/chrome/browser/resources/collected_cookies.css b/chrome/browser/resources/collected_cookies.css
new file mode 100644
index 0000000..18217b9
--- /dev/null
+++ b/chrome/browser/resources/collected_cookies.css
@@ -0,0 +1,16 @@
+body {
+ font-size: 84%;
+ font-family: Arial, Helvetica, sans-serif;
+}
+
+.cookies-tree {
+ border: 1px solid lightgrey;
+ padding: 5px;
+ width: 450px;
+ height: 135px;
+}
+
+#info-banner {
+ background: -webkit-linear-gradient(#fff2b7, #fae691 97%, #878787);
+ padding: 2px 0;
+}
diff --git a/chrome/browser/resources/collected_cookies.html b/chrome/browser/resources/collected_cookies.html
new file mode 100644
index 0000000..293e11f
--- /dev/null
+++ b/chrome/browser/resources/collected_cookies.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html i18n-values="dir:textdirection;">
+
+<head>
+<meta charset="utf-8">
+<title i18n-content="title"></title>
+<link rel="stylesheet" href="chrome://resources/css/tree.css">
+<link rel="stylesheet" href="collected_cookies.css">
+</head>
+
+<script src="chrome://resources/css/tree.css.js"></script>
+
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/ui.js"></script>
+<script src="chrome://resources/js/cr/ui/tree.js"></script>
+<script src="chrome://resources/js/util.js"></script>
+<script src="cookies_tree.js"></script>
+<script src="collected_cookies.js"></script>
+
+<body>
+
+<div id="info-banner" hidden></div>
+
+<p i18n-content="allowedCookies"></p>
+<tree id="allowed-cookies" class="cookies-tree"></tree>
+<button id="block-button" i18n-content="blockButton"></button>
+
+<p i18n-content="blockedCookies"></p>
+<tree id="blocked-cookies" class="cookies-tree"></tree>
+<button id="allow-button" i18n-content="allowButton"></button>
+<button id="allow-this-session-button"
+ i18n-content="allowThisSessionButton"></button>
+<button id="close-button" i18n-content="closeButton"></button>
+</body>
+</html>
diff --git a/chrome/browser/resources/collected_cookies.js b/chrome/browser/resources/collected_cookies.js
new file mode 100644
index 0000000..ca3cbb0
--- /dev/null
+++ b/chrome/browser/resources/collected_cookies.js
@@ -0,0 +1,79 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function closeDialog() {
+ chrome.send('DialogClose', ['']);
+}
+
+function setInfobarLabel(text) {
+ $('info-banner').textContent = text;
+ $('info-banner').hidden = !text.length;
+}
+
+function updateControlState() {
+ var allowedCookies = $('allowed-cookies');
+ $('block-button').disabled = !allowedCookies.children.length ||
+ !allowedCookies.selectedItem ||
+ allowedCookies.selectedItem.data.type != 'origin';
+
+ var blockedCookies = $('blocked-cookies');
+ $('allow-button').disabled =
+ $('allow-this-session-button').disabled = !blockedCookies.children.length ||
+ !blockedCookies.selectedItem ||
+ blockedCookies.selectedItem.data.type != 'origin';
+}
+
+function handleCookiesTreeChange(e) {
+ updateControlState();
+}
+
+function handleBlockButtonClick(e) {
+ var selected = $('allowed-cookies').selectedItem;
+ if (!selected)
+ return;
+
+ chrome.send('Block', [selected.pathId]);
+}
+
+function handleAllowButtonClick(e) {
+ var selected = $('blocked-cookies').selectedItem;
+ if (selected)
+ chrome.send('Allow', [selected.pathId]);
+}
+
+function handleAllowThisSessionButtonClick(e) {
+ var selected = $('blocked-cookies').selectedItem;
+ if (selected)
+ chrome.send('AllowThisSession', [selected.pathId]);
+}
+
+function load() {
+ ui.CookiesTree.decorate($('allowed-cookies'));
+ ui.CookiesTree.decorate($('blocked-cookies'));
+
+ chrome.send('BindCookiesTreeModel', []);
+
+ $('allowed-cookies').addEventListener('change', handleCookiesTreeChange);
+ $('blocked-cookies').addEventListener('change', handleCookiesTreeChange);
+
+ $('block-button').addEventListener('click', handleBlockButtonClick);
+ $('allow-button').addEventListener('click', handleAllowButtonClick);
+ $('allow-this-session-button').addEventListener('click',
+ handleAllowThisSessionButtonClick);
+
+ $('close-button').addEventListener('click', closeDialog);
+
+ document.oncontextmenu = function(e) {
+ e.preventDefault();
+ }
+
+ document.onkeydown = function(e) {
+ if (e.keyCode == 27) // Esc
+ closeDialog();
+ }
+
+ updateControlState();
+}
+
+document.addEventListener('DOMContentLoaded', load);
diff --git a/chrome/browser/resources/cookies_tree.js b/chrome/browser/resources/cookies_tree.js
new file mode 100644
index 0000000..42187de
--- /dev/null
+++ b/chrome/browser/resources/cookies_tree.js
@@ -0,0 +1,224 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('ui', function() {
+ const Tree = cr.ui.Tree;
+ const TreeItem = cr.ui.TreeItem;
+
+ /**
+ * Creates a new tree item for sites data.
+ * @param {Object=} data Data used to create a cookie tree item.
+ * @constructor
+ * @extends {TreeItem}
+ */
+ function CookiesTreeItem(data) {
+ var treeItem = new TreeItem({
+ label: data.title,
+ data: data
+ });
+ treeItem.__proto__ = CookiesTreeItem.prototype;
+
+ if (data.icon)
+ treeItem.icon = data.icon;
+
+ treeItem.decorate();
+ return treeItem;
+ }
+
+ CookiesTreeItem.prototype = {
+ __proto__: TreeItem.prototype,
+
+ /** @inheritDoc */
+ decorate: function() {
+ this.hasChildren = this.data.hasChildren;
+ },
+
+ /** @inheritDoc */
+ addAt: function(child, index) {
+ TreeItem.prototype.addAt.call(this, child, index);
+ if (child.data && child.data.id)
+ this.tree.treeLookup[child.data.id] = child;
+ },
+
+ /** @inheritDoc */
+ remove: function(child) {
+ TreeItem.prototype.remove.call(this, child);
+ if (child.data && child.data.id)
+ delete this.tree.treeLookup[child.data.id];
+ },
+
+ /**
+ * Clears all children.
+ */
+ clear: function() {
+ // We might leave some garbage in treeLookup for removed children.
+ // But that should be okay because treeLookup is cleared when we
+ // reload the tree.
+ this.lastElementChild.textContent = '';
+ },
+
+ /**
+ * The tree path id.
+ * @type {string}
+ */
+ get pathId() {
+ var parent = this.parentItem;
+ if (parent instanceof CookiesTreeItem)
+ return parent.pathId + ',' + this.data.id;
+ else
+ return this.data.id;
+ },
+
+ /** @inheritDoc */
+ get expanded() {
+ return TreeItem.prototype.__lookupGetter__('expanded').call(this);
+ },
+ set expanded(b) {
+ if (b && this.expanded != b)
+ chrome.send(this.tree.requestChildrenMessage, [this.pathId]);
+
+ TreeItem.prototype.__lookupSetter__('expanded').call(this, b);
+ }
+ };
+
+ /**
+ * Creates a new cookies tree.
+ * @param {Object=} opt_propertyBag Optional properties.
+ * @constructor
+ * @extends {Tree}
+ */
+ var CookiesTree = cr.ui.define('tree');
+
+ CookiesTree.prototype = {
+ __proto__: Tree.prototype,
+
+ /**
+ * Per-tree dict to map from data.id to tree node.
+ */
+ treeLookup_: null,
+ get treeLookup() {
+ if (!this.treeLookup_)
+ this.treeLookup_ = {};
+ return this.treeLookup_;
+ },
+
+ /** @inheritDoc */
+ addAt: function(child, index) {
+ Tree.prototype.addAt.call(this, child, index);
+ if (child.data && child.data.id)
+ this.treeLookup[child.data.id] = child;
+ },
+
+ /** @inheritDoc */
+ remove: function(child) {
+ Tree.prototype.remove.call(this, child);
+ if (child.data && child.data.id)
+ delete this.treeLookup[child.data.id];
+ },
+
+ /**
+ * Add tree nodes by given parent.
+ * @param {Object} parent Parent node.
+ * @param {number} start Start index of where to insert nodes.
+ * @param {Array} nodesData Nodes data array.
+ */
+ addByParent: function(parent, start, nodesData) {
+ for (var i = 0; i < nodesData.length; ++i) {
+ parent.addAt(new CookiesTreeItem(nodesData[i]), start + i);
+ }
+
+ cr.dispatchSimpleEvent(this, 'change');
+ },
+
+ /**
+ * Add tree nodes by parent id.
+ * @param {string} parentId Id of the parent node.
+ * @param {int} start Start index of where to insert nodes.
+ * @param {Array} nodesData Nodes data array.
+ */
+ addByParentId: function(parentId, start, nodesData) {
+ var parent = parentId ? this.treeLookup[parentId] : this;
+ this.addByParent(parent, start, nodesData);
+ },
+
+ /**
+ * Removes tree nodes by parent id.
+ * @param {string} parentId Id of the parent node.
+ * @param {int} start Start index of nodes to remove.
+ * @param {int} count Number of nodes to remove.
+ */
+ removeByParentId: function(parentId, start, count) {
+ var parent = parentId ? this.treeLookup[parentId] : this;
+
+ for (; count > 0 && parent.items.length; --count) {
+ parent.remove(parent.items[start]);
+ }
+
+ cr.dispatchSimpleEvent(this, 'change');
+ },
+
+ /**
+ * Clears the tree.
+ */
+ clear: function() {
+ // Remove all fields without recreating the object since other code
+ // references it.
+ for (var id in this.treeLookup){
+ delete this.treeLookup[id];
+ }
+ this.textContent = '';
+ },
+
+ /**
+ * Unique 'requestChildren' callback message name to send request to
+ * underlying CookiesTreeModelAdapter.
+ * @type {string}
+ */
+ requestChildrenMessage_ : null,
+ get requestChildrenMessage() {
+ return this.requestChildrenMessage_;
+ },
+
+ /**
+ * Set callback message name.
+ * @param {string} loadChildren Message name for 'loadChildren' request.
+ */
+ doSetCallback: function(loadChildren) {
+ this.requestChildrenMessage_ = loadChildren;
+ },
+
+ /**
+ * Sets the immediate children of given parent node.
+ * @param {string} parentId Id of the parent node.
+ * @param {Array} children The immediate children of parent node.
+ */
+ doSetChildren: function(parentId, children) {
+ var parent = parentId ? this.treeLookup[parentId] : this;
+
+ parent.clear();
+ this.addByParent(parent, 0, children);
+ }
+ };
+
+ // CookiesTreeModelAdapter callbacks.
+ CookiesTree.setCallback = function(treeId, message) {
+ $(treeId).doSetCallback(message);
+ }
+
+ CookiesTree.onTreeItemAdded = function(treeId, parentId, start, children) {
+ $(treeId).addByParentId(parentId, start, children);
+ }
+
+ CookiesTree.onTreeItemRemoved = function(treeId, parentId, start, count) {
+ $(treeId).removeByParentId(parentId, start, count);
+ }
+
+ CookiesTree.setChildren = function(treeId, parentId, children) {
+ $(treeId).doSetChildren(parentId, children);
+ }
+
+ return {
+ CookiesTree: CookiesTree
+ };
+});
diff --git a/chrome/browser/ui/gtk/constrained_html_delegate_gtk.cc b/chrome/browser/ui/gtk/constrained_html_delegate_gtk.cc
index 26deb64..af42724 100644
--- a/chrome/browser/ui/gtk/constrained_html_delegate_gtk.cc
+++ b/chrome/browser/ui/gtk/constrained_html_delegate_gtk.cc
@@ -19,7 +19,7 @@ class ConstrainedHtmlDelegateGtk : public ConstrainedWindowGtkDelegate,
public ConstrainedHtmlUIDelegate {
public:
ConstrainedHtmlDelegateGtk(Profile* profile,
- HtmlDialogUIDelegate* delegate);
+ HtmlDialogUIDelegate* delegate);
virtual ~ConstrainedHtmlDelegateGtk();
diff --git a/chrome/browser/ui/gtk/constrained_window_gtk.cc b/chrome/browser/ui/gtk/constrained_window_gtk.cc
index 2a454ce..a3650a6 100644
--- a/chrome/browser/ui/gtk/constrained_window_gtk.cc
+++ b/chrome/browser/ui/gtk/constrained_window_gtk.cc
@@ -24,6 +24,10 @@ bool ConstrainedWindowGtkDelegate::GetBackgroundColor(GdkColor* color) {
return false;
}
+bool ConstrainedWindowGtkDelegate::ShouldHaveBorderPadding() const {
+ return true;
+}
+
ConstrainedWindowGtk::ConstrainedWindowGtk(
TabContents* owner, ConstrainedWindowGtkDelegate* delegate)
: owner_(owner),
@@ -41,9 +45,12 @@ ConstrainedWindowGtk::ConstrainedWindowGtk(
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
- gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
- gtk_util::kContentAreaBorder, gtk_util::kContentAreaBorder,
- gtk_util::kContentAreaBorder, gtk_util::kContentAreaBorder);
+ if (delegate->ShouldHaveBorderPadding()) {
+ gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
+ gtk_util::kContentAreaBorder, gtk_util::kContentAreaBorder,
+ gtk_util::kContentAreaBorder, gtk_util::kContentAreaBorder);
+ }
+
GdkColor background;
if (delegate->GetBackgroundColor(&background)) {
gtk_widget_modify_base(ebox, GTK_STATE_NORMAL, &background);
diff --git a/chrome/browser/ui/gtk/constrained_window_gtk.h b/chrome/browser/ui/gtk/constrained_window_gtk.h
index 90cd2ea..51b4cb2 100644
--- a/chrome/browser/ui/gtk/constrained_window_gtk.h
+++ b/chrome/browser/ui/gtk/constrained_window_gtk.h
@@ -36,6 +36,9 @@ class ConstrainedWindowGtkDelegate {
virtual bool GetBackgroundColor(GdkColor* color);
+ // Returns true if hosting ConstrainedWindowGtk should apply default padding.
+ virtual bool ShouldHaveBorderPadding() const;
+
protected:
virtual ~ConstrainedWindowGtkDelegate();
};
diff --git a/chrome/browser/ui/views/constrained_html_delegate_gtk.cc b/chrome/browser/ui/views/constrained_html_delegate_gtk.cc
index 3fdd72c..223f643 100644
--- a/chrome/browser/ui/views/constrained_html_delegate_gtk.cc
+++ b/chrome/browser/ui/views/constrained_html_delegate_gtk.cc
@@ -44,6 +44,9 @@ class ConstrainedHtmlDelegateGtk : public views::WidgetGtk,
html_delegate_->OnDialogClosed("");
tab_container_->ChangeTabContents(NULL);
}
+ virtual bool ShouldHaveBorderPadding() const {
+ return false;
+ }
// HtmlDialogTabContentsDelegate interface.
void MoveContents(TabContents* source, const gfx::Rect& pos) {}
diff --git a/chrome/browser/ui/views/dialog_stubs_gtk.cc b/chrome/browser/ui/views/dialog_stubs_gtk.cc
index b455bf8..b5214ee 100644
--- a/chrome/browser/ui/views/dialog_stubs_gtk.cc
+++ b/chrome/browser/ui/views/dialog_stubs_gtk.cc
@@ -21,6 +21,7 @@
#include "chrome/browser/ui/options/options_window.h"
#include "chrome/browser/ui/views/browser_dialogs.h"
#include "content/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/webui/collected_cookies_ui_delegate.h"
#include "views/widget/widget.h"
namespace browser {
@@ -67,7 +68,11 @@ void ShowContentSettingsWindow(gfx::NativeWindow parent_window,
void ShowCollectedCookiesDialog(gfx::NativeWindow parent_window,
TabContents* tab_contents) {
+#if defined(OS_CHROMEOS)
+ CollectedCookiesUIDelegate::Show(tab_contents);
+#else
new CollectedCookiesGtk(GTK_WINDOW(parent_window), tab_contents);
+#endif
}
} // namespace browser
diff --git a/chrome/browser/ui/webui/collected_cookies_ui_delegate.cc b/chrome/browser/ui/webui/collected_cookies_ui_delegate.cc
new file mode 100644
index 0000000..6909769
--- /dev/null
+++ b/chrome/browser/ui/webui/collected_cookies_ui_delegate.cc
@@ -0,0 +1,288 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/collected_cookies_ui_delegate.h"
+
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "base/values.h"
+#include "chrome/browser/cookies_tree_model.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
+#include "chrome/browser/ui/webui/constrained_html_ui.h"
+#include "chrome/browser/ui/webui/cookies_tree_model_util.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/url_constants.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "content/common/notification_service.h"
+#include "grit/browser_resources.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace {
+
+// TODO(xiyuan): Localize this.
+const int kDialogWidth = 480;
+const int kDialogHeight = 470;
+
+CookieTreeOriginNode* GetOriginNode(CookiesTreeModel* model,
+ const std::string& node_path) {
+ CookieTreeNode* node = cookies_tree_model_util::GetTreeNodeFromPath(
+ model->GetRoot(), node_path);
+
+ while (node && node->GetDetailedInfo().node_type !=
+ CookieTreeNode::DetailedInfo::TYPE_ORIGIN) {
+ node = node->parent();
+ }
+
+ return static_cast<CookieTreeOriginNode*>(node);
+}
+
+std::string GetInfobarLabel(ContentSetting setting,
+ const string16& domain_name) {
+ switch (setting) {
+ case CONTENT_SETTING_BLOCK:
+ return l10n_util::GetStringFUTF8(
+ IDS_COLLECTED_COOKIES_BLOCK_RULE_CREATED, domain_name);
+
+ case CONTENT_SETTING_ALLOW:
+ return l10n_util::GetStringFUTF8(
+ IDS_COLLECTED_COOKIES_ALLOW_RULE_CREATED, domain_name);
+
+ case CONTENT_SETTING_SESSION_ONLY:
+ return l10n_util::GetStringFUTF8(
+ IDS_COLLECTED_COOKIES_SESSION_RULE_CREATED, domain_name);
+
+ default:
+ NOTREACHED() << "Unknown ContentSetting, " << setting;
+ return std::string();
+ }
+}
+
+class CollectedCookiesSource : public ChromeURLDataManager::DataSource {
+ public:
+ explicit CollectedCookiesSource(bool block_third_party_cookies)
+ : DataSource(chrome::kChromeUICollectedCookiesHost,
+ MessageLoop::current()),
+ block_third_party_cookies_(block_third_party_cookies) {
+ }
+
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+
+ virtual std::string GetMimeType(const std::string& path) const {
+ return "text/html";
+ }
+
+ private:
+ virtual ~CollectedCookiesSource() {}
+
+ bool block_third_party_cookies_;
+
+ DISALLOW_COPY_AND_ASSIGN(CollectedCookiesSource);
+};
+
+void CollectedCookiesSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ DictionaryValue localized_strings;
+ localized_strings.SetString("title",
+ l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_DIALOG_TITLE));
+
+ localized_strings.SetString("title",
+ l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_DIALOG_TITLE));
+ localized_strings.SetString("allowedCookies",
+ l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_ALLOWED_COOKIES_LABEL));
+ localized_strings.SetString("blockButton",
+ l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_BLOCK_BUTTON));
+
+ localized_strings.SetString("blockedCookies",
+ l10n_util::GetStringUTF16(block_third_party_cookies_ ?
+ IDS_COLLECTED_COOKIES_BLOCKED_THIRD_PARTY_BLOCKING_ENABLED :
+ IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_LABEL));
+
+ localized_strings.SetString("allowButton",
+ l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_ALLOW_BUTTON));
+ localized_strings.SetString("allowThisSessionButton",
+ l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_SESSION_ONLY_BUTTON));
+ localized_strings.SetString("closeButton",
+ l10n_util::GetStringUTF16(IDS_CLOSE));
+
+ SetFontAndTextDirection(&localized_strings);
+
+ static const base::StringPiece html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_COLLECTED_COOKIES_HTML));
+ const std::string response = jstemplate_builder::GetI18nTemplateHtml(
+ html, &localized_strings);
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(response.size());
+ std::copy(response.begin(), response.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+} // namespace
+
+// static
+void CollectedCookiesUIDelegate::Show(TabContents* tab_contents) {
+ CollectedCookiesUIDelegate* delegate =
+ new CollectedCookiesUIDelegate(tab_contents);
+ ConstrainedHtmlUI::CreateConstrainedHtmlDialog(tab_contents->profile(),
+ delegate,
+ tab_contents);
+}
+
+CollectedCookiesUIDelegate::CollectedCookiesUIDelegate(
+ TabContents* tab_contents)
+ : tab_contents_(tab_contents),
+ closed_(false) {
+ TabSpecificContentSettings* content_settings =
+ tab_contents->GetTabSpecificContentSettings();
+ HostContentSettingsMap* host_content_settings_map =
+ tab_contents_->profile()->GetHostContentSettingsMap();
+
+ registrar_.Add(this, NotificationType::COLLECTED_COOKIES_SHOWN,
+ Source<TabSpecificContentSettings>(content_settings));
+
+ allowed_cookies_tree_model_.reset(
+ content_settings->GetAllowedCookiesTreeModel());
+ blocked_cookies_tree_model_.reset(
+ content_settings->GetBlockedCookiesTreeModel());
+
+ CollectedCookiesSource* source = new CollectedCookiesSource(
+ host_content_settings_map->BlockThirdPartyCookies());
+ tab_contents->profile()->GetChromeURLDataManager()->AddDataSource(source);
+}
+
+CollectedCookiesUIDelegate::~CollectedCookiesUIDelegate() {
+}
+
+bool CollectedCookiesUIDelegate::IsDialogModal() const {
+ return false;
+}
+
+std::wstring CollectedCookiesUIDelegate::GetDialogTitle() const {
+ return std::wstring();
+}
+
+GURL CollectedCookiesUIDelegate::GetDialogContentURL() const {
+ return GURL(chrome::kChromeUICollectedCookiesURL);
+}
+
+void CollectedCookiesUIDelegate::GetWebUIMessageHandlers(
+ std::vector<WebUIMessageHandler*>* handlers) const {
+ const WebUIMessageHandler* handler = this;
+ handlers->push_back(const_cast<WebUIMessageHandler*>(handler));
+}
+
+void CollectedCookiesUIDelegate::GetDialogSize(gfx::Size* size) const {
+ size->set_width(kDialogWidth);
+ size->set_height(kDialogHeight);
+}
+
+std::string CollectedCookiesUIDelegate::GetDialogArgs() const {
+ return std::string();
+}
+
+void CollectedCookiesUIDelegate::OnDialogClosed(
+ const std::string& json_retval) {
+ closed_ = true;
+}
+
+bool CollectedCookiesUIDelegate::ShouldShowDialogTitle() const {
+ return true;
+}
+
+void CollectedCookiesUIDelegate::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("BindCookiesTreeModel",
+ NewCallback(this, &CollectedCookiesUIDelegate::BindCookiesTreeModel));
+ web_ui_->RegisterMessageCallback("Block",
+ NewCallback(this, &CollectedCookiesUIDelegate::Block));
+ web_ui_->RegisterMessageCallback("Allow",
+ NewCallback(this, &CollectedCookiesUIDelegate::Allow));
+ web_ui_->RegisterMessageCallback("AllowThisSession",
+ NewCallback(this, &CollectedCookiesUIDelegate::AllowThisSession));
+
+ allowed_cookies_adapter_.Init(web_ui_);
+ blocked_cookies_adapter_.Init(web_ui_);
+}
+
+void CollectedCookiesUIDelegate::CloseDialog() {
+ if (!closed_ && web_ui_)
+ web_ui_->CallJavascriptFunction("closeDialog");
+}
+
+void CollectedCookiesUIDelegate::SetInfobarLabel(const std::string& text) {
+ StringValue string(text);
+ web_ui_->CallJavascriptFunction("setInfobarLabel", string);
+}
+
+void CollectedCookiesUIDelegate::AddContentException(
+ CookieTreeOriginNode* origin_node, ContentSetting setting) {
+ if (origin_node->CanCreateContentException()) {
+ origin_node->CreateContentException(
+ tab_contents_->profile()->GetHostContentSettingsMap(), setting);
+
+ SetInfobarLabel(GetInfobarLabel(setting, origin_node->GetTitle()));
+ }
+}
+
+void CollectedCookiesUIDelegate::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK_EQ(type.value, NotificationType::COLLECTED_COOKIES_SHOWN);
+ DCHECK_EQ(Source<TabSpecificContentSettings>(source).ptr(),
+ tab_contents_->GetTabSpecificContentSettings());
+ CloseDialog();
+}
+
+void CollectedCookiesUIDelegate::BindCookiesTreeModel(const ListValue* args) {
+ allowed_cookies_adapter_.Bind("allowed-cookies",
+ allowed_cookies_tree_model_.get());
+ blocked_cookies_adapter_.Bind("blocked-cookies",
+ blocked_cookies_tree_model_.get());
+}
+
+void CollectedCookiesUIDelegate::Block(const ListValue* args) {
+ std::string node_path;
+ if (!args->GetString(0, &node_path))
+ return;
+
+ CookieTreeOriginNode* origin_node = GetOriginNode(
+ allowed_cookies_tree_model_.get(), node_path);
+ if (!origin_node)
+ return;
+
+ AddContentException(origin_node, CONTENT_SETTING_BLOCK);
+}
+
+void CollectedCookiesUIDelegate::Allow(const ListValue* args) {
+ std::string node_path;
+ if (!args->GetString(0, &node_path))
+ return;
+
+ CookieTreeOriginNode* origin_node = GetOriginNode(
+ blocked_cookies_tree_model_.get(), node_path);
+ if (!origin_node)
+ return;
+
+ AddContentException(origin_node, CONTENT_SETTING_ALLOW);
+}
+
+void CollectedCookiesUIDelegate::AllowThisSession(const ListValue* args) {
+ std::string node_path;
+ if (!args->GetString(0, &node_path))
+ return;
+
+ CookieTreeOriginNode* origin_node = GetOriginNode(
+ blocked_cookies_tree_model_.get(), node_path);
+ if (!origin_node)
+ return;
+
+ AddContentException(origin_node, CONTENT_SETTING_SESSION_ONLY);
+}
diff --git a/chrome/browser/ui/webui/collected_cookies_ui_delegate.h b/chrome/browser/ui/webui/collected_cookies_ui_delegate.h
new file mode 100644
index 0000000..c49766e
--- /dev/null
+++ b/chrome/browser/ui/webui/collected_cookies_ui_delegate.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_COLLECTED_COOKIES_UI_DELEGATE_H_
+#define CHROME_BROWSER_UI_WEBUI_COLLECTED_COOKIES_UI_DELEGATE_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/ui/webui/cookies_tree_model_adapter.h"
+#include "chrome/browser/ui/webui/html_dialog_ui.h"
+#include "chrome/common/content_settings.h"
+#include "content/common/notification_observer.h"
+#include "content/common/notification_registrar.h"
+
+class GURL;
+class TabContents;
+
+namespace gfx {
+class Size;
+}
+
+class CollectedCookiesUIDelegate : public HtmlDialogUIDelegate,
+ WebUIMessageHandler,
+ NotificationObserver {
+ public:
+ virtual ~CollectedCookiesUIDelegate();
+
+ // static factory method that shows CollectedCookiesUI for |tab_contents|.
+ static void Show(TabContents* tab_contents);
+
+ // HtmlDialogUIDelegate implementation:
+ virtual bool IsDialogModal() const;
+ virtual std::wstring GetDialogTitle() const;
+ virtual GURL GetDialogContentURL() const;
+ virtual void GetWebUIMessageHandlers(
+ std::vector<WebUIMessageHandler*>* handlers) const;
+ virtual void GetDialogSize(gfx::Size* size) const;
+ virtual std::string GetDialogArgs() const;
+ virtual void OnDialogClosed(const std::string& json_retval);
+ virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) {}
+ virtual bool ShouldShowDialogTitle() const;
+
+ // WebUIMessageHandler implementation:
+ virtual void RegisterMessages();
+
+ private:
+ explicit CollectedCookiesUIDelegate(TabContents* tab_contents);
+
+ // Closes the dialog from javascript.
+ void CloseDialog();
+
+ // Sets infobar label text.
+ void SetInfobarLabel(const std::string& text);
+
+ // Add content exception.
+ void AddContentException(CookieTreeOriginNode* origin_node,
+ ContentSetting setting);
+
+ // Notification Observer implementation.
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // JS callback to bind cookies tree models with JS trees.
+ void BindCookiesTreeModel(const ListValue* args);
+
+ // JS callback to block/allow cookies from given site.
+ void Block(const ListValue* args);
+ void Allow(const ListValue* args);
+ void AllowThisSession(const ListValue* args);
+
+ NotificationRegistrar registrar_;
+ TabContents* tab_contents_;
+ bool closed_;
+
+ scoped_ptr<CookiesTreeModel> allowed_cookies_tree_model_;
+ scoped_ptr<CookiesTreeModel> blocked_cookies_tree_model_;
+
+ CookiesTreeModelAdapter allowed_cookies_adapter_;
+ CookiesTreeModelAdapter blocked_cookies_adapter_;
+
+ DISALLOW_COPY_AND_ASSIGN(CollectedCookiesUIDelegate);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_COLLECTED_COOKIES_UI_DELEGATE_H_
diff --git a/chrome/browser/ui/webui/cookies_tree_model_adapter.cc b/chrome/browser/ui/webui/cookies_tree_model_adapter.cc
new file mode 100644
index 0000000..03e04ea
--- /dev/null
+++ b/chrome/browser/ui/webui/cookies_tree_model_adapter.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/cookies_tree_model_adapter.h"
+
+#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/ui/webui/cookies_tree_model_util.h"
+#include "content/browser/webui/web_ui.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace {
+
+// Returns a unique callback name for |adapter|'s requestChildren.
+std::string GetRequestChildrenCallbackName(CookiesTreeModelAdapter* adapter) {
+ static const char kPrefixLoadCookie[] = "requestChildren";
+ return std::string(kPrefixLoadCookie) +
+ base::HexEncode(&adapter, sizeof(adapter));
+}
+
+} // namespace
+
+CookiesTreeModelAdapter::CookiesTreeModelAdapter()
+ : web_ui_(NULL),
+ model_(NULL),
+ batch_update_(false) {
+}
+
+CookiesTreeModelAdapter::~CookiesTreeModelAdapter() {
+ if (model_)
+ model_->RemoveCookiesTreeObserver(this);
+}
+
+void CookiesTreeModelAdapter::Init(WebUI* web_ui) {
+ web_ui_ = web_ui;
+
+ web_ui_->RegisterMessageCallback(GetRequestChildrenCallbackName(this),
+ NewCallback(this, &CookiesTreeModelAdapter::RequestChildren));
+}
+
+void CookiesTreeModelAdapter::Bind(const std::string& tree_id,
+ CookiesTreeModel* model) {
+ DCHECK(web_ui_); // We should have been initialized.
+ DCHECK(tree_id_.empty() && !model_); // No existing bindings.
+
+ tree_id_ = tree_id;
+ model_ = model;
+ model_->AddCookiesTreeObserver(this);
+
+ StringValue tree_id_value(tree_id_);
+ StringValue message_name(GetRequestChildrenCallbackName(this));
+ web_ui_->CallJavascriptFunction("ui.CookiesTree.setCallback",
+ tree_id_value, message_name);
+
+ SendChildren(model_->GetRoot());
+}
+
+void CookiesTreeModelAdapter::TreeNodesAdded(ui::TreeModel* model,
+ ui::TreeModelNode* parent,
+ int start,
+ int count) {
+ // Skip if there is a batch update in progress.
+ if (batch_update_)
+ return;
+
+ CookieTreeNode* parent_node = model_->AsNode(parent);
+
+ StringValue tree_id(tree_id_);
+ scoped_ptr<Value> parend_id(GetTreeNodeId(parent_node));
+ FundamentalValue start_value(start);
+ ListValue children;
+ cookies_tree_model_util::GetChildNodeList(parent_node, start, count,
+ &children);
+ web_ui_->CallJavascriptFunction("ui.CookiesTree.onTreeItemAdded",
+ tree_id, *parend_id.get(), start_value, children);
+}
+
+void CookiesTreeModelAdapter::TreeNodesRemoved(ui::TreeModel* model,
+ ui::TreeModelNode* parent,
+ int start,
+ int count) {
+ // Skip if there is a batch update in progress.
+ if (batch_update_)
+ return;
+
+ StringValue tree_id(tree_id_);
+ scoped_ptr<Value> parend_id(GetTreeNodeId(model_->AsNode(parent)));
+ FundamentalValue start_value(start);
+ FundamentalValue count_value(count);
+ web_ui_->CallJavascriptFunction("ui.CookiesTree.onTreeItemRemoved",
+ tree_id, *parend_id.get(), start_value, count_value);
+}
+
+void CookiesTreeModelAdapter::TreeModelBeginBatch(CookiesTreeModel* model) {
+ DCHECK(!batch_update_); // There should be no nested batch begin.
+ batch_update_ = true;
+}
+
+void CookiesTreeModelAdapter::TreeModelEndBatch(CookiesTreeModel* model) {
+ DCHECK(batch_update_);
+ batch_update_ = false;
+
+ SendChildren(model_->GetRoot());
+}
+
+void CookiesTreeModelAdapter::RequestChildren(const ListValue* args) {
+ std::string node_path;
+ CHECK(args->GetString(0, &node_path));
+
+ CookieTreeNode* node = cookies_tree_model_util::GetTreeNodeFromPath(
+ model_->GetRoot(), node_path);
+ if (node)
+ SendChildren(node);
+}
+
+void CookiesTreeModelAdapter::SendChildren(CookieTreeNode* parent) {
+ StringValue tree_id(tree_id_);
+ scoped_ptr<Value> parend_id(GetTreeNodeId(model_->AsNode(parent)));
+ ListValue children;
+ cookies_tree_model_util::GetChildNodeList(parent, 0, parent->child_count(),
+ &children);
+ web_ui_->CallJavascriptFunction("ui.CookiesTree.setChildren",
+ tree_id, *parend_id.get(), children);
+}
+
+Value* CookiesTreeModelAdapter::GetTreeNodeId(CookieTreeNode* node) {
+ if (node == model_->GetRoot())
+ return Value::CreateNullValue();
+
+ return Value::CreateStringValue(
+ cookies_tree_model_util::GetTreeNodeId(node));
+}
diff --git a/chrome/browser/ui/webui/cookies_tree_model_adapter.h b/chrome/browser/ui/webui/cookies_tree_model_adapter.h
new file mode 100644
index 0000000..6bb8311
--- /dev/null
+++ b/chrome/browser/ui/webui/cookies_tree_model_adapter.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_COOKIES_TREE_MODEL_ADAPTER_H_
+#define CHROME_BROWSER_UI_WEBUI_COOKIES_TREE_MODEL_ADAPTER_H_
+#pragma once
+
+#include "chrome/browser/cookies_tree_model.h"
+
+class ListValue;
+class Value;
+class WebUI;
+
+// CookiesTreeModelAdapter binds a CookiesTreeModel with a JS tree. It observes
+// tree model changes and forwards them to JS tree. It also provides a
+// a callback for JS tree to load children of a specific node.
+class CookiesTreeModelAdapter : public CookiesTreeModel::Observer {
+ public:
+ CookiesTreeModelAdapter();
+ virtual ~CookiesTreeModelAdapter();
+
+ // Initializes with given WebUI.
+ void Init(WebUI* web_ui);
+
+ // Sets up the bindings between js tree and |model|.
+ // Note that this class does not take ownership of the model.
+ void Bind(const std::string& tree_id, CookiesTreeModel* model);
+
+ private:
+ // CookiesTreeModel::Observer implementation.
+ virtual void TreeNodesAdded(ui::TreeModel* model,
+ ui::TreeModelNode* parent,
+ int start,
+ int count);
+ virtual void TreeNodesRemoved(ui::TreeModel* model,
+ ui::TreeModelNode* parent,
+ int start,
+ int count);
+ virtual void TreeNodeChanged(ui::TreeModel* model, ui::TreeModelNode* node) {}
+ virtual void TreeModelBeginBatch(CookiesTreeModel* model);
+ virtual void TreeModelEndBatch(CookiesTreeModel* model);
+
+ // JS callback that gets the tree node using the tree path info in |args| and
+ // call SendChildren to pass back children nodes data to WebUI.
+ void RequestChildren(const ListValue* args);
+
+ // Get children nodes data and pass it to 'CookiesTree.loadChildren' to
+ // update the WebUI.
+ void SendChildren(CookieTreeNode* parent);
+
+ // Helper function to get a Value* representing id of |node|.
+ // Caller needs to free the returned Value.
+ Value* GetTreeNodeId(CookieTreeNode* node);
+
+ // Hosting WebUI of the js tree.
+ WebUI* web_ui_;
+
+ // Id of JS tree that is managed by this handler.
+ std::string tree_id_;
+
+ // The Cookies Tree model. Note that we are not owning the model.
+ CookiesTreeModel* model_;
+
+ // Flag to indicate whether there is a batch update in progress.
+ bool batch_update_;
+
+ DISALLOW_COPY_AND_ASSIGN(CookiesTreeModelAdapter);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_COOKIES_TREE_MODEL_ADAPTER_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index b2f822c..849ff3c 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -3196,8 +3196,12 @@
'browser/ui/webui/chrome_url_data_manager_backend.h',
'browser/ui/webui/chrome_url_data_manager.cc',
'browser/ui/webui/chrome_url_data_manager.h',
+ 'browser/ui/webui/collected_cookies_ui_delegate.cc',
+ 'browser/ui/webui/collected_cookies_ui_delegate.h',
'browser/ui/webui/constrained_html_ui.cc',
'browser/ui/webui/constrained_html_ui.h',
+ 'browser/ui/webui/cookies_tree_model_adapter.cc',
+ 'browser/ui/webui/cookies_tree_model_adapter.h',
'browser/ui/webui/cookies_tree_model_util.cc',
'browser/ui/webui/cookies_tree_model_util.h',
'browser/ui/webui/crashes_ui.cc',
@@ -3392,6 +3396,10 @@
['exclude', 'browser/policy/device_policy_identity_strategy.h'],
['exclude', 'browser/renderer_host/offline_resource_handler.cc'],
['exclude', 'browser/renderer_host/offline_resource_handler.h'],
+ ['exclude', 'browser/ui/webui/collected_cookies_ui_delegate.cc'],
+ ['exclude', 'browser/ui/webui/collected_cookies_ui_delegate.h'],
+ ['exclude', 'browser/ui/webui/cookies_tree_model_adapter.cc'],
+ ['exclude', 'browser/ui/webui/cookies_tree_model_adapter.h'],
['exclude', 'browser/ui/webui/filebrowse_ui.cc'],
['exclude', 'browser/ui/webui/mediaplayer_ui.cc'],
['exclude', 'browser/ui/webui/slideshow_ui.cc'],
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index d57b89f..1387d51 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -80,6 +80,7 @@ const char kChromeUIAppLauncherURL[] = "chrome://newtab/#mode=app-launcher";
const char kChromeUIBookmarksURL[] = "chrome://bookmarks/";
const char kChromeUIBugReportURL[] = "chrome://bugreport/";
const char kChromeUIConflictsURL[] = "chrome://conflicts/";
+const char kChromeUICollectedCookiesURL[] = "chrome://collected-cookies/";
const char kChromeUIConstrainedHTMLTestURL[] = "chrome://constrained-test/";
const char kChromeUICrashesURL[] = "chrome://crashes/";
const char kChromeUIDevToolsURL[] = "chrome-devtools://devtools/";
@@ -117,6 +118,7 @@ const char kChromeUIBookmarksHost[] = "bookmarks";
const char kChromeUIBugReportHost[] = "bugreport";
const char kChromeUIConflictsHost[] = "conflicts";
const char kChromeUICrashesHost[] = "crashes";
+const char kChromeUICollectedCookiesHost[] = "collected-cookies";
const char kChromeUIDevToolsHost[] = "devtools";
const char kChromeUIDialogHost[] = "dialog";
const char kChromeUIDownloadsHost[] = "downloads";
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index f9889d7..971a4df 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -72,6 +72,7 @@ extern const char kChromeUIAppLauncherURL[];
extern const char kChromeUIBookmarksURL[];
extern const char kChromeUIBugReportURL[];
extern const char kChromeUIConflictsURL[];
+extern const char kChromeUICollectedCookiesURL[];
extern const char kChromeUIConstrainedHTMLTestURL[];
extern const char kChromeUICrashesURL[];
extern const char kChromeUIDevToolsURL[];
@@ -110,6 +111,7 @@ extern const char kChromeUIBookmarksHost[];
extern const char kChromeUIBugReportHost[];
extern const char kChromeUIConflictsHost[];
extern const char kChromeUICrashesHost[];
+extern const char kChromeUICollectedCookiesHost[];
extern const char kChromeUIDevToolsHost[];
extern const char kChromeUIDialogHost[];
extern const char kChromeUIDownloadsHost[];
diff --git a/content/browser/webui/web_ui_factory.cc b/content/browser/webui/web_ui_factory.cc
index 7468407..350d403 100644
--- a/content/browser/webui/web_ui_factory.cc
+++ b/content/browser/webui/web_ui_factory.cc
@@ -99,8 +99,10 @@ static WebUIFactoryFunction GetWebUIFactoryFunction(Profile* profile,
if (url.SchemeIs(chrome::kGearsScheme))
return &NewWebUI<HtmlDialogUI>;
- if (url.host() == chrome::kChromeUIDialogHost)
+ if (url.host() == chrome::kChromeUIDialogHost ||
+ url.host() == chrome::kChromeUICollectedCookiesHost) {
return &NewWebUI<ConstrainedHtmlUI>;
+ }
ExtensionService* service = profile ? profile->GetExtensionService() : NULL;
if (service && service->ExtensionBindingsAllowed(url))