diff options
author | tsepez@chromium.org <tsepez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-06 21:46:24 +0000 |
---|---|---|
committer | tsepez@chromium.org <tsepez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-06 21:46:24 +0000 |
commit | 6e368e096fa3d0f1f3eedb4ee8cb7cc0eb83dd9a (patch) | |
tree | 2c3e2ba76d542889940c2e30af9ecaf9e40a50f5 /chrome/browser | |
parent | da00dc1867fb2c4e51b4f4dbaa5796a748eaf120 (diff) | |
download | chromium_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.grd | 3 | ||||
-rw-r--r-- | chrome/browser/resources/active_downloads.html | 685 | ||||
-rw-r--r-- | chrome/browser/resources/active_downloads.js | 678 | ||||
-rw-r--r-- | chrome/browser/ui/webui/active_downloads_ui.cc | 92 | ||||
-rw-r--r-- | chrome/browser/ui/webui/chrome_url_data_manager_backend.cc | 1 |
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); |