Index: chrome/browser/resources/downloads.html |
=================================================================== |
--- chrome/browser/resources/downloads.html (revision 0) |
+++ chrome/browser/resources/downloads.html (revision 0) |
@@ -0,0 +1,551 @@ |
+<!DOCTYPE HTML> |
+<html id="t"> |
+<head> |
+<meta charset="utf-8"> |
+<title jscontent="title"></title> |
+<style type="text/css"> |
+body { |
+ font-family:arial; |
+ background-color:white; |
+ color:black; |
+ font-size:84%; |
+ margin:10px; |
+} |
+.header { |
+ overflow:auto; |
+ clear:both; |
+} |
+.header .logo { |
+ float:left; |
+} |
+.header .form { |
+ float:left; |
+ margin-top:22px; |
+ margin-left:12px; |
+} |
+#downloads-summary { |
+ margin-top:12px; |
+ border-top:1px solid #9cc2ef; |
+ background-color:#ebeff9; |
+ font-weight:bold; |
+ padding:3px; |
+ margin-bottom:6px; |
+} |
+#downloads-display { |
+ max-width:740px; |
+} |
+.download { |
+ position:relative; |
+ padding-left:45px; |
+ margin-bottom:16px; |
+} |
+.download .icon { |
+ position:absolute; |
+ top:2px; |
+ left:2px; |
+ width:32px; |
+ height:32px; |
+} |
+.name { |
+ display:none; |
+ padding-right:16px; |
+ max-width:450px; |
+ text-overflow:ellipsis; |
+} |
+.download .status { |
+ display:inline; |
+ color:#999; |
+} |
+.download .url { |
+ color:#080; |
+ width:500px; |
+ white-space:nowrap; |
+ overflow:hidden; |
+ text-overflow:ellipsis; |
+} |
+.controls a { |
+ color:#777; |
+} |
+#downloads-pagination { |
+ padding-top:24px; |
+ margin-left:18px; |
+} |
+.page-navigation { |
+ padding:8px; |
+ background-color:#ebeff9; |
+ margin-right:4px; |
+} |
+.footer { |
+ height:24px; |
+} |
+</style> |
+<script type="text/javascript"> |
+/////////////////////////////////////////////////////////////////////////////// |
+// localStrings: |
+/** |
+ * We get strings into the page by using JSTemplate to populate some elements |
+ * with localized content, then reading the content of those elements into |
+ * this global strings object. |
+ * @param {Node} node The DOM node containing all our strings. |
+ */ |
+function LocalStrings(node) { |
+ this.strings_ = {}; |
+ |
+ var children = node.childNodes; |
+ for (var i = 0, child; child = children[i]; i++) { |
+ var id = child.id; |
+ if (id) { |
+ this.strings_[id] = child.innerHTML; |
+ } |
+ } |
+} |
+ |
+/** |
+ * Gets a localized string by its id. |
+ * @param {string} s The id of the string we want |
+ * @return {string} The localized string |
+ */ |
+LocalStrings.prototype.getString = function(s) { |
+ return (s in this.strings_) ? this.strings_[s] : ''; |
+} |
+ |
+/** |
+ * Returns a formatted localized string (where all %s contents are replaced |
+ * by the second argument). |
+ * @param {string} s The id of the string we want |
+ * @param {string} d The string to include in the formatted string |
+ * @return {string} The formatted string. |
+ */ |
+LocalStrings.prototype.formatString = function(s, d) { |
+ return (s in this.strings_) ? this.strings_[s].replace(/\%s/, d) : ''; |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+// Helper functions |
+function $(o) {return document.getElementById(o);} |
+ |
+function bind(fn, selfObj, var_args) { |
+ var boundArgs = Array.prototype.slice.call(arguments, 2); |
+ return function() { |
+ var args = Array.prototype.slice.call(arguments); |
+ args.unshift.apply(args, boundArgs); |
+ return fn.apply(selfObj, args); |
+ } |
+} |
+ |
+/** |
+ * Sets the display style of a node. |
+ */ |
+function showInline(node, isShow) { |
+ node.style.display = isShow ? 'inline' : 'none'; |
+} |
+ |
+/** |
+ * Creates an element of a specified type with a specified class name. |
+ * @param {String} type The node type. |
+ * @param {String} className The class name to use. |
+ */ |
+function createElementWithClassName(type, className) { |
+ var elm = document.createElement(type); |
+ elm.className = className; |
+ return elm; |
+} |
+ |
+/** |
+ * Creates a link with a specified onclick handler and content |
+ * @param {String} onclick The onclick handler |
+ * @param {String} value The link text |
+ */ |
+function createLink(onclick, value) { |
+ var link = document.createElement("a"); |
+ link.onclick = onclick; |
+ link.href = '#'; |
+ link.innerHTML = value; |
+ return link; |
+} |
+ |
+/** |
+ * Creates a button with a specified onclick handler and content |
+ * @param {String} onclick The onclick handler |
+ * @param {String} value The button text |
+ */ |
+function createButton(onclick, value) { |
+ var button = document.createElement("input"); |
+ button.type = 'button'; |
+ button.value = value; |
+ button.onclick = onclick; |
+ return button; |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+// Downloads |
+/** |
+ * Class to hold all the information about the visible downloads. |
+ */ |
+function Downloads() { |
+ this.downloads_ = {}; |
+ this.node_ = $('downloads-display'); |
+ this.summary_ = $('downloads-summary'); |
+ this.searchText_ = ""; |
+} |
+ |
+/** |
+ * Called when a download has been updated or added. |
+ * @param {Object} download A backend download object (see downloads_ui.cc) |
+ */ |
+Downloads.prototype.updated = function(download) { |
+ var id = download.id; |
+ if (!!this.downloads_[id]) { |
+ this.downloads_[id].update(download); |
+ } else { |
+ this.downloads_[id] = new Download(download); |
+ // We get downloads in display order, so we don't have to worry about |
+ // maintaining correct order for now. |
+ this.node_.insertBefore(this.downloads_[id].node, |
+ this.node_.firstChild); |
+ } |
+} |
+ |
+/** |
+ * Set our display search text. |
+ * @param {String} searchText The string we're searching for. |
+ */ |
+Downloads.prototype.setSearchText = function(searchText) { |
+ this.searchText_ = searchText; |
+} |
+ |
+/** |
+ * Update the summary block above the results |
+ */ |
+Downloads.prototype.updateSummary = function() { |
+ if (this.searchText_) { |
+ this.summary_.innerHTML = localStrings.formatString( |
+ 'searchresultsfor', this.searchText_); |
+ } else { |
+ this.summary_.innerHTML = localStrings.getString('downloads'); |
+ } |
+ |
+ var hasDownloads = false; |
+ for (var i in this.downloads_) { |
+ hasDownloads = true; |
+ break; |
+ } |
+ |
+ if (!hasDownloads) { |
+ this.node_.innerHTML = localStrings.getString('noresults'); |
+ } |
+} |
+ |
+/** |
+ * Remove a download. |
+ * @param {Number} id The id of the download to remove. |
+ */ |
+Downloads.prototype.remove = function(id) { |
+ this.node_.removeChild(this.downloads_[id].node); |
+ delete this.downloads_[id]; |
+} |
+ |
+/** |
+ * Clear all downloads and reset us back to a null state. |
+ */ |
+Downloads.prototype.clear = function() { |
+ for (var id in this.downloads_) { |
+ this.downloads_[id].clear(); |
+ this.remove(id); |
+ } |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+// Download |
+/** |
+ * A download and the DOM representation for that download. |
+ * @param {Object} download A backend download object (see downloads_ui.cc) |
+ */ |
+function Download(download) { |
+ // Create DOM |
+ this.node = createElementWithClassName('div', 'download'); |
+ |
+ // Container for all 'safe download' UI. |
+ this.safe_ = document.createElement("div"); |
+ this.safe_.ondragstart = bind(this.drag_, this); |
+ this.node.appendChild(this.safe_); |
+ |
+ this.nodeImg_ = createElementWithClassName('img', 'icon'); |
+ this.safe_.appendChild(this.nodeImg_); |
+ |
+ // FileLink is used for completed downloads, otherwise we show FileName. |
+ this.nodeTitleArea_ = createElementWithClassName('div', 'title-area'); |
+ this.safe_.appendChild(this.nodeTitleArea_); |
+ |
+ this.nodeFileLink_ = createLink(bind(this.openFile_, this), ''); |
+ this.nodeFileLink_.className = 'name'; |
+ this.nodeFileLink_.style.display = 'none'; |
+ this.nodeTitleArea_.appendChild(this.nodeFileLink_); |
+ |
+ this.nodeFileName_ = createElementWithClassName('span', 'name'); |
+ this.nodeFileName_.style.display = 'none'; |
+ this.nodeTitleArea_.appendChild(this.nodeFileName_); |
+ |
+ this.nodeStatus_ = createElementWithClassName('span', 'status'); |
+ this.nodeTitleArea_.appendChild(this.nodeStatus_); |
+ |
+ this.nodeURL_ = createElementWithClassName('div', 'url'); |
+ this.safe_.appendChild(this.nodeURL_); |
+ |
+ // Controls. |
+ this.nodeControls_ = createElementWithClassName('div', 'controls'); |
+ this.safe_.appendChild(this.nodeControls_); |
+ |
+ this.controlShow_ = createLink(bind(this.show_, this), |
+ localStrings.getString('control_showinfolder')); |
+ this.nodeControls_.appendChild(this.controlShow_); |
+ |
+ this.controlPause_ = createLink(bind(this.pause_, this), |
+ localStrings.getString('control_pause')); |
+ this.nodeControls_.appendChild(this.controlPause_); |
+ |
+ this.controlCancel_ = createLink(bind(this.cancel_, this), |
+ localStrings.getString('control_cancel')); |
+ this.nodeControls_.appendChild(this.controlCancel_); |
+ |
+ // Container for 'unsafe download' UI. |
+ this.danger_ = createElementWithClassName('div', 'show-dangerous'); |
+ this.node.appendChild(this.danger_); |
+ |
+ this.dangerDesc_ = document.createElement("div"); |
+ this.danger_.appendChild(this.dangerDesc_); |
+ |
+ this.dangerSave_ = createButton(bind(this.saveDangerous_, this), |
+ localStrings.getString("danger_save")); |
+ this.danger_.appendChild(this.dangerSave_); |
+ |
+ this.dangerDiscard_ = createButton(bind(this.discardDangerous_, this), |
+ localStrings.getString("danger_discard")); |
+ this.danger_.appendChild(this.dangerDiscard_); |
+ |
+ // Update member vars. |
+ this.update(download); |
+} |
+ |
+/** |
+ * The states a download can be in. These correspond to states defined in |
+ * DownloadsDOMHandler::CreateDownloadItemValue |
+ */ |
+Download.States = { |
+ IN_PROGRESS : "IN_PROGRESS", |
+ CANCELLED : "CANCELLED", |
+ COMPLETE : "COMPLETE", |
+ PAUSED : "PAUSED", |
+ DANGEROUS : "DANGEROUS", |
+} |
+ |
+/** |
+ * Updates the download to reflect new data. |
+ * @param {Object} download A backend download object (see downloads_ui.cc) |
+ */ |
+Download.prototype.update = function(download) { |
+ this.id_ = download.id; |
+ this.filePath_ = download.file_path; |
+ this.fileName_ = download.file_name; |
+ this.url_ = download.url; |
+ this.state_ = download.state; |
+ this.percent_ = download.percent; |
+ this.speed_ = download.speed; |
+ this.received_ = download.received; |
+ |
+ if (this.state_ == Download.States.DANGEROUS) { |
+ this.dangerDesc_.innerHTML = localStrings.formatString('danger_desc', |
+ this.fileName_); |
+ this.danger_.style.display = 'block'; |
+ this.safe_.style.display = 'none'; |
+ } else { |
+ this.nodeImg_.src = 'chrome-ui://fileicon/' + this.filePath_; |
+ |
+ if (this.state_ == Download.States.COMPLETE) { |
+ this.nodeFileLink_.innerHTML = this.fileName_; |
+ this.nodeFileLink_.href = this.filePath_; |
+ } else { |
+ this.nodeFileName_.innerHTML = this.fileName_; |
+ } |
+ |
+ showInline(this.nodeFileLink_, this.state_ == Download.States.COMPLETE); |
+ showInline(this.nodeFileName_, this.state_ != Download.States.COMPLETE); |
+ |
+ showInline(this.controlShow_, this.state_ == Download.States.COMPLETE); |
+ showInline(this.controlPause_, this.state_ == Download.States.IN_PROGRESS); |
+ showInline(this.controlCancel_, this.state_ == Download.States.IN_PROGRESS); |
+ |
+ this.nodeURL_.innerHTML = this.url_; |
+ this.nodeStatus_.innerHTML = this.getStatusText_(); |
+ |
+ this.danger_.style.display = 'none'; |
+ this.safe_.style.display = 'block'; |
+ } |
+} |
+ |
+/** |
+ * Removes applicable bits from the DOM in preparation for deletion. |
+ */ |
+Download.prototype.clear = function() { |
+ this.safe_.ondragstart = null; |
+ this.nodeFileLink_.onclick = null; |
+ this.controlShow_.onclick = null; |
+ this.controlCancel_.onclick = null; |
+ this.controlPause_.onclick = null; |
+ this.dangerDiscard_.onclick = null; |
+ |
+ this.node.innerHTML = ''; |
+} |
+ |
+/** |
+ * @return {String} User-visible status update text. |
+ */ |
+Download.prototype.getStatusText_ = function() { |
+ switch (this.state_) { |
+ case Download.States.IN_PROGRESS: |
+ // TODO(glen): Make pretty, localize, etc. |
+ return this.percent_ + '% at ' + this.speed_; |
+ case Download.States.CANCELLED: |
+ return localStrings.getString('status_cancelled'); |
+ case Download.States.PAUSED: |
+ return localStrings.getString('status_paused'); |
+ case Download.States.DANGEROUS: |
+ return localStrings.getString('danger_desc'); |
+ case Download.States.COMPLETE: |
+ return ""; |
+ } |
+} |
+ |
+/** |
+ * Tells the backend to initiate a drag, allowing users to drag |
+ * files from the download page and have them appear as native file |
+ * drags. |
+ */ |
+Download.prototype.drag_ = function() { |
+ chrome.send("drag", [this.id_.toString()]); |
+ return false; |
+} |
+ |
+/** |
+ * Tells the backend to open this file. |
+ */ |
+Download.prototype.openFile_ = function() { |
+ chrome.send("openFile", [this.id_.toString()]); |
+ return false; |
+} |
+ |
+/** |
+ * Tells the backend that the user chose to save a dangerous file. |
+ */ |
+Download.prototype.saveDangerous_ = function() { |
+ chrome.send("saveDangerous", [this.id_.toString()]); |
+ return false; |
+} |
+ |
+/** |
+ * Tells the backend that the user chose to discard a dangerous file. |
+ */ |
+Download.prototype.discardDangerous_ = function() { |
+ chrome.send("discardDangerous", [this.id_.toString()]); |
+ downloads.remove(this.id_); |
+ return false; |
+} |
+ |
+/** |
+ * Tells the backend to show the file in explorer. |
+ */ |
+Download.prototype.show_ = function() { |
+ chrome.send("show", [this.id_.toString()]); |
+ return false; |
+} |
+ |
+/** |
+ * Tells the backend to pause this download. |
+ */ |
+Download.prototype.pause_ = function() { |
+ chrome.send("pause", [this.id_.toString()]); |
+ return false; |
+} |
+ |
+/** |
+ * Tells the backend to cancel this download. |
+ */ |
+Download.prototype.cancel_ = function() { |
+ chrome.send("cancel", [this.id_.toString()]); |
+ return false; |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+// Page: |
+var downloads, localStrings; |
+ |
+function load() { |
+ localStrings = new LocalStrings($('l10n')); |
+ downloads = new Downloads(); |
+ setSearch(""); |
+} |
+ |
+function setSearch(searchText) { |
+ downloads.clear(); |
+ downloads.setSearchText(searchText); |
+ chrome.send("getDownloads", [searchText.toString()]); |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+// Chrome callbacks: |
+/** |
+ * Our history system calls this function with results from searches or when |
+ * downloads are added or removed. |
+ */ |
+function downloadsList(results) { |
+ downloadUpdated(results); |
+ downloads.updateSummary(); |
+} |
+ |
+/** |
+ * When a download is updated (progress, state change), this is called. |
+ */ |
+function downloadUpdated(results) { |
+ for (var i = 0, thisResult; thisResult = results[i]; i++) { |
+ downloads.updated(thisResult); |
+ } |
+} |
+</script> |
+</head> |
+<body onload="load();"> |
+<div class="header"> |
+ <a href="" onclick="setSearch(''); return false;"> |
+ <img src="../../app/theme/downloads_section.png" |
+ width="67" height="67" class="logo" border="0" /></a> |
+ <form method="post" action="" |
+ onsubmit="setSearch(this.term.value); return false;" |
+ class="form"> |
+ <input type="text" name="term" id="term" /> |
+ <input type="submit" name="submit" jsvalues="value:searchbutton" /> |
+ </form> |
+</div> |
+<div class="main"> |
+ <div id="downloads-summary"></div> |
+ <div id="downloads-display"></div> |
+</div> |
+<div class="footer"> |
+</div> |
+<div id="l10n" style="display:none;"> |
+ <span id="searchresultsfor" jscontent="searchresultsfor">Search results for '%s'</span> |
+ <span id="no_results" jscontent="no_results">No results found.</span> |
+ <span id="downloads" jscontent="downloads">Downloads</span> |
+ |
+ <span id="status_cancelled" jscontent="status_cancelled">Cancelled</span> |
+ <span id="status_paused" jscontent="status_paused">Paused</span> |
+ |
+ <span id="danger_desc" jscontent="danger_desc">This is a dangerous file</span> |
+ <span id="danger_save" jscontent="danger_save">Save</span> |
+ <span id="danger_discard" jscontent="danger_discard">Discard</span> |
+ |
+ <span id="control_pause" jscontent="control_pause">Pause</span> |
+ <span id="control_showinfolder" jscontent="control_showinfolder">Show in folder</span> |
+ <span id="control_cancel" jscontent="control_cancel">Cancel</span> |
+ <span id="control_resume" jscontent="control_resume">Resume</span> |
+</div> |
+</body> |
+</html> |
Property changes on: chrome\browser\resources\downloads.html |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |