summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authortsepez@chromium.org <tsepez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-06 21:46:24 +0000
committertsepez@chromium.org <tsepez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-06 21:46:24 +0000
commit6e368e096fa3d0f1f3eedb4ee8cb7cc0eb83dd9a (patch)
tree2c3e2ba76d542889940c2e30af9ecaf9e40a50f5 /chrome/browser
parentda00dc1867fb2c4e51b4f4dbaa5796a748eaf120 (diff)
downloadchromium_src-6e368e096fa3d0f1f3eedb4ee8cb7cc0eb83dd9a.zip
chromium_src-6e368e096fa3d0f1f3eedb4ee8cb7cc0eb83dd9a.tar.gz
chromium_src-6e368e096fa3d0f1f3eedb4ee8cb7cc0eb83dd9a.tar.bz2
Revert 104341 - Add Content-Security-Policy to chromeos chrome://active-downloads page. Makes chromeos downloadcancelled test flakey since the RDH may still be processing request for webui resources that are now out-of-line and its assert 0 flunks. Will need to fix the test along with the checkin to be reliable.
TBR=abarth@chromium.org Review URL: http://codereview.chromium.org/8171017 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@104372 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/browser_resources.grd3
-rw-r--r--chrome/browser/resources/active_downloads.html685
-rw-r--r--chrome/browser/resources/active_downloads.js678
-rw-r--r--chrome/browser/ui/webui/active_downloads_ui.cc92
-rw-r--r--chrome/browser/ui/webui/chrome_url_data_manager_backend.cc1
5 files changed, 744 insertions, 715 deletions
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index bad3808..b97d4b1 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -120,8 +120,7 @@
</if>
<if expr="pp_ifdef('chromeos')">
<include name="IDR_ABOUT_SYS_HTML" file="resources\about_sys.html" flattenhtml="true" type="BINDATA" />
- <include name="IDR_ACTIVE_DOWNLOADS_HTML" file="resources\active_downloads.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_ACTIVE_DOWNLOADS_JS" file="resources\active_downloads.js" type="BINDATA" />
+ <include name="IDR_ACTIVE_DOWNLOADS_HTML" file="resources\active_downloads.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_CHOOSE_MOBILE_NETWORK_HTML" file="resources\chromeos\choose_mobile_network.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_HOST_REGISTRATION_PAGE_HTML" file="resources\host_registration_page.html" flattenhtml="true" type="BINDATA" />
diff --git a/chrome/browser/resources/active_downloads.html b/chrome/browser/resources/active_downloads.html
index 9d23262..8061148 100644
--- a/chrome/browser/resources/active_downloads.html
+++ b/chrome/browser/resources/active_downloads.html
@@ -184,17 +184,684 @@ div.showalldownloads {
}
</style>
-<script src="chrome://resources/js/local_strings.js"></script>
-<script src="chrome://resources/js/media_common.js"></script>
-<script src="chrome://resources/js/util.js"></script>
-<script src="chrome://active-downloads/strings.js"></script>
-<script src="chrome://active-downloads/active_downloads.js"></script>
-<body i18n-values=".style.fontFamily:fontfamily">
+<script src="shared/js/local_strings.js"></script>
+<script src="shared/js/media_common.js"></script>
+<script src="shared/js/util.js"></script>
+<script>
+
+/**
+ * Wrapper for chrome.send.
+ */
+function chromeSend(func, arg) {
+ if (arg == undefined)
+ arg = '';
+
+ // Convert to string.
+ if (typeof arg == 'number')
+ arg = '' + arg;
+
+ chrome.send(func, [arg]);
+};
+
+/**
+ * Create a child element.
+ *
+ * @param {string} type The type - div, span, etc.
+ * @param {string} className The class name
+ * @param {HTMLElement} parent Parent to append this child to.
+ * @param {string} textContent optional text content of child.
+ * @param {function(*)} onclick onclick function of child.
+ */
+function createChild(type, className, parent, textContent, onclick) {
+ var elem = document.createElement(type);
+ elem.className = className;
+ if (textContent !== undefined)
+ elem.textContent = textContent;
+ elem.onclick = onclick;
+ parent.appendChild(elem);
+ return elem;
+};
+
+var localStrings;
+var downloadRowList;
+
+function init() {
+ localStrings = new LocalStrings();
+ initTestHarness();
+
+ window.onkeydown = function(e) {
+ if (e.keyCode == 27) // Escape.
+ menu.clear();
+ e.preventDefault(); // Suppress browser shortcuts.
+ };
+
+ $('showalldownloadstext').textContent =
+ localStrings.getString('showalldownloads');
+
+ downloadRowList = new DownloadRowList();
+ chromeSend('getDownloads');
+}
+
+/**
+ * Testing. Allow this page to be loaded in a browser.
+ * Create stubs for localStrings and chrome.send.
+ */
+function initTestHarness() {
+ if (location.protocol != 'file:')
+ return;
+
+ // Enable right click for dom inspector.
+ document.body.oncontextmenu = '';
+
+ // Fix localStrings.
+ localStrings = {
+ getString: function(name) {
+ if (name == 'showalldownloads')
+ return 'Show All Downloads';
+ if (name == 'dangerousextension')
+ return 'Extensions, apps, and themes can harm your computer.' +
+ ' Are you sure you want to continue?'
+ if (name == 'continue')
+ return 'Continue';
+ if (name == 'discard')
+ return 'Discard';
+ return name;
+ },
+ getStringF: function(name, path) {
+ return path + ' - Unknown file type.';
+ },
+ };
+
+ // Log chrome.send calls.
+ chrome.send = function(name, ary) {
+ console.log('chrome.send ' + name + ' ' + ary);
+ if (name == 'getDownloads' ||
+ (name == 'openNewFullWindow' &&
+ ary[0] == 'chrome://downloads'))
+ sendTestResults();
+ };
+
+ // Fix resource images.
+ var cssRules = document.styleSheets[0].cssRules;
+ for (var i = 0; i < cssRules.length; i++) {
+ var cssRule = cssRules[i];
+ if (cssRule.selectorText.match(/^div\.icon|^\.menuicon/)) {
+ cssRule.style.backgroundImage =
+ cssRule.style.backgroundImage.replace('chrome://resources', 'shared');
+ }
+ }
+}
+
+/**
+ * Create a results array with test data and call downloadsList.
+ */
+var testElement;
+var testId = 0;
+var testResults = [];
+function sendTestResults() {
+ var testState = (testId % 3 == 0 ? 'IN_PROGRESS' :
+ (testId % 3 == 1 ? 'DANGEROUS' : 'COMPLETE'));
+ state1 = (testId % 3 == 0);
+ testResults.push({
+ state: testState,
+ percent: (testId % 3 == 0 ? 90 : 100),
+ id: testId,
+ file_name: ' Test' + testId + '.pdf',
+ file_path: '/home/achuith/Downloads/Test' + testId + '.pdf',
+ progress_status_text : '107 MB/s - 108 MB of 672 MB, 5 secs left',
+ });
+ testId++;
+ downloadsList(testResults);
+}
+
+/**
+ * Current Menu.
+ */
+var menu = {
+ current_: null,
+
+ /**
+ * Close the current menu.
+ */
+ clear: function() {
+ var current = this.current_;
+ if (current) {
+ current.firstChild.style.display = 'none';
+ current.style.opacity = '';
+ this.current_ = null;
+ }
+ },
+
+ /**
+ * If it's a second click on an open menu, close the menu.
+ * Otherwise, close any other open menu and open the clicked menu.
+ */
+ clicked: function(row) {
+ var menuicon = row.menuicon;
+ if (this.current_ === menuicon) {
+ this.clear();
+ return;
+ }
+ this.clear();
+ if (menuicon.firstChild.style.display != 'block') {
+ menuicon.firstChild.style.display = 'block';
+ menuicon.style.opacity = '1';
+ menuicon.scrollIntoView();
+ this.current_ = menuicon;
+ }
+ window.event.stopPropagation();
+ },
+};
+
+function DiscardResult(result) {
+ return (result.state == 'CANCELLED' ||
+ result.state == 'INTERRUPTED' ||
+ result.state == 'REMOVING');
+};
+
+/**
+ * C++ api calls.
+ */
+function downloadsList(results) {
+ downloadRowList.list(results);
+}
+
+function downloadUpdated(result) {
+ downloadRowList.update(result);
+}
+
+function showAllDownloads() {
+ chromeSend('openNewFullWindow', 'chrome://downloads');
+}
+
+/**
+ * DownloadRow contains all the elements that go into a row of the downloads
+ * list. It represents a single DownloadItem.
+ *
+ * @param {DownloadRowList} list Global DownloadRowList.
+ * @param {Object} result JSON representation of DownloadItem.
+ * @constructor
+ */
+function DownloadRow(list, result) {
+ this.path = result.file_path;
+ this.name = result.file_name;
+ this.fileUrl = result.file_url;
+ this.list = list;
+ this.id = result.id;
+
+ this.createRow_(list);
+ this.createMenu_();
+ this.createRowButton_();
+ this.setMenuHidden_(true);
+}
+
+DownloadRow.prototype = {
+ /**
+ * Create the row html element and book-keeping for the row.
+ * @param {DownloadRowList} list global DownloadRowList instance.
+ * @private
+ */
+ createRow_: function(list) {
+ var elem = document.createElement('li');
+ elem.className = 'downloadrow';
+ elem.id = this.path;
+ elem.row = this;
+ this.element = elem;
+
+ list.append(this);
+ },
+
+ setErrorText_: function(text) {
+ this.filename.textContent = text;
+ },
+
+ supportsPdf_: function() {
+ return 'application/pdf' in navigator.mimeTypes;
+ },
+
+ openFilePath_: function() {
+ chromeSend('openNewFullWindow', this.fileUrl);
+ },
+
+ /**
+ * Determine onclick behavior based on filename.
+ * @private
+ */
+ getFunctionForItem_: function() {
+ var path = this.path;
+ var self = this;
+
+ if (pathIsAudioFile(path)) {
+ return function() {
+ chromeSend('playMediaFile', path);
+ };
+ }
+ if (pathIsVideoFile(path)) {
+ return function() {
+ chromeSend('playMediaFile', path);
+ };
+ }
+ if (pathIsImageFile(path)) {
+ return function() {
+ self.openFilePath_();
+ }
+ }
+ if (pathIsHtmlFile(path)) {
+ return function() {
+ self.openFilePath_();
+ }
+ }
+ if (pathIsPdfFile(path) && this.supportsPdf_()) {
+ return function() {
+ self.openFilePath_();
+ }
+ }
+
+ return function() {
+ self.setErrorText_(localStrings.getStringF('error_unknown_file_type',
+ self.name));
+ };
+ },
+
+ setDangerousIcon_: function(warning) {
+ this.icon.className = warning ? 'iconwarning' : 'icon';
+ this.icon.style.background = warning ? '' :
+ 'url(chrome://fileicon' + escape(this.path) +
+ '?iconsize=small) no-repeat';
+ },
+
+ /**
+ * Create the row button for the left of the row.
+ * This contains the icon, filename and error elements.
+ * @private
+ */
+ createRowButton_: function () {
+ this.rowbutton = createChild('div', 'rowbutton rowbg', this.element);
+
+ // Icon.
+ this.icon = createChild('div', 'icon', this.rowbutton);
+ this.setDangerousIcon_(false);
+
+ // Filename.
+ this.filename = createChild('span', 'title', this.rowbutton, this.name);
+ },
+
+ setMenuHidden_: function(hidden) {
+ this.menubutton.hidden = hidden;
+ if (hidden) {
+ this.rowbutton.style.width = '238px';
+ } else {
+ this.rowbutton.style.width = '';
+ }
+ },
+
+ /**
+ * Create the menu button on the right of the row.
+ * This contains the menuicon. The menuicon contains the menu, which
+ * contains items for Pause/Resume and Cancel.
+ * @private
+ */
+ createMenu_: function() {
+ var self = this;
+ this.menubutton = createChild('div', 'menubutton rowbg', this.element, '',
+ function() {
+ menu.clicked(self);
+ });
+
+ this.menuicon = createChild('div', 'menuicon', this.menubutton);
+
+ var menudiv = createChild('div', 'menu', this.menuicon);
+
+ this.pause = createChild('div', 'menuitem', menudiv,
+ localStrings.getString('pause'), function() {
+ self.pauseToggleDownload_();
+ });
+
+ this.cancel = createChild('div', 'menuitem', menudiv,
+ localStrings.getString('cancel'), function() {
+ self.cancelDownload_();
+ });
+ },
+
+ allowDownload_: function() {
+ chromeSend('allowDownload', this.id);
+ },
+
+ cancelDownload_: function() {
+ chromeSend('cancelDownload', this.id);
+ },
+
+ pauseToggleDownload_: function() {
+ this.pause.textContent =
+ (this.pause.textContent == localStrings.getString('pause')) ?
+ localStrings.getString('resume') :
+ localStrings.getString('pause');
+
+ chromeSend('pauseToggleDownload', this.id);
+ },
+
+ changeElemHeight_: function(elem, x) {
+ elem.style.height = elem.clientHeight + x + 'px';
+ },
+
+ changeRowHeight_: function(x) {
+ this.list.rowsHeight += x;
+ this.changeElemHeight_(this.element, x);
+ // rowbutton has 5px padding.
+ this.changeElemHeight_(this.rowbutton, x - 5);
+ this.list.resize();
+ },
+
+ DANGEROUS_HEIGHT: 60,
+ createDangerousPrompt_: function(dangerType) {
+ if (this.dangerous)
+ return;
+
+ this.dangerous = createChild('div', 'dangerousprompt', this.rowbutton);
+
+ // Handle dangerous files, extensions and dangerous urls.
+ var dangerText;
+ if (dangerType == 'DANGEROUS_URL') {
+ dangerText = localStrings.getString('dangerousurl');
+ } else if (dangerType == 'DANGEROUS_FILE' && this.path.match(/\.crx$/)) {
+ dangerText = localStrings.getString('dangerousextension');
+ } else {
+ dangerText = localStrings.getStringF('dangerousfile', this.name);
+ }
+ createChild('span', 'dangerousprompttext', this.dangerous, dangerText);
+
+ var self = this;
+ createChild('span', 'confirm', this.dangerous,
+ localStrings.getString('discard'),
+ function() {
+ self.cancelDownload_();
+ });
+ createChild('span', 'confirm', this.dangerous,
+ localStrings.getString('continue'),
+ function() {
+ self.allowDownload_();
+ });
+
+ this.changeRowHeight_(this.DANGEROUS_HEIGHT);
+ this.setDangerousIcon_(true);
+ },
+
+ removeDangerousPrompt_: function() {
+ if (!this.dangerous)
+ return;
+
+ this.rowbutton.removeChild(this.dangerous);
+ this.dangerous = null;
+
+ this.changeRowHeight_(-this.DANGEROUS_HEIGHT);
+ this.setDangerousIcon_(false);
+ },
+
+ PROGRESS_HEIGHT: 8,
+ createProgress_: function() {
+ if (this.progress)
+ return;
+
+ this.progress = createChild('div', 'progress', this.rowbutton);
+
+ this.setMenuHidden_(false);
+ this.changeRowHeight_(this.PROGRESS_HEIGHT);
+ },
+
+ removeProgress_: function() {
+ if (!this.progress)
+ return;
+
+ this.rowbutton.removeChild(this.progress);
+ this.progress = null;
+
+ this.changeRowHeight_(-this.PROGRESS_HEIGHT);
+ this.setMenuHidden_(true);
+ },
+
+ updatePause_: function(result) {
+ var pause = this.pause;
+ var pauseStr = localStrings.getString('pause');
+ var resumeStr = localStrings.getString('resume');
+
+ if (pause &&
+ result.state == 'PAUSED' &&
+ pause.textContent != resumeStr) {
+ pause.textContent = resumeStr;
+ } else if (pause &&
+ result.state == 'IN_PROGRESS' &&
+ pause.textContent != pauseStr) {
+ pause.textContent = pauseStr;
+ }
+ },
+
+ progressStatusText_: function(progress) {
+ if (!progress)
+ return progress;
+
+ /* m looks like this:
+ ["107 MB/s - 108 MB of 672 MB, 5 secs left",
+ "107 MB/s", "108", "MB", "672", "MB", "5 secs left"]
+ We want to return progress text like this:
+ "108 / 672 MB, 5 secs left"
+ or
+ "108 kB / 672 MB, 5 secs left"
+ */
+ var m = progress.match(
+ /([^-]*) - ([0-9\.]*) ([a-zA-Z]*) of ([0-9\.]*) ([a-zA-Z]*), (.*)/);
+ if (!m || m.length != 7)
+ return progress;
+
+ return m[2] + (m[3] == m[5] ? '' : ' ' + m[3]) +
+ ' / ' + m[4] + ' ' + m[5] + ', ' + m[6];
+ },
+
+ updateProgress_: function(result) {
+ this.removeDangerousPrompt_();
+ this.createProgress_();
+ this.progress.textContent =
+ this.progressStatusText_(result.progress_status_text);
+ this.updatePause_(result);
+ },
+
+ /**
+ * Called when the item has finished downloading. Switch the menu
+ * and remove the progress bar.
+ * @private
+ */
+ finishedDownloading_: function() {
+ // Make rowbutton clickable.
+ this.rowbutton.onclick = this.getFunctionForItem_();
+ this.rowbutton.style.cursor = 'pointer';
+
+ // Make rowbutton draggable.
+ this.rowbutton.setAttribute('draggable', 'true');
+ var self = this;
+ this.rowbutton.addEventListener('dragstart', function(e) {
+ e.dataTransfer.effectAllowed = 'copy';
+ e.dataTransfer.setData('Text', self.path);
+ e.dataTransfer.setData('URL', self.fileUrl);
+ }, false);
+
+ this.removeDangerousPrompt_();
+ this.removeProgress_();
+ },
+
+ /**
+ * One of the DownloadItem we are observing has updated.
+ * @param {Object} result JSON representation of DownloadItem.
+ */
+ update: function(result) {
+ this.filename.textContent = result.file_name;
+ this.id = result.id;
+
+ if (result.state != 'COMPLETE') {
+ this.rowbutton.onclick = '';
+ this.rowbutton.style.cursor = '';
+ }
+
+ if (DiscardResult(result)) {
+ this.list.remove(this);
+ } else if (result.state == 'DANGEROUS') {
+ this.createDangerousPrompt_(result.danger_type);
+ } else if (result.percent < 100) {
+ this.updateProgress_(result);
+ } else if (result.state == 'COMPLETE') {
+ this.finishedDownloading_();
+ }
+ },
+};
+
+/**
+ * DownloadRowList is a container for DownloadRows.
+ */
+function DownloadRowList() {
+ this.element = createChild('ul', 'downloadlist', $('main'));
+
+ document.title = localStrings.getString('downloadpath').
+ split('/').pop();
+}
+
+DownloadRowList.prototype = {
+
+ /**
+ * numRows is the current number of rows.
+ * rowsHeight is the sum of the heights of all rows.
+ * rowListHeight is the height of the container containing the rows.
+ * rows is the list of DownloadRows.
+ */
+ numRows: 0,
+ rowsHeight: 0,
+ rowListHeight: 72,
+ rows: [],
+
+ /**
+ * Resize the panel to accomodate all rows.
+ */
+ resize: function() {
+ var diff = this.rowsHeight - this.rowListHeight;
+ if (diff != 0 && (this.rowListHeight + diff > 72)) {
+ window.resizeBy(0, diff);
+ this.rowListHeight += diff;
+ }
+ },
+
+ /**
+ * Remove a row from the list, as when a download is canceled, or
+ * the the number of rows has exceeded the max allowed.
+ *
+ * @param {DownloadRow} row Row to be removed.
+ * @private
+ */
+ remove: function(row) {
+ this.rows.splice(this.rows.indexOf(row), 1);
+
+ this.numRows--;
+ this.rowsHeight -= row.element.offsetHeight;
+ this.resize();
+
+ this.element.removeChild(row.element);
+ row.element.row = null;
+ },
+
+ removeList: function(rows) {
+ for (i = 0; i < rows.length; i++) {
+ this.remove(rows[i]);
+ }
+ },
+
+ updateList: function(results) {
+ for (var i = 0; i < results.length; i++) {
+ this.update(results[i]);
+ }
+ },
+
+ /**
+ * Append a new row to the list, removing the last row if we exceed the
+ * maximum allowed.
+ * @param {DownloadRow} row Row to be removed.
+ */
+ append: function(row) {
+ this.rows.push(row);
+
+ var elem = row.element;
+ var list = this.element;
+ if (list.firstChild) {
+ list.insertBefore(elem, list.firstChild);
+ } else {
+ list.appendChild(elem);
+ }
+
+ this.rowsHeight += elem.offsetHeight;
+
+ this.numRows++;
+ // We display no more than 5 elements.
+ if (this.numRows > 5)
+ this.remove(list.lastChild.row);
+
+ this.resize();
+ },
+
+ getRow: function(path) {
+ for (var i = 0; i < this.rows.length; i++) {
+ if (this.rows[i].path == path)
+ return this.rows[i];
+ }
+ },
+
+ /**
+ * Returns the list of rows that are not in the results array.
+ * @param {Array} results Array of JSONified DownloadItems.
+ */
+ findMissing: function(results) {
+ var removeList = [];
+
+ for (var i = 0; i < this.rows.length; i++) {
+ var row = this.rows[i];
+ var found = false;
+ for (var j = 0; j < results.length; j++) {
+ if (row.path == results[j].file_path) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ removeList.push(row);
+ }
+ return removeList;
+ },
+
+ /**
+ * Handle list callback with list of DownloadItems.
+ * @param {Array} results Array of JSONified DownloadItems.
+ */
+ list: function(results) {
+ var rows = this.findMissing(results);
+ this.updateList(results);
+ this.removeList(rows);
+ },
+
+ /**
+ * Handle update of a DownloadItem we're observing.
+ * @param {Object} result JSON representation of DownloadItem.
+ */
+ update: function(result) {
+ var row = this.getRow(result.file_path);
+ if (!row && !DiscardResult(result))
+ row = new DownloadRow(this, result);
+
+ row && row.update(result);
+ },
+};
+
+</script>
+<body onload="init();" onclick="menu.clear();" onselectstart="return false;"
+ i18n-values=".style.fontFamily:fontfamily" oncontextmenu="return false;"
+ onBlur="menu.clear();">
<div id="main" class="columnlist"></div>
<div id="showalldownloads" class="showalldownloads">
- <span id="showalldownloadstext" class="showalldownloadstext"></span>
+ <span id="showalldownloadstext" class="showalldownloadstext"
+ onclick="showAllDownloads()"></span>
</div>
-<script src="chrome://resources/js/i18n_template.js"></script>
-<script src="chrome://resources/js/i18n_process.js"></script>
</body>
</html>
diff --git a/chrome/browser/resources/active_downloads.js b/chrome/browser/resources/active_downloads.js
deleted file mode 100644
index 82161f8..0000000
--- a/chrome/browser/resources/active_downloads.js
+++ /dev/null
@@ -1,678 +0,0 @@
-// 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.
-
-/**
- * Wrapper for chrome.send.
- */
-function chromeSend(func, arg) {
- if (arg == undefined)
- arg = '';
-
- // Convert to string.
- if (typeof arg == 'number')
- arg = '' + arg;
-
- chrome.send(func, [arg]);
-};
-
-/**
- * Create a child element.
- *
- * @param {string} type The type - div, span, etc.
- * @param {string} className The class name
- * @param {HTMLElement} parent Parent to append this child to.
- * @param {string} textContent optional text content of child.
- * @param {function(*)} onclick onclick function of child.
- */
-function createChild(type, className, parent, textContent, onclick) {
- var elem = document.createElement(type);
- elem.className = className;
- if (textContent !== undefined)
- elem.textContent = textContent;
- elem.onclick = onclick;
- parent.appendChild(elem);
- return elem;
-};
-
-var localStrings;
-var downloadRowList;
-
-function init() {
- localStrings = new LocalStrings();
- initTestHarness();
-
- window.onkeydown = function(e) {
- if (e.keyCode == 27) // Escape.
- menu.clear();
- e.preventDefault(); // Suppress browser shortcuts.
- };
-
- document.body.addEventListener("blur", menu.clear);
- document.body.addEventListener("click", menu.clear);
- document.body.addEventListener("contextmenu", function (e) {
- e.preventDefault(); });
- document.body.addEventListener("selectstart", function (e) {
- e.preventDefault(); });
-
- var sadt = $('showalldownloadstext');
- sadt.textContent = localStrings.getString('showalldownloads');
- sadt.addEventListener("click", showAllDownloads);
-
- downloadRowList = new DownloadRowList();
- chromeSend('getDownloads');
-}
-
-/**
- * Testing. Allow this page to be loaded in a browser.
- * Create stubs for localStrings and chrome.send.
- */
-function initTestHarness() {
- if (location.protocol != 'file:')
- return;
-
- // Enable right click for dom inspector.
- document.body.oncontextmenu = '';
-
- // Fix localStrings.
- localStrings = {
- getString: function(name) {
- if (name == 'showalldownloads')
- return 'Show All Downloads';
- if (name == 'dangerousextension')
- return 'Extensions, apps, and themes can harm your computer.' +
- ' Are you sure you want to continue?'
- if (name == 'continue')
- return 'Continue';
- if (name == 'discard')
- return 'Discard';
- return name;
- },
- getStringF: function(name, path) {
- return path + ' - Unknown file type.';
- },
- };
-
- // Log chrome.send calls.
- chrome.send = function(name, ary) {
- console.log('chrome.send ' + name + ' ' + ary);
- if (name == 'getDownloads' ||
- (name == 'openNewFullWindow' &&
- ary[0] == 'chrome://downloads'))
- sendTestResults();
- };
-
- // Fix resource images.
- var cssRules = document.styleSheets[0].cssRules;
- for (var i = 0; i < cssRules.length; i++) {
- var cssRule = cssRules[i];
- if (cssRule.selectorText.match(/^div\.icon|^\.menuicon/)) {
- cssRule.style.backgroundImage =
- cssRule.style.backgroundImage.replace('chrome://resources', 'shared');
- }
- }
-}
-
-/**
- * Create a results array with test data and call downloadsList.
- */
-var testElement;
-var testId = 0;
-var testResults = [];
-function sendTestResults() {
- var testState = (testId % 3 == 0 ? 'IN_PROGRESS' :
- (testId % 3 == 1 ? 'DANGEROUS' : 'COMPLETE'));
- state1 = (testId % 3 == 0);
- testResults.push({
- state: testState,
- percent: (testId % 3 == 0 ? 90 : 100),
- id: testId,
- file_name: ' Test' + testId + '.pdf',
- file_path: '/home/achuith/Downloads/Test' + testId + '.pdf',
- progress_status_text : '107 MB/s - 108 MB of 672 MB, 5 secs left',
- });
- testId++;
- downloadsList(testResults);
-}
-
-/**
- * Current Menu.
- */
-var menu = {
- current_: null,
-
- /**
- * Close the current menu.
- */
- clear: function() {
- var current = this.current_;
- if (current) {
- current.firstChild.style.display = 'none';
- current.style.opacity = '';
- this.current_ = null;
- }
- },
-
- /**
- * If it's a second click on an open menu, close the menu.
- * Otherwise, close any other open menu and open the clicked menu.
- */
- clicked: function(row) {
- var menuicon = row.menuicon;
- if (this.current_ === menuicon) {
- this.clear();
- return;
- }
- this.clear();
- if (menuicon.firstChild.style.display != 'block') {
- menuicon.firstChild.style.display = 'block';
- menuicon.style.opacity = '1';
- menuicon.scrollIntoView();
- this.current_ = menuicon;
- }
- window.event.stopPropagation();
- },
-};
-
-function DiscardResult(result) {
- return (result.state == 'CANCELLED' ||
- result.state == 'INTERRUPTED' ||
- result.state == 'REMOVING');
-};
-
-/**
- * C++ api calls.
- */
-function downloadsList(results) {
- downloadRowList.list(results);
-}
-
-function downloadUpdated(result) {
- downloadRowList.update(result);
-}
-
-function showAllDownloads() {
- chromeSend('openNewFullWindow', 'chrome://downloads');
-}
-
-/**
- * DownloadRow contains all the elements that go into a row of the downloads
- * list. It represents a single DownloadItem.
- *
- * @param {DownloadRowList} list Global DownloadRowList.
- * @param {Object} result JSON representation of DownloadItem.
- * @constructor
- */
-function DownloadRow(list, result) {
- this.path = result.file_path;
- this.name = result.file_name;
- this.fileUrl = result.file_url;
- this.list = list;
- this.id = result.id;
-
- this.createRow_(list);
- this.createMenu_();
- this.createRowButton_();
- this.setMenuHidden_(true);
-}
-
-DownloadRow.prototype = {
- /**
- * Create the row html element and book-keeping for the row.
- * @param {DownloadRowList} list global DownloadRowList instance.
- * @private
- */
- createRow_: function(list) {
- var elem = document.createElement('li');
- elem.className = 'downloadrow';
- elem.id = this.path;
- elem.row = this;
- this.element = elem;
-
- list.append(this);
- },
-
- setErrorText_: function(text) {
- this.filename.textContent = text;
- },
-
- supportsPdf_: function() {
- return 'application/pdf' in navigator.mimeTypes;
- },
-
- openFilePath_: function() {
- chromeSend('openNewFullWindow', this.fileUrl);
- },
-
- /**
- * Determine onclick behavior based on filename.
- * @private
- */
- getFunctionForItem_: function() {
- var path = this.path;
- var self = this;
-
- if (pathIsAudioFile(path)) {
- return function() {
- chromeSend('playMediaFile', path);
- };
- }
- if (pathIsVideoFile(path)) {
- return function() {
- chromeSend('playMediaFile', path);
- };
- }
- if (pathIsImageFile(path)) {
- return function() {
- self.openFilePath_();
- }
- }
- if (pathIsHtmlFile(path)) {
- return function() {
- self.openFilePath_();
- }
- }
- if (pathIsPdfFile(path) && this.supportsPdf_()) {
- return function() {
- self.openFilePath_();
- }
- }
-
- return function() {
- self.setErrorText_(localStrings.getStringF('error_unknown_file_type',
- self.name));
- };
- },
-
- setDangerousIcon_: function(warning) {
- this.icon.className = warning ? 'iconwarning' : 'icon';
- this.icon.style.background = warning ? '' :
- 'url(chrome://fileicon' + escape(this.path) +
- '?iconsize=small) no-repeat';
- },
-
- /**
- * Create the row button for the left of the row.
- * This contains the icon, filename and error elements.
- * @private
- */
- createRowButton_: function () {
- this.rowbutton = createChild('div', 'rowbutton rowbg', this.element);
-
- // Icon.
- this.icon = createChild('div', 'icon', this.rowbutton);
- this.setDangerousIcon_(false);
-
- // Filename.
- this.filename = createChild('span', 'title', this.rowbutton, this.name);
- },
-
- setMenuHidden_: function(hidden) {
- this.menubutton.hidden = hidden;
- if (hidden) {
- this.rowbutton.style.width = '238px';
- } else {
- this.rowbutton.style.width = '';
- }
- },
-
- /**
- * Create the menu button on the right of the row.
- * This contains the menuicon. The menuicon contains the menu, which
- * contains items for Pause/Resume and Cancel.
- * @private
- */
- createMenu_: function() {
- var self = this;
- this.menubutton = createChild('div', 'menubutton rowbg', this.element, '',
- function() {
- menu.clicked(self);
- });
-
- this.menuicon = createChild('div', 'menuicon', this.menubutton);
-
- var menudiv = createChild('div', 'menu', this.menuicon);
-
- this.pause = createChild('div', 'menuitem', menudiv,
- localStrings.getString('pause'), function() {
- self.pauseToggleDownload_();
- });
-
- this.cancel = createChild('div', 'menuitem', menudiv,
- localStrings.getString('cancel'), function() {
- self.cancelDownload_();
- });
- },
-
- allowDownload_: function() {
- chromeSend('allowDownload', this.id);
- },
-
- cancelDownload_: function() {
- chromeSend('cancelDownload', this.id);
- },
-
- pauseToggleDownload_: function() {
- this.pause.textContent =
- (this.pause.textContent == localStrings.getString('pause')) ?
- localStrings.getString('resume') :
- localStrings.getString('pause');
-
- chromeSend('pauseToggleDownload', this.id);
- },
-
- changeElemHeight_: function(elem, x) {
- elem.style.height = elem.clientHeight + x + 'px';
- },
-
- changeRowHeight_: function(x) {
- this.list.rowsHeight += x;
- this.changeElemHeight_(this.element, x);
- // rowbutton has 5px padding.
- this.changeElemHeight_(this.rowbutton, x - 5);
- this.list.resize();
- },
-
- DANGEROUS_HEIGHT: 60,
- createDangerousPrompt_: function(dangerType) {
- if (this.dangerous)
- return;
-
- this.dangerous = createChild('div', 'dangerousprompt', this.rowbutton);
-
- // Handle dangerous files, extensions and dangerous urls.
- var dangerText;
- if (dangerType == 'DANGEROUS_URL') {
- dangerText = localStrings.getString('dangerousurl');
- } else if (dangerType == 'DANGEROUS_FILE' && this.path.match(/\.crx$/)) {
- dangerText = localStrings.getString('dangerousextension');
- } else {
- dangerText = localStrings.getStringF('dangerousfile', this.name);
- }
- createChild('span', 'dangerousprompttext', this.dangerous, dangerText);
-
- var self = this;
- createChild('span', 'confirm', this.dangerous,
- localStrings.getString('discard'),
- function() {
- self.cancelDownload_();
- });
- createChild('span', 'confirm', this.dangerous,
- localStrings.getString('continue'),
- function() {
- self.allowDownload_();
- });
-
- this.changeRowHeight_(this.DANGEROUS_HEIGHT);
- this.setDangerousIcon_(true);
- },
-
- removeDangerousPrompt_: function() {
- if (!this.dangerous)
- return;
-
- this.rowbutton.removeChild(this.dangerous);
- this.dangerous = null;
-
- this.changeRowHeight_(-this.DANGEROUS_HEIGHT);
- this.setDangerousIcon_(false);
- },
-
- PROGRESS_HEIGHT: 8,
- createProgress_: function() {
- if (this.progress)
- return;
-
- this.progress = createChild('div', 'progress', this.rowbutton);
-
- this.setMenuHidden_(false);
- this.changeRowHeight_(this.PROGRESS_HEIGHT);
- },
-
- removeProgress_: function() {
- if (!this.progress)
- return;
-
- this.rowbutton.removeChild(this.progress);
- this.progress = null;
-
- this.changeRowHeight_(-this.PROGRESS_HEIGHT);
- this.setMenuHidden_(true);
- },
-
- updatePause_: function(result) {
- var pause = this.pause;
- var pauseStr = localStrings.getString('pause');
- var resumeStr = localStrings.getString('resume');
-
- if (pause &&
- result.state == 'PAUSED' &&
- pause.textContent != resumeStr) {
- pause.textContent = resumeStr;
- } else if (pause &&
- result.state == 'IN_PROGRESS' &&
- pause.textContent != pauseStr) {
- pause.textContent = pauseStr;
- }
- },
-
- progressStatusText_: function(progress) {
- if (!progress)
- return progress;
-
- /* m looks like this:
- ["107 MB/s - 108 MB of 672 MB, 5 secs left",
- "107 MB/s", "108", "MB", "672", "MB", "5 secs left"]
- We want to return progress text like this:
- "108 / 672 MB, 5 secs left"
- or
- "108 kB / 672 MB, 5 secs left"
- */
- var m = progress.match(
- /([^-]*) - ([0-9\.]*) ([a-zA-Z]*) of ([0-9\.]*) ([a-zA-Z]*), (.*)/);
- if (!m || m.length != 7)
- return progress;
-
- return m[2] + (m[3] == m[5] ? '' : ' ' + m[3]) +
- ' / ' + m[4] + ' ' + m[5] + ', ' + m[6];
- },
-
- updateProgress_: function(result) {
- this.removeDangerousPrompt_();
- this.createProgress_();
- this.progress.textContent =
- this.progressStatusText_(result.progress_status_text);
- this.updatePause_(result);
- },
-
- /**
- * Called when the item has finished downloading. Switch the menu
- * and remove the progress bar.
- * @private
- */
- finishedDownloading_: function() {
- // Make rowbutton clickable.
- this.rowbutton.onclick = this.getFunctionForItem_();
- this.rowbutton.style.cursor = 'pointer';
-
- // Make rowbutton draggable.
- this.rowbutton.setAttribute('draggable', 'true');
- var self = this;
- this.rowbutton.addEventListener('dragstart', function(e) {
- e.dataTransfer.effectAllowed = 'copy';
- e.dataTransfer.setData('Text', self.path);
- e.dataTransfer.setData('URL', self.fileUrl);
- }, false);
-
- this.removeDangerousPrompt_();
- this.removeProgress_();
- },
-
- /**
- * One of the DownloadItem we are observing has updated.
- * @param {Object} result JSON representation of DownloadItem.
- */
- update: function(result) {
- this.filename.textContent = result.file_name;
- this.id = result.id;
-
- if (result.state != 'COMPLETE') {
- this.rowbutton.onclick = '';
- this.rowbutton.style.cursor = '';
- }
-
- if (DiscardResult(result)) {
- this.list.remove(this);
- } else if (result.state == 'DANGEROUS') {
- this.createDangerousPrompt_(result.danger_type);
- } else if (result.percent < 100) {
- this.updateProgress_(result);
- } else if (result.state == 'COMPLETE') {
- this.finishedDownloading_();
- }
- },
-};
-
-/**
- * DownloadRowList is a container for DownloadRows.
- */
-function DownloadRowList() {
- this.element = createChild('ul', 'downloadlist', $('main'));
-
- document.title = localStrings.getString('downloadpath').
- split('/').pop();
-}
-
-DownloadRowList.prototype = {
-
- /**
- * numRows is the current number of rows.
- * rowsHeight is the sum of the heights of all rows.
- * rowListHeight is the height of the container containing the rows.
- * rows is the list of DownloadRows.
- */
- numRows: 0,
- rowsHeight: 0,
- rowListHeight: 72,
- rows: [],
-
- /**
- * Resize the panel to accomodate all rows.
- */
- resize: function() {
- var diff = this.rowsHeight - this.rowListHeight;
- if (diff != 0 && (this.rowListHeight + diff > 72)) {
- window.resizeBy(0, diff);
- this.rowListHeight += diff;
- }
- },
-
- /**
- * Remove a row from the list, as when a download is canceled, or
- * the the number of rows has exceeded the max allowed.
- *
- * @param {DownloadRow} row Row to be removed.
- * @private
- */
- remove: function(row) {
- this.rows.splice(this.rows.indexOf(row), 1);
-
- this.numRows--;
- this.rowsHeight -= row.element.offsetHeight;
- this.resize();
-
- this.element.removeChild(row.element);
- row.element.row = null;
- },
-
- removeList: function(rows) {
- for (i = 0; i < rows.length; i++) {
- this.remove(rows[i]);
- }
- },
-
- updateList: function(results) {
- for (var i = 0; i < results.length; i++) {
- this.update(results[i]);
- }
- },
-
- /**
- * Append a new row to the list, removing the last row if we exceed the
- * maximum allowed.
- * @param {DownloadRow} row Row to be removed.
- */
- append: function(row) {
- this.rows.push(row);
-
- var elem = row.element;
- var list = this.element;
- if (list.firstChild) {
- list.insertBefore(elem, list.firstChild);
- } else {
- list.appendChild(elem);
- }
-
- this.rowsHeight += elem.offsetHeight;
-
- this.numRows++;
- // We display no more than 5 elements.
- if (this.numRows > 5)
- this.remove(list.lastChild.row);
-
- this.resize();
- },
-
- getRow: function(path) {
- for (var i = 0; i < this.rows.length; i++) {
- if (this.rows[i].path == path)
- return this.rows[i];
- }
- },
-
- /**
- * Returns the list of rows that are not in the results array.
- * @param {Array} results Array of JSONified DownloadItems.
- */
- findMissing: function(results) {
- var removeList = [];
-
- for (var i = 0; i < this.rows.length; i++) {
- var row = this.rows[i];
- var found = false;
- for (var j = 0; j < results.length; j++) {
- if (row.path == results[j].file_path) {
- found = true;
- break;
- }
- }
- if (!found)
- removeList.push(row);
- }
- return removeList;
- },
-
- /**
- * Handle list callback with list of DownloadItems.
- * @param {Array} results Array of JSONified DownloadItems.
- */
- list: function(results) {
- var rows = this.findMissing(results);
- this.updateList(results);
- this.removeList(rows);
- },
-
- /**
- * Handle update of a DownloadItem we're observing.
- * @param {Object} result JSON representation of DownloadItem.
- */
- update: function(result) {
- var row = this.getRow(result.file_path);
- if (!row && !DiscardResult(result))
- row = new DownloadRow(this, result);
-
- row && row.update(result);
- },
-};
-
-document.addEventListener('DOMContentLoaded', init);
diff --git a/chrome/browser/ui/webui/active_downloads_ui.cc b/chrome/browser/ui/webui/active_downloads_ui.cc
index 7f7f0d8..e2f78b3 100644
--- a/chrome/browser/ui/webui/active_downloads_ui.cc
+++ b/chrome/browser/ui/webui/active_downloads_ui.cc
@@ -33,9 +33,9 @@
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/browser/ui/webui/fileicon_source_chromeos.h"
-#include "chrome/browser/ui/webui/chrome_web_ui_data_source.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/url_constants.h"
#include "content/browser/download/download_item.h"
#include "content/browser/download/download_manager.h"
@@ -47,6 +47,7 @@
#include "grit/locale_settings.h"
#include "net/base/escape.h"
#include "net/url_request/url_request_file_job.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
namespace {
@@ -63,36 +64,75 @@ static const char kPropertyTitle[] = "title";
static const char kPropertyDirectory[] = "isDirectory";
static const char kActiveDownloadAppName[] = "active-downloads";
-ChromeWebUIDataSource* CreateActiveDownloadsUIHTMLSource() {
- ChromeWebUIDataSource* source =
- new ChromeWebUIDataSource(chrome::kChromeUIActiveDownloadsHost);
-
- source->AddLocalizedString("dangerousfile", IDS_PROMPT_DANGEROUS_DOWNLOAD);
- source->AddLocalizedString("dangerousextension",
- IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION);
- source->AddLocalizedString("dangerousurl", IDS_PROMPT_UNSAFE_DOWNLOAD_URL);
- source->AddLocalizedString("cancel", IDS_DOWNLOAD_LINK_CANCEL);
- source->AddLocalizedString("discard", IDS_DISCARD_DOWNLOAD);
- source->AddLocalizedString("continue", IDS_CONTINUE_EXTENSION_DOWNLOAD);
- source->AddLocalizedString("pause", IDS_DOWNLOAD_LINK_PAUSE);
- source->AddLocalizedString("resume", IDS_DOWNLOAD_LINK_RESUME);
- source->AddLocalizedString("showalldownloads",
- IDS_FILEBROWSER_SHOW_ALL_DOWNLOADS);
- source->AddLocalizedString("error_unknown_file_type",
- IDS_FILEBROWSER_ERROR_UNKNOWN_FILE_TYPE);
+class ActiveDownloadsUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ ActiveDownloadsUIHTMLSource();
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_incognito,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const {
+ return "text/html";
+ }
+
+ private:
+ ~ActiveDownloadsUIHTMLSource() {}
+
+ DISALLOW_COPY_AND_ASSIGN(ActiveDownloadsUIHTMLSource);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ActiveDownloadsUIHTMLSource
+//
+////////////////////////////////////////////////////////////////////////////////
+ActiveDownloadsUIHTMLSource::ActiveDownloadsUIHTMLSource()
+ : DataSource(chrome::kChromeUIActiveDownloadsHost, MessageLoop::current()) {
+}
+
+void ActiveDownloadsUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_incognito,
+ int request_id) {
+ DictionaryValue localized_strings;
+ localized_strings.SetString("dangerousfile",
+ l10n_util::GetStringUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD));
+ localized_strings.SetString("dangerousextension",
+ l10n_util::GetStringUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION));
+ localized_strings.SetString("dangerousurl",
+ l10n_util::GetStringUTF16(IDS_PROMPT_UNSAFE_DOWNLOAD_URL));
+ localized_strings.SetString("cancel",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_CANCEL));
+ localized_strings.SetString("discard",
+ l10n_util::GetStringUTF16(IDS_DISCARD_DOWNLOAD));
+ localized_strings.SetString("continue",
+ l10n_util::GetStringUTF16(IDS_CONTINUE_EXTENSION_DOWNLOAD));
+ localized_strings.SetString("pause",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_PAUSE));
+ localized_strings.SetString("resume",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_RESUME));
+ localized_strings.SetString("showalldownloads",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_SHOW_ALL_DOWNLOADS));
FilePath default_download_path;
if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
&default_download_path)) {
NOTREACHED();
}
// TODO(viettrungluu): this is wrong -- FilePath's need not be Unicode.
- source->AddString("downloadpath", UTF8ToUTF16(default_download_path.value()));
-
- source->set_json_path("strings.js");
- source->add_resource_path("active_downloads.js", IDR_ACTIVE_DOWNLOADS_JS);
- source->set_default_resource(IDR_ACTIVE_DOWNLOADS_HTML);
- return source;
+ localized_strings.SetString("downloadpath", default_download_path.value());
+ localized_strings.SetString("error_unknown_file_type",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_ERROR_UNKNOWN_FILE_TYPE));
+ SetFontAndTextDirection(&localized_strings);
+
+ static const base::StringPiece active_downloads_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_ACTIVE_DOWNLOADS_HTML));
+ std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
+ active_downloads_html, &localized_strings);
+
+ SendResponse(request_id, base::RefCountedString::TakeString(&full_html));
}
} // namespace
@@ -345,11 +385,11 @@ ActiveDownloadsUI::ActiveDownloadsUI(TabContents* contents)
handler_(new ActiveDownloadsHandler()) {
AddMessageHandler(handler_->Attach(this));
handler_->Init();
+ ActiveDownloadsUIHTMLSource* html_source = new ActiveDownloadsUIHTMLSource();
// Set up the chrome://active-downloads/ source.
Profile* profile = Profile::FromBrowserContext(contents->browser_context());
- profile->GetChromeURLDataManager()->AddDataSource(
- CreateActiveDownloadsUIHTMLSource());
+ profile->GetChromeURLDataManager()->AddDataSource(html_source);
}
#if defined(TOUCH_UI)
diff --git a/chrome/browser/ui/webui/chrome_url_data_manager_backend.cc b/chrome/browser/ui/webui/chrome_url_data_manager_backend.cc
index b889bde..1815c28 100644
--- a/chrome/browser/ui/webui/chrome_url_data_manager_backend.cc
+++ b/chrome/browser/ui/webui/chrome_url_data_manager_backend.cc
@@ -62,6 +62,7 @@ class ChromeURLContentSecurityPolicyExceptionSet
insert(chrome::kChromeUINewTabHost);
insert(chrome::kChromeUITextfieldsHost);
#if defined(OS_CHROMEOS)
+ insert(chrome::kChromeUIActiveDownloadsHost);
insert(chrome::kChromeUIChooseMobileNetworkHost);
insert(chrome::kChromeUIEnterpriseEnrollmentHost);
insert(chrome::kChromeUIImageBurnerHost);