diff options
author | dgozman@chromium.org <dgozman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-30 16:45:13 +0000 |
---|---|---|
committer | dgozman@chromium.org <dgozman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-30 16:45:13 +0000 |
commit | 0d4cd065a9b3e28de6ae1e332e1b5fe1d38d6cb6 (patch) | |
tree | 4d531a08192b846f52ae4ec21d94a85783eb77f1 /chrome | |
parent | c37c498ddc13f35a7a199c4e03e6f1ec047f9c52 (diff) | |
download | chromium_src-0d4cd065a9b3e28de6ae1e332e1b5fe1d38d6cb6.zip chromium_src-0d4cd065a9b3e28de6ae1e332e1b5fe1d38d6cb6.tar.gz chromium_src-0d4cd065a9b3e28de6ae1e332e1b5fe1d38d6cb6.tar.bz2 |
[filebrowser] Changed task buttons to single dropdown. Double-click and click-on-preview for default action.
BUG=chromium-os:23582,chromium-os:17507,chromium-os:25022
TEST=See bugs.
Review URL: https://chromiumcodereview.appspot.com/9284019
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@119678 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
8 files changed, 343 insertions, 45 deletions
diff --git a/chrome/browser/extensions/extension_file_browser_private_api.cc b/chrome/browser/extensions/extension_file_browser_private_api.cc index 245b025..c2dd955 100644 --- a/chrome/browser/extensions/extension_file_browser_private_api.cc +++ b/chrome/browser/extensions/extension_file_browser_private_api.cc @@ -1624,6 +1624,9 @@ bool FileDialogStringsFunction::RunImpl() { SET_STRING(IDS_FILE_BROWSER, SAVE_LABEL); SET_STRING(IDS_FILE_BROWSER, OK_LABEL); + SET_STRING(IDS_FILE_BROWSER, ERROR_VIEWING_FILE_TITLE); + SET_STRING(IDS_FILE_BROWSER, ERROR_VIEWING_FILE); + SET_STRING(IDS_FILE_BROWSER, DEFAULT_NEW_FOLDER_NAME); SET_STRING(IDS_FILE_BROWSER, MORE_FILES); diff --git a/chrome/browser/resources/file_manager/css/combobutton.css b/chrome/browser/resources/file_manager/css/combobutton.css new file mode 100644 index 0000000..7daed67 --- /dev/null +++ b/chrome/browser/resources/file_manager/css/combobutton.css @@ -0,0 +1,110 @@ +/* + * 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. + */ + +.cr-button { + border: 1px solid #aaa; + border-radius: 2px; + font: -webkit-small-control; +} + +.cr-button:hover { + border: 1px solid #999; + -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 3px 0; +} + +.cr-button:active { + -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 3px 0 inset; +} + + + +.cr-combobutton { + position: relative; + display: none; + font: -webkit-small-control; +} + +.cr-combobutton[visible] { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-box-align: stretch; +} + +.cr-cb-container { + -webkit-box-flex: 1; + display: -webkit-box; +} + +.cr-cb-button-container { + -webkit-box-flex: 1; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-box-align: stretch; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; +} + +.cr-combobutton[open] .cr-cb-button-container { + border-top-left-radius: 0; +} + +.cr-cb-button-container > * { + background-color: rgba(0, 0, 0, 0); +} + +.cr-combobutton[open] .cr-cb-button-container:hover > * { + background-color: #f2f6fa; +} + +.cr-cb-trigger { + -webkit-box-flex: 0; + -webkit-margin-start: -1px; + width: 20px; + background-image: url('../images/disclosure_arrow_dk_grey_down.png'); + background-repeat: no-repeat; + background-position: center; + display: none; + border-top-left-radius: 0px; + border-bottom-left-radius: 0px; +} + +.cr-combobutton[multiple] .cr-cb-trigger { + display: block; +} + +.cr-combobutton[open] .cr-cb-trigger { + border-top-right-radius: 0; +} + +.cr-cb-popup { + position: absolute; + left: 0; + right: 0; + display: none; + -webkit-box-orient: vertical; + -webkit-box-align: stretch; + + border: 1px solid #aaa; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + border-bottom-width: 0; +} + +.cr-cb-popup:active { + box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.1); +} + +.cr-combobutton[open] .cr-cb-popup { + display: -webkit-box; +} + +.cr-cb-popup > * { + background-color: white; +} + +.cr-cb-popup > *:hover { + background-color: #f2f6fa; +} diff --git a/chrome/browser/resources/file_manager/css/file_manager.css b/chrome/browser/resources/file_manager/css/file_manager.css index 9cf64a0..ba2df36 100644 --- a/chrome/browser/resources/file_manager/css/file_manager.css +++ b/chrome/browser/resources/file_manager/css/file_manager.css @@ -529,6 +529,7 @@ input.rename { .preview-panel { -webkit-box-orient: horizontal; display: -webkit-box; + -webkit-box-align: center; height: 61px; background-color: #F0F0F0; padding: 0 14px; @@ -598,11 +599,6 @@ input.rename { pointer-events: auto; } -.preview-panel > * { - display: -webkit-box; - -webkit-box-align: center; -} - /* cr.ui.Table has a black focus border by default, which we don't want. */ .detail-table:focus { border: 0; @@ -803,28 +799,31 @@ li.table-row { -webkit-margin-end: 6px; } -/* The task buttons at the bottom of the preview pane. */ -.task-buttons { +.preview-panel .spacer { -webkit-box-flex: 1; - overflow: hidden; +} - display: -webkit-box; - -webkit-box-orient: horizontal; - -webkit-box-pack: end; +.delete-button { + -webkit-margin-start: 4px; + -webkit-margin-end: 4px; } -.task-button { +.task-item { display: -webkit-box; -webkit-box-orient: horizontal; - -webkit-margin-end: 4px; - -webkit-margin-start: 4px; - height: 29px; + -webkit-box-align: center; text-align: left; - vertical-align: middle; - padding: 6px; + padding: 5px; +} + +.task-item > div { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + padding-right: 5px; } -.task-button > img { +.task-item > img { -webkit-margin-end: 5px; } diff --git a/chrome/browser/resources/file_manager/images/disclosure_arrow_dk_grey_down.png b/chrome/browser/resources/file_manager/images/disclosure_arrow_dk_grey_down.png Binary files differnew file mode 100644 index 0000000..88f9bde --- /dev/null +++ b/chrome/browser/resources/file_manager/images/disclosure_arrow_dk_grey_down.png diff --git a/chrome/browser/resources/file_manager/js/combobutton.js b/chrome/browser/resources/file_manager/js/combobutton.js new file mode 100644 index 0000000..a0324d5 --- /dev/null +++ b/chrome/browser/resources/file_manager/js/combobutton.js @@ -0,0 +1,142 @@ +// Copyright (c) 2012 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. + +/** + * @fileoverview This implements a combobutton control. + */ + +cr.define('cr.ui', function() { + /** + * Creates a new combobutton element. + * @param {Object=} opt_propertyBag Optional properties. + * @constructor + * @extends {HTMLUListElement} + */ + var ComboButton = cr.ui.define('div'); + + ComboButton.prototype = { + __proto__: HTMLDivElement.prototype, + + /** + * The items list. + */ + items_: null, + + clear: function() { + this.items_ = []; + this.popup_.textContent = ''; + this.buttonContainer_.textContent = ''; + this.multiple = false; + }, + + addItem: function(item) { + this.items_.push(item); + if (this.items_.length == 1) { + this.buttonContainer_.appendChild(item); + } else { + this.multiple = true; + if (this.visible) + this.popup_.style.bottom = this.clientHeight + 'px'; + if (this.popup_.hasChildNodes()) + this.popup_.insertBefore(item, this.popup_.firstChild); + else + this.popup_.appendChild(item); + } + }, + + /** + * Initializes the element. + */ + decorate: function() { + this.items_ = []; + + this.classList.add('cr-combobutton'); + + this.container_ = this.ownerDocument.createElement('div'); + this.container_.className = 'cr-cb-container'; + this.buttonContainer_ = this.ownerDocument.createElement('div'); + this.buttonContainer_.className = 'cr-button cr-cb-button-container'; + this.trigger_ = this.ownerDocument.createElement('div'); + this.trigger_.className = 'cr-button cr-cb-trigger'; + this.container_.appendChild(this.buttonContainer_); + this.container_.appendChild(this.trigger_); + + this.popup_ = this.ownerDocument.createElement('div'); + this.popup_.className = 'cr-cb-popup'; + + this.textContent = ''; + this.appendChild(this.container_); + this.appendChild(this.popup_); + + this.buttonContainer_.addEventListener('click', + this.handleButtonClick_.bind(this)); + this.popup_.addEventListener('click', + this.handlePopupClick_.bind(this)); + this.trigger_.addEventListener('click', + this.handleTriggerClicked_.bind(this)); + this.addEventListener('mouseout', this.handleMouseOut_.bind(this)); + this.popup_.addEventListener('mouseout', + this.handleMouseOut_.bind(this)); + + this.visible = true; + }, + + handleTriggerClicked_: function(event) { + this.open = !this.open; + }, + + handleMouseOut_: function(event) { + var x = event.x; + var y = event.y; + var r = this.popup_.getBoundingClientRect(); + if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom) + return; + r = this.container_.getBoundingClientRect(); + if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom) + return; + this.open = false; + }, + + handleButtonClick_: function(event) { + this.dispatchSelectEvent(this.items_[0]); + }, + + handlePopupClick_: function(event) { + var item = event.target; + while (item && item.parentNode != this.popup_) + item = item.parentNode; + if (!item) + return; + + this.open = false; + this.dispatchSelectEvent(item); + }, + + dispatchSelectEvent: function(item) { + var selectEvent = new Event('select'); + selectEvent.item = item; + this.dispatchEvent(selectEvent); + }, + + get visible() { + return this.hasAttribute('visible'); + }, + set visible(value) { + if (value) { + this.setAttribute('visible', 'visible'); + this.popup_.style.bottom = this.clientHeight + 'px'; + } else { + this.removeAttribute('visible'); + } + } + }; + + cr.defineProperty(ComboButton, 'disabled', cr.PropertyKind.BOOL_ATTR); + cr.defineProperty(ComboButton, 'open', cr.PropertyKind.BOOL_ATTR); + cr.defineProperty(ComboButton, 'multiple', cr.PropertyKind.BOOL_ATTR); + + return { + ComboButton: ComboButton + } +}); diff --git a/chrome/browser/resources/file_manager/js/file_manager.js b/chrome/browser/resources/file_manager/js/file_manager.js index bbbf127..a049159 100644 --- a/chrome/browser/resources/file_manager/js/file_manager.js +++ b/chrome/browser/resources/file_manager/js/file_manager.js @@ -629,7 +629,7 @@ FileManager.prototype = { this.previewFilename_ = this.dialogDom_.querySelector('.preview-filename'); this.previewSummary_ = this.dialogDom_.querySelector('.preview-summary'); this.filenameInput_ = this.dialogDom_.querySelector('.filename-input'); - this.taskButtons_ = this.dialogDom_.querySelector('.task-buttons'); + this.taskItems_ = this.dialogDom_.querySelector('.tasks'); this.okButton_ = this.dialogDom_.querySelector('.ok'); this.cancelButton_ = this.dialogDom_.querySelector('.cancel'); this.deleteButton_ = this.dialogDom_.querySelector('.delete-button'); @@ -678,6 +678,10 @@ FileManager.prototype = { this.dialogDom_.querySelector('button.thumbnail-view').addEventListener( 'click', this.onThumbnailViewButtonClick_.bind(this)); + cr.ui.ComboButton.decorate(this.taskItems_); + this.taskItems_.addEventListener('select', + this.onTaskItemClicked_.bind(this)); + this.dialogDom_.ownerDocument.defaultView.addEventListener( 'resize', this.onResize_.bind(this)); @@ -1788,7 +1792,8 @@ FileManager.prototype = { // Removing childrens of task buttons and preview thumbnails after simple // event dispatched (see above). This can ensure a smooth disappearing // animation when nothing is selected. - removeChildren(this.taskButtons_); + this.taskItems_.visible = false; + this.taskItems_.clear(); removeChildren(this.previewThumbnails_); var fileCount = 0; @@ -1819,6 +1824,7 @@ FileManager.prototype = { var thumbnail = this.renderThumbnailBox_(entry, true, imageLoadCalback); box.appendChild(thumbnail); box.style.zIndex = MAX_PREVIEW_THUMBAIL_COUNT + 1 - i; + box.addEventListener('click', this.dispatchDefaultTask_.bind(this)); this.previewThumbnails_.appendChild(box); thumbnailCount++; @@ -1866,7 +1872,7 @@ FileManager.prototype = { } if (this.dialogType_ == FileManager.DialogType.FULL_PAGE) { - removeChildren(this.taskButtons_); + this.taskItems_.clear(); // Some internal tasks cannot be defined in terms of file patterns, // so we pass selection to check for them manually. if (selection.directoryCount == 0 && selection.fileCount > 0) { @@ -2022,7 +2028,7 @@ FileManager.prototype = { * @param {Array.<Task>} tasksList The tasks list. */ FileManager.prototype.onTasksFound_ = function(selection, tasksList) { - removeChildren(this.taskButtons_); + this.taskItems_.clear(); for (var i = 0; i < tasksList.length; i++) { var task = tasksList[i]; @@ -2054,29 +2060,42 @@ FileManager.prototype = { this.galleryTask_ = task; } } - this.renderTaskButton_(task); + this.renderTaskItem_(task); } + this.taskItems_.visible = tasksList.length > 0; + + selection.tasksList = tasksList; + if (selection.dispatchDefault) { + // We got a request to dispatch the default task for the selection. + selection.dispatchDefault = false; + if (tasksList.length > 0) { + this.dispatchFileTask_(tasksList[0], selection.urls); + } else { + this.alert.showWithTitle( + strf('ERROR_VIEWING_FILE_TITLE', selection.entries[0].name), + strf('ERROR_VIEWING_FILE')); + } + } // These are done in separate functions, as the checks require // asynchronous function calls. this.maybeRenderFormattingTask_(selection); }; - FileManager.prototype.renderTaskButton_ = function(task) { - var button = this.document_.createElement('button'); - button.addEventListener('click', - this.onTaskButtonClicked_.bind(this, task)); - button.className = 'task-button'; + FileManager.prototype.renderTaskItem_ = function(task) { + var item = this.document_.createElement('div'); + item.className = 'task-item'; + item.task = task; var img = this.document_.createElement('img'); img.src = task.iconUrl; + item.appendChild(img); - button.appendChild(img); var label = this.document_.createElement('div'); - label.appendChild(this.document_.createTextNode(task.title)) - button.appendChild(label); + label.appendChild(this.document_.createTextNode(task.title)); + item.appendChild(label); - this.taskButtons_.appendChild(button); + this.taskItems_.addItem(item); }; /** @@ -2106,7 +2125,7 @@ FileManager.prototype = { title: str('FORMAT_DEVICE'), internal: true }; - self.renderTaskButton_(task); + self.renderTaskItem_(task); } } @@ -2138,19 +2157,34 @@ FileManager.prototype = { } }; - FileManager.prototype.onTaskButtonClicked_ = function(task, event) { - this.dispatchFileTask_(task, this.selection.urls); + FileManager.prototype.onTaskItemClicked_ = function(event) { + this.dispatchFileTask_(event.item.task, this.selection.urls); + }; + + /** + * Dispatches default task for the current selection. If tasks are not ready + * yet, dispatches after task are available. + */ + FileManager.prototype.dispatchDefaultTask_ = function() { + if (this.selection.tasksList) { + if (this.selection.tasksList.length > 0 && this.selection.urls.length > 0) + this.dispatchFileTask_(this.selection.tasksList[0], + this.selection.urls); + } else { + // Request to dispatch default task after we get all the tasks. + this.selection.dispatchDefault = true; + } }; FileManager.prototype.dispatchFileTask_ = function(task, urls) { + chrome.fileBrowserPrivate.executeTask(task.taskId, urls); if (task.internal) { - // For internal tasks call the handler directly to avoid being handled - // multiple times. + // For internal tasks we do not listen to the event to avoid + // handling the same task instance from multiple tabs. + // So, we manually execute the task. var taskId = task.taskId.split('|')[1]; this.onFileTaskExecute_(taskId, {urls: urls, task: task}); - return; } - chrome.fileBrowserPrivate.executeTask(task.taskId, urls); }; /** @@ -2824,9 +2858,12 @@ FileManager.prototype = { return this.onDirectoryAction(entry); } - if (!this.okButton_.disabled) - this.onOk_(); - + if (this.dialogType_ == FileManager.DialogType.FULL_PAGE) { + this.dispatchDefaultTask_(); + } else { + if (!this.okButton_.disabled) + this.onOk_(); + } }; FileManager.prototype.onDirectoryAction = function(entry) { diff --git a/chrome/browser/resources/file_manager/js/mock_chrome.js b/chrome/browser/resources/file_manager/js/mock_chrome.js index ac4eaaa..0fd2075 100644 --- a/chrome/browser/resources/file_manager/js/mock_chrome.js +++ b/chrome/browser/resources/file_manager/js/mock_chrome.js @@ -298,6 +298,9 @@ chrome.fileBrowserPrivate = { OPEN_LABEL: 'Open', SAVE_LABEL: 'Save', OK_LABEL: 'OK', + ERROR_VIEWING_FILE_TITLE: '$1', + ERROR_VIEWING_FILE: 'To view this file, convert it to a format that\'s ' + + 'viewable on the web. For example, you can upload it to Google Docs.', DEFAULT_NEW_FOLDER_NAME: 'New Folder', MORE_FILES: 'Show all files', diff --git a/chrome/browser/resources/file_manager/main.html b/chrome/browser/resources/file_manager/main.html index 9ee92e6..001a820 100644 --- a/chrome/browser/resources/file_manager/main.html +++ b/chrome/browser/resources/file_manager/main.html @@ -84,6 +84,9 @@ <script src="../shared/js/cr/ui/menu.js"></script> <script src="../shared/js/cr/ui/context_menu_handler.js"></script> + <script src="js/combobutton.js"></script> + <link rel="stylesheet" href="css/combobutton.css"></link> + <link rel="stylesheet" href="css/file_manager.css"></link> <script src="js/util.js"></script> @@ -176,15 +179,16 @@ <div class=preview-panel visibility=hidden> <div><div class=preview-thumbnails></div></div> <div><div class=preview-summary></div></div> - <div class=task-buttons></div> + <div class=spacer></div> + <div class=tasks></div> <div> - <button class='delete-button task-button' command='#delete' + <div class='delete-button cr-button task-item' command='#delete' onclick='fileManager.deleteEntries( fileManager.selection.entries, false)' visibleif='this.dialogType_ == "full-page"' ><img src='images/button-icon-delete.png' ><div i18n-content=DELETE_BUTTON_LABEL></div - ></button> + ></div> </div> </div> </div> |