diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/chrome/browser/resources/file_manager/foreground | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/chrome/browser/resources/file_manager/foreground')
423 files changed, 0 insertions, 41748 deletions
diff --git a/chromium/chrome/browser/resources/file_manager/foreground/css/action_choice.css b/chromium/chrome/browser/resources/file_manager/foreground/css/action_choice.css deleted file mode 100644 index 508809c520d..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/css/action_choice.css +++ /dev/null @@ -1,172 +0,0 @@ -/* 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. */ - -input:focus, -button:focus { - outline-color: rgb(77, 144, 254); -} - -.action-choice { - -webkit-box-align: center; - -webkit-box-pack: center; - -webkit-user-select: none; - background: white; - bottom: 0; - color: black; - display: -webkit-box; - font-family: Open Sans, Droid Sans Fallback, sans-serif; - font-size: 84%; - left: 0; - margin: 0; - overflow: hidden; - padding: 10px; - position: absolute; - right: 0; - top: 0; -} - -.action-choice[loading] .content, -.action-choice:not([loading]) .loading { - display: none; -} - -.action-choice h1 { - font-size: 14px; - font-weight: normal; - line-height: 1.5; - margin: 5px 3px; -} - -/* The loading preview */ - -.loading { - -webkit-box-align: center; - -webkit-box-orient: vertical; - color: #333; - display: -webkit-box; - font-size: 12px; -} - -.spinner { - background-image: url('../images/common/spinner.svg'); - background-size: 100%; - height: 21px; - left: 44px; - margin-left: -10px; - margin-top: -10px; - opacity: 0.5; - position: absolute; - top: 29px; - width: 21px; -} - -.device-type { - height: 64px; - position: relative; - width: 116px; -} - -.device-type[device-type=usb] { - background-image: -webkit-image-set( - url('../images/volumes/device_usb_large.png') 1x, - url('../images/volumes/2x/device_usb_large.png') 2x); -} - -.device-type[device-type=sd] { - -webkit-transform: rotate(-90deg); - background-image: -webkit-image-set( - url('../images/volumes/device_sd_large.png') 1x, - url('../images/volumes/2x/device_sd_large.png') 2x); - bottom: 10px; /* Adjust the rotated image to not overlap with element below */ -} - -/* The action choice content */ - -.content { - -webkit-box-align: start; - -webkit-box-orient: vertical; - display: -webkit-box; - height: 100%; - overflow: hidden; - position: relative; - width: 100%; -} - -.previews { - -webkit-box-orient: horizontal; - -webkit-mask-image: linear-gradient(to left, rgba(0, 0, 0, 0) 0, - rgba(0, 0, 0, 1) 80px); - display: -webkit-box; - position: relative; - width: 100%; -} - -.img-container { - height: 120px; - margin: 0 2px; - overflow: hidden; - position: relative; - width: 120px; -} - -.img-container > img { - -webkit-user-drag: none; - position: absolute; -} - -.counter { - color: #808080; - margin: 5px 3px; - width: 100%; -} - -.choices { - width: 100%; -} - -/* Padding counterweights negative margins of items, thus eliminating scroll - bar when it's not needed. Max height is set to fit 8 items before showing - scroll bar. */ -#actions-list { - display: block; - max-height: 328px; - outline: none; - overflow: auto; - padding: 1px 0; - position: relative; -} - -#actions-list > li { - cursor: default; - list-style-type: none; -} - -#actions-list > li > div { - background-position: 5px center; - background-repeat: no-repeat; - line-height: 39px; - padding-left: 43px; -} - -#actions-list > [selected] { - background-color: #dedede; -} - -#actions-list:focus > [selected] { - background-color: rgb(203, 219, 241); -} - -#actions-list > [selected]:hover { - background-color: rgb(193, 211, 236); - border-color: hsl(214, 91%, 85%); -} - -#actions-list > :hover { - background-color: #f1f1f1; - border-color: hsl(214, 91%, 85%); -} - -#actions-list > li > div.disabled { - opacity: 0.5; -} diff --git a/chromium/chrome/browser/resources/file_manager/foreground/css/audio_player.css b/chromium/chrome/browser/resources/file_manager/foreground/css/audio_player.css deleted file mode 100644 index 1f6b7bbfb91..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/css/audio_player.css +++ /dev/null @@ -1,404 +0,0 @@ -/* 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. */ - -body { - -webkit-user-select: none; - overflow: hidden; - padding: 0; -} - -.audio-player { - background-color: #1d1d1d; - bottom: 0; - color: white; - cursor: default; - font-family: Open Sans, Droid Sans Fallback, sans-serif; - font-size: 10pt; - left: 0; - position: absolute; - right: 0; - top: 0; -} - -/* Title buttons. - * In the collapsed/single-track mode they overlap the first track. */ - -.title-button { - background-position: center center; - background-repeat: no-repeat; - cursor: pointer; - height: 29px; - opacity: 0.4; - position: absolute; - top: 0; - width: 29px; - z-index: 2; -} - -.title-button:hover { - background-color: rgb(60, 126, 255) !important; - opacity: 1; -} - -.audio-player:not(.collapsed):not(.single-track) > .title-button { - background-color: #1f1f1f; -} - -.title-button.close { - background-image: -webkit-image-set( - url('../images/media/media_close.png') 1x, - url('../images/media/2x/media_close.png') 2x); - right: 0; -} - -.title-button.collapse { - background-image: -webkit-image-set( - url('../images/media/media_collapse.png') 1x, - url('../images/media/2x/media_collapse.png') 2x); - right: 0; -} - -.audio-player:not(.frameless) .title-button.close { - display: none; -} - -.audio-player.frameless .title-button.collapse { - right: 29px; -} - -.collapsed .title-button.collapse { - background-image: -webkit-image-set( - url('../images/media/media_expand.png') 1x, - url('../images/media/2x/media_expand.png') 2x); -} - -.single-track .title-button.collapse { - display: none; -} - -/* Common properties for track containers. */ -.audio-player > .track-list, -.audio-player > .track-stack { - bottom: 35px; /* Room for the controls bar. */ - left: 0; - position: absolute; - right: 0; -} - -/* Scrollable list of tracks. - * Displayed in expanded mode if there is more than one track. */ -.audio-player > .track-list { - -webkit-box-align: center; - -webkit-box-orient: vertical; - -webkit-box-pack: start; - display: -webkit-box; - overflow-x: hidden; - overflow-y: auto; - top: 0; -} - -/* A single track container. - * Displayed in the compact mode or when there is only one track. */ -.audio-player > .track-stack { - height: 58px; -} - -.audio-player.collapsed > .track-list, -.audio-player.single_track > .track-list, -.audio-player:not(.collapsed):not(.single-track) > .track-stack { - opacity: 0; - pointer-events: none; -} - -/* Track item. */ -.track { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: start; - display: -webkit-box; - height: 58px; - width: 100%; -} - -/* In the expanded mode the selected track is highlighted. */ -.track-list .track.selected { - background-color: #2d2d2d; -} - -.track-list .track:hover { - background-color: #272727 !important; -} - -.track-list .track:not(.selected) .data { - opacity: 0.7; -} - -/* In the compact mode all tracks are in the same position, only the selected - is visible.*/ -.track-stack > .track { - position: absolute; - top: 0; -} - -.track-stack > .track.selected { - z-index: 1; -} - -/* Opacity transition is controlled differently for the text and the artwork. - * Text transition looks better if fade-in and fade-out go in parallel. - * For the artwork we start fading out the old icon only after the new one - * is completely opaque (otherwise when transitioning between identical icons - * we see some fading because the background transpires). */ -.track-stack > .track:not(.selected) .data, -.track-stack > .track:not(.visible) .art { - opacity: 0; - transition: opacity 220ms ease-out; -} - -/* Track data. */ - -.track .art { - box-sizing: border-box; - height: 48px; - margin: 4px 0 6px 4px; - position: relative; - width: 48px; -} - -.track .art.blank { - background-color: #111; - border: 1px solid #333; -} - -.track .art img { - height: 100%; - width: 100%; -} - -.track .art.blank img { - display: none; -} - -.track .art.error { - background-image: -webkit-image-set( - url('../images/media/error.png') 1x, - url('../images/media/2x/error.png') 2x); - background-position: center center; - background-repeat: no-repeat; -} - -.noart .track .art { - display: none; -} - -.track .data { - -webkit-box-flex: 1; - -webkit-box-orient: vertical; - -webkit-box-pack: center; - display: -webkit-box; - margin-left: 8px; - margin-right: 4px; -} - -.track .data .data-title, -.track .data .data-artist { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.track .data .data-title { - font-weight: bold; -} - -/* TODO(kaznacheev): Set to 20px when the audio player is title-less. */ -.single-track .data-title { - padding-right: 0; -} - -/* TODO(kaznacheev): Set to 50px when the audio player is title-less. */ -.collapsed:not(.single-track) .data-title { - padding-right: 20px; -} - -/* Controls bar. */ - -.audio-controls { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - background-color: #2D2D2D; - border-top: 1px solid rgba(255, 255, 255, 0.1); - bottom: 0; - display: -webkit-box; - height: 30px; - left: 0; - padding: 0 0 4px 13px; - position: absolute; - right: 0; -} - -.audio-controls .media-button { - height: 29px; - margin-top: 1px; - width: 29px; -} - -.audio-controls .media-button.play { - margin-left: -10px; - margin-right: -8px; -} - -.audio-controls .media-button.play > .default.normal, -.audio-controls .media-button.play > .ended.normal { - background-image: -webkit-image-set( - url('../images/media/media_play_audio.png') 1x, - url('../images/media/2x/media_play_audio.png') 2x); -} - -.audio-controls .media-button.play > .default.hover, -.audio-controls .media-button.play > .ended.hover { - background-image: -webkit-image-set( - url('../images/media/media_play_audio_hover.png') 1x, - url('../images/media/2x/media_play_audio_hover.png') 2x); -} - -.audio-controls .media-button.play > .default.active, -.audio-controls .media-button.play > .ended.active { - background-image: -webkit-image-set( - url('../images/media/media_play_audio_down.png') 1x, - url('../images/media/2x/media_play_audio_down.png') 2x); -} - -.audio-controls .media-button.play > .playing.normal { - background-image: -webkit-image-set( - url('../images/media/media_pause_audio.png') 1x, - url('../images/media/2x/media_pause_audio.png') 2x); -} - -.audio-controls .media-button.play > .playing.hover { - background-image: -webkit-image-set( - url('../images/media/media_pause_audio_hover.png') 1x, - url('../images/media/2x/media_pause_audio_hover.png') 2x); -} - -.audio-controls .media-button.play > .playing.active { - background-image: -webkit-image-set( - url('../images/media/media_pause_audio_down.png') 1x, - url('../images/media/2x/media_pause_audio_down.png') 2x); -} - -.audio-controls .time-controls { - margin-left: 10px; - margin-right: 9px; -} - -.audio-controls .time-controls .time { - margin-left: 11px; -} - -.media-button.previous { - margin-left: -2px; -} - -.media-button.previous > .normal { - background-image: -webkit-image-set( - url('../images/media/media_previous.png') 1x, - url('../images/media/2x/media_previous.png') 2x); -} - -.media-button.previous > .hover { - background-image: -webkit-image-set( - url('../images/media/media_previous_hover.png') 1x, - url('../images/media/2x/media_previous_hover.png') 2x); -} - -.media-button.previous > .active { - background-image: -webkit-image-set( - url('../images/media/media_previous_down.png') 1x, - url('../images/media/2x/media_previous_down.png') 2x); -} - -.media-button.next { - margin-right: -2px; -} - -.media-button.next > .normal { - background-image: -webkit-image-set( - url('../images/media/media_next.png') 1x, - url('../images/media/2x/media_next.png') 2x); -} - -.media-button.next > .hover { - background-image: -webkit-image-set( - url('../images/media/media_next_hover.png') 1x, - url('../images/media/2x/media_next_hover.png') 2x); -} - -.media-button.next > .active { - background-image: -webkit-image-set( - url('../images/media/media_next_down.png') 1x, - url('../images/media/2x/media_next_down.png') 2x); -} - -.single-track .media-button.next, -.single-track .media-button.previous { - display: none; -} - -/* Customized scrollbar for the playlist. */ - -::-webkit-scrollbar { - height: 16px; - width: 16px; -} - -::-webkit-scrollbar-button { - height: 0; - width: 0; -} - -::-webkit-scrollbar-thumb { - background-clip: padding-box; - background-color: rgba(255, 255, 255, 0.15); - box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.10), - inset 0 -1px 0 rgba(0, 0, 0, 0.07); - min-height: 28px; - padding-top: 100px; -} - -::-webkit-scrollbar-thumb:hover { - background-color: rgba(255,255,255,0.20); - box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.25); -} - -::-webkit-scrollbar-thumb:active { - background-color: rgba(255, 255, 255, 0.25); - box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.35); -} - -::-webkit-scrollbar-thumb:vertical { - border-bottom: 0 solid transparent; - border-left: 5px solid transparent; - border-right: 0 solid transparent; - border-top: 0 solid transparent; -} - -::-webkit-scrollbar-track:hover { - background-color: rgba(0, 0, 0, 0.05); - box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.10); -} - -::-webkit-scrollbar-track:active { - background-color: rgba(0, 0, 0, 0.05); - box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.14), - inset -1px -1px 0 rgba(0, 0, 0, 0.07); -} - -::-webkit-scrollbar-track:vertical { - background-clip: padding-box; - background-color: transparent; - border-left: 5px solid transparent; - border-right: 0 solid transparent; -} diff --git a/chromium/chrome/browser/resources/file_manager/foreground/css/combobutton.css b/chromium/chrome/browser/resources/file_manager/foreground/css/combobutton.css deleted file mode 100644 index 2651aad6bbb..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/css/combobutton.css +++ /dev/null @@ -1,34 +0,0 @@ -/* 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. */ - -.buttonbar button.combobutton { - -webkit-box-align: stretch; - display: -webkit-box; -} - -.buttonbar .combobutton > .action { - background-position: left center; - background-repeat: no-repeat; - background-size: 16px 16px; - padding-left: 21px; -} - -.buttonbar .combobutton > .trigger { - border-left: solid 1px #dcdcdc; - margin-left: 8px; - margin-right: -8px; - width: 22px; -} - -.buttonbar .combobutton:not([multiple]) > .trigger { - display: none; -} - -.buttonbar .combobutton > div > span.disclosureindicator { - -webkit-transform: rotate(90deg); -} - -.buttonbar .combobutton[hidden] { - display: none; -} diff --git a/chromium/chrome/browser/resources/file_manager/foreground/css/common.css b/chromium/chrome/browser/resources/file_manager/foreground/css/common.css deleted file mode 100644 index e9051864258..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/css/common.css +++ /dev/null @@ -1,501 +0,0 @@ -/* 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. */ - -/* Special attribute to hide elements. */ -[hidden] { - display: none !important; -} - -/* This file contains "borrowed" copy of standard styles. To simplify merging, - * when altering, please preserve original property value by adding comments. */ -input.common[type='checkbox'], -input.common[type='radio'] { - -webkit-appearance: none; - border: 1px solid #555; - border-radius: 1px; - box-sizing: border-box; - cursor: default; - height: 13px; - margin: 0; - opacity: 0.4; - width: 13px; -} - -input.common[type='checkbox']:hover, -input.common[type='checkbox']:checked, -input.common[type='radio']:hover, -input.common[type='radio']:checked { - opacity: 1; -} - -input.common[type='checkbox'] { - position: relative; -} - -input.common[type='checkbox']:checked::after { - background-image: -webkit-image-set( - url('../images/common/check_no_box.png') 1x, - url('../images/common/2x/check_no_box.png') 2x); - background-position: -3px -4px; - background-repeat: no-repeat; -} - -input.common[type='checkbox'].white { - border: none; -} - -input.common[type='checkbox'].white:not(:checked)::after { - background-image: -webkit-image-set( - url('../images/common/checkbox_white_unchecked.png') 1x, - url('../images/common/2x/checkbox_white_unchecked.png') 2x); - background-position: -1px 0; -} - -input.common[type='checkbox'].white:checked::after { - background-image: -webkit-image-set( - url('../images/common/checkbox_white_checked.png') 1x, - url('../images/common/2x/checkbox_white_checked.png') 2x); - background-position: -1px 0; -} - -input.common[type='checkbox']::after { - content: ''; - display: -webkit-box; - height: 15px; - left: -2px; - position: absolute; - top: -2px; - width: 17px; -} - -.bubble { - background: #FFF; - border-radius: 2px; - cursor: default; - outline: 1px solid rgba(0, 0, 0, 0.2); - padding: 16px; -} - -.bubble .pointer { - background: -webkit-image-set( - url('../images/common/bubble_point_white.png') 1x, - url('../images/common/2x/bubble_point_white.png') 2x); - display: block; - height: 11px; - left: 24px; - margin: 0 0 0 -5px; - outline: none; - position: absolute; - width: 17px; -} - -.bubble .pointer:not(.bottom) { - top: -11px; -} - -.bubble .pointer.bottom { - -webkit-transform: rotate(180deg); - bottom: -11px; -} - -.bubble .close-x { - background: -webkit-image-set( - url('../images/common/close_x_gray.png') 1x, - url('../images/common/2x/close_x_gray.png') 2x); - height: 21px; - opacity: 0.3; - position: absolute; - right: 3px; - top: 3px; - width: 21px; -} - -.bubble .close-x:hover { - opacity: 0.7; -} - -.buttonbar { - display: -webkit-box; - height: 31px; -} - -.buttonbar button:active img { - opacity: 1.0; -} - -.buttonbar button:hover img { - opacity: 0.72; -} - -.buttonbar button[disabled] img { - opacity: 0.9; -} - -.buttonbar button img { - display: inline-block; - margin: -3px 0 0; - opacity: 0.55; - vertical-align: middle; -} - -.buttonbar button.menubutton span.disclosureindicator { - -webkit-transform: rotate(90deg); - float: right; - margin-left: 7px; - margin-top: 10px; - opacity: .8; - transition: none; -} - -span.disclosureindicator { - background-image: -webkit-image-set( - url('../images/common/disclosure_arrow_dk_grey.png') 1x, - url('../images/common/2x/disclosure_arrow_dk_grey.png') 2x); - background-position: center; - background-repeat: no-repeat; - display: inline-block; - height: 7px; - width: 5px; -} - -/* "chrome-menu" class overrides some standard menu.css styles, to make custom - menus in FileBrowser look like native ChromeOS menus. */ - -menu.chrome-menu { - background-color: rgb(250, 250, 250); - border-radius: 3px; - box-shadow: 0 1px 4px 0 rgba(0, 0, 0, .5); - color: rgb(34, 34, 34); - outline: none; - overflow: hidden; - padding: 5px 0; - transition: opacity 200ms ease-in; - z-index: 600; /* Must be below the overlay pane (1000). */ -} - -menu.chrome-menu[hidden] { - display: block !important; /* Overrides default [hidden] for animation. */ - opacity: 0; - pointer-events: none; - visibility: hidden; -} - -menu.chrome-menu.hide-delayed[hidden] { - transition-delay: 120ms; - transition-property: opacity, visibility; -} - -menu.chrome-menu > :not(hr) { - background-position: right 10px center; - background-repeat: no-repeat; - line-height: 30px; - padding-left: 20px; - padding-right: 20px; -} - -menu.chrome-menu > .menuitem-button { - background-position: center; - background-repeat: no-repeat; - border: 1px solid rgb(235, 235, 235); - height: 42px; - margin: -36px -1px -1px 0; - min-width: 60px; - padding: 0; - position: absolute; - width: 60px; -} - -menu.chrome-menu > .menuitem-button[checked] { - background-color: rgb(235, 235, 235); -} - -menu.chrome-menu > .menuitem-button.left { - right: 59px; -} - -menu.chrome-menu > .menuitem-button.right { - right: 0; -} - -menu.chrome-menu > menuitem[disabled] { - color: rgb(153, 153, 153); -} - -menu.chrome-menu > menuitem:not([disabled])[selected], -menu.chrome-menu > menuitem:not([disabled])[selected]:active { - background-color: rgb(66, 129, 244); - color: white; -} - -menu.chrome-menu > hr { - background: rgb(235, 235, 235); - height: 1px; - margin: 5px 0; -} - -menu.chrome-menu > menuitem[checked] { - background-image: -webkit-image-set( - url('../images/common/check_no_box.png') 1x, - url('../images/common/2x/check_no_box.png') 2x); -} - -menu.chrome-menu > [checked]::before { - display: none; -} - -menu[showShortcuts] > menuitem[shortcutText][selected]:not([disabled])::after { - color: white; -} - -/** - * Ok/Cancel style buttons - * Height: 31px (content:21px + border:5px * 2) - **/ -button, -input[type='button'], -input[type='submit'], -select { - background-color: rgb(250, 250, 250); - background-image: none; - background-position: center; - background-repeat: no-repeat; - border: 5px solid transparent; - border-image: -webkit-image-set( - url('chrome://resources/images/apps/button.png') 1x, - url('chrome://resources/images/2x/apps/button.png') - 2x) 5 / 5px / 2px repeat; - box-sizing: content-box; - color: rgb(34, 34, 34); - cursor: default; - height: 21px; - line-height: 21px; - margin: 0; - min-height: 21px; - min-width: 55px; - padding: 0 10px; - position: relative; - text-align: center; - z-index: 1; -} - -.buttonbar button { - -webkit-margin-start: 10px; -} - -button:hover, -input[type='button']:hover, -input[type='submit']:hover, -select:hover { - border-image: -webkit-image-set( - url('chrome://resources/images/apps/button_hover.png') 1x, - url('chrome://resources/images/2x/apps/button_hover.png') - 2x) 5 fill / 5px / 2px repeat; - color: #222; -} - -button:active, -input[type='button']:active, -input[type='submit']:active { - border-image: -webkit-image-set( - url('chrome://resources/images/apps/button_pressed.png') 1x, - url('chrome://resources/images/2x/apps/button_pressed.png') - 2x) 5 fill / 5px / 2px repeat; - color: #333; -} - -button[disabled], -input[type='button'][disabled], -input[type='submit'][disabled], -button[disabled]:hover, -input[type='button'][disabled]:hover, -input[type='submit'][disabled]:hover { - background-color: rgb(250, 250, 250); - background-image: none; - border-image: -webkit-image-set( - url('chrome://resources/images/apps/button.png') 1x, - url('chrome://resources/images/2x/apps/button.png') - 2x) 5 fill / 5px / 2px repeat; - color: rgb(150, 150, 150); -} - -/* Gray progress bar. */ -.progress-bar { - background-color: #e6e6e6; - border-radius: 3px; - height: 6px; -} - -.progress-track { - background-color: #888; - border-radius: 3px; - height: 6px; - min-width: 6px; -} - -.progress-track.smoothed { - transition: width 1s linear; -} - -/* Icons for the action choice dialog and choosing the default app. */ -div.import-photos-to-drive-icon { - background-image: -webkit-image-set( - url('../images/media/drive.png') 1x, - url('../images/media/2x/drive.png') 2x); -} - -div.view-files-icon { - background-image: -webkit-image-set( - url('../../common/images/icon32.png') 1x, - url('../../common/images/icon64.png') 2x); -} - -div.watch-single-video-icon { - background-image: -webkit-image-set( - url('../images/media/watch.png') 1x, - url('../images/media/2x/watch.png') 2x); -} - -/* Pop-up dialogs. */ - -.cr-dialog-container { - -webkit-box-align: center; - -webkit-box-pack: center; - -webkit-user-select: none; - display: -webkit-box; - height: 100%; - left: 0; - overflow: hidden; - position: absolute; - top: 0; - transition: opacity 250ms linear; - width: 100%; - z-index: 9999; -} - -.cr-dialog-frame { - -webkit-box-orient: vertical; - background-color: rgb(250, 250, 250); - border: 1px solid rgb(255, 255, 255); - border-radius: 2px; - box-shadow: 0 1px 4px 0 rgba(0, 0, 0, .5); - color: rgb(34, 34, 34); - cursor: default; - display: -webkit-box; - padding: 20px; - position: relative; - width: 460px; -} - -.cr-dialog-frame:focus { - outline: none; -} - -@-webkit-keyframes pulse { - 0% { - -webkit-transform: scale(1); - } - 40% { - -webkit-transform: scale(1.02); - } - 60% { - -webkit-transform: scale(1.02); - } - 100% { - -webkit-transform: scale(1); - } -} - -.cr-dialog-frame.pulse { - -webkit-animation-duration: 180ms; - -webkit-animation-iteration-count: 1; - -webkit-animation-name: pulse; - -webkit-animation-timing-function: ease-in-out; -} - -.shown > .cr-dialog-frame { - -webkit-transform: perspective(500px) scale(1) - translateY(0) rotateX(0); - opacity: 1; -} - -.cr-dialog-frame { - -webkit-transform: perspective(500px) scale(0.99) - translateY(-20px) rotateX(5deg); - opacity: 0; - transition: all 180ms; - transition-duration: 250ms; -} - -.cr-dialog-shield { - background-color: white; - bottom: 0; - display: block; - left: 0; - opacity: 0; - pointer-events: none; - position: absolute; - right: 0; - top: 0; - transition: opacity 500ms; -} - -.shown > .cr-dialog-shield { - opacity: 0.5; - transition: opacity 500ms; -} - -.cr-dialog-title { - -webkit-margin-after: 10px; - -webkit-margin-end: 20px; - display: block; - font-size: 125%; - white-space: nowrap; - word-wrap: normal; -} - -.cr-dialog-text { - margin: 13px 0; -} - -.cr-dialog-text, -.cr-dialog-title { - overflow: hidden; - text-overflow: ellipsis; -} - -.cr-dialog-frame input { - box-sizing: border-box; - width: 100%; -} - -.cr-dialog-buttons { - -webkit-box-orient: horizontal; - -webkit-box-pack: end; - display: -webkit-box; - padding-top: 10px; -} - -.cr-dialog-buttons button { - -webkit-margin-start: 8px; - line-height: 1.8; -} - -.cr-dialog-close { - background: url('chrome://theme/IDR_CLOSE_DIALOG') center no-repeat; - display: inline-block; - height: 44px; - opacity: 0.7; - position: absolute; - right: 0; - top: 0; - width: 44px; -} - -.cr-dialog-close:hover { - background-image: url('chrome://theme/IDR_CLOSE_DIALOG_H'); -} - -.cr-dialog-close:active { - background-image: url('chrome://theme/IDR_CLOSE_DIALOG_P'); -} diff --git a/chromium/chrome/browser/resources/file_manager/foreground/css/drive_welcome.css b/chromium/chrome/browser/resources/file_manager/foreground/css/drive_welcome.css deleted file mode 100644 index a3c5ddb8999..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/css/drive_welcome.css +++ /dev/null @@ -1,188 +0,0 @@ -/* 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. */ - -/* Google Drive welcome banners.*/ -.drive-welcome-wrapper { - /* This image looks good in high DPI as is. */ - background-image: url(chrome://resources/images/clouds.png); - background-repeat: repeat-x; - color: #333; -} - -.drive-welcome-icon { - background-image: -webkit-image-set( - url('../images/files/ui/drive_logo.png') 1x, - url('../images/files/ui/2x/drive_logo.png') 2x); - background-repeat: no-repeat; -} - -.drive-welcome-links { - -webkit-box-orient: horizontal; - display: -webkit-box; -} - -.drive-welcome-button { - -webkit-user-select: none; - background-image: linear-gradient(to bottom, #f5f5f5, #f1f1f1); - border: 1px solid rgba(0,0,0,0.1); - border-radius: 2px; - color: #444; - cursor: default; - display: inline-block; - font-size: 13px; - font-weight: bold; - height: 27px; - line-height: 27px; - padding: 0 8px; - text-align: center; - transition: all 218ms; -} - -.drive-welcome-button:hover { - background-image: linear-gradient(to bottom, #f8f8f8, #f1f1f1); - border-color: #C6C6C6; - box-shadow: 0 1px 1px rgba(0,0,0,0.1); - color: #222; - transition: all 0; -} - -.drive-welcome-button:active { - background-image: linear-gradient(to bottom, #f6f6f6, #f1f1f1); - box-shadow: inset 0 1px 2px rgba(0,0,0,0.1); -} - - -.drive-welcome-button.drive-welcome-start { - background-image: - linear-gradient(to bottom, rgb(77, 144, 254), rgb(71, 135, 237)); - border-color: rgb(48, 121, 237); - color: white; - text-decoration: none; -} - -.drive-welcome-button.drive-welcome-start:hover { - background-image: - linear-gradient(to bottom, rgb(77, 144, 254), rgb(53, 122, 232)); - border-color: rgb(47, 91, 183); - box-shadow: 0 1px 1px rgba(0,0,0,0.1); -} - -/* Header welcome banner. */ -.drive-welcome.header { - -webkit-box-flex: 0; - height: 100px; - overflow: hidden; - position: relative; - transition: height 180ms ease, visibility 0 linear 180ms; -} - -.dialog-container:not([drive-welcome='header']) .drive-welcome.header { - height: 0; - visibility: hidden; -} - -.drive-welcome.header .drive-welcome-wrapper { - -webkit-box-orient: horizontal; - background-size: 308px 100px; - bottom: 0; - display: -webkit-box; - left: 0; - position: absolute; - right: 0; - top: 0; -} - -.drive-welcome.header .drive-welcome-icon { - background-position: center 18px; - background-size: 51px 44px; - width: 120px; -} - -.drive-welcome.header .drive-welcome-message { - -webkit-box-flex: 1; - -webkit-box-orient: vertical; - display: -webkit-box; -} - -.drive-welcome.header .drive-welcome-title { - font-size: 140%; - margin-bottom: 4px; - margin-top: 14px; -} - -.drive-welcome.header .drive-welcome-text { - margin-bottom: 6px; -} - -.drive-welcome.header .drive-welcome-dismiss { - display: none; -} - -/* Full page welcome banner. */ -.drive-welcome.page { - bottom: 0; - left: 0; - position: absolute; - right: 0; - top: 0; -} - -.dialog-container:not([drive-welcome='page']) .drive-welcome.page { - display: none; -} - -.drive-welcome.page .cr-dialog-close { - display: none; -} - -.drive-welcome.page .drive-welcome-wrapper { - -webkit-box-align: center; - -webkit-box-orient: vertical; - background-size: 520px 173px; - bottom: 0; - display: -webkit-box; - font-size: 120%; - left: 0; - overflow: hidden; - position: absolute; - right: 0; - top: 0; -} - -.drive-welcome.page .drive-welcome-icon { - background-position: center center; - height: 240px; - left: 0; - right: 0; - top: 0; - width: 100%; -} - -.drive-welcome.page .drive-welcome-message { - margin-left: 10px; - margin-right: 10px; - max-width: 525px; -} - -.drive-welcome.page .drive-welcome-title { - font-size: 133%; - margin-bottom: 30px; - text-align: center; -} - -.drive-welcome.page .drive-welcome-text { - margin-bottom: 24px; -} - -.drive-welcome.page .drive-welcome-dismiss { - margin-left: 20px; -} - -body:not([type='full-page']) .drive-welcome.page .drive-welcome-wrapper { - background-position: 0 0; -} - -body:not([type='full-page']) .drive-welcome.page .drive-welcome-icon { - height: 200px; -} diff --git a/chromium/chrome/browser/resources/file_manager/foreground/css/file_manager.css b/chromium/chrome/browser/resources/file_manager/foreground/css/file_manager.css deleted file mode 100644 index 560cef7e9a5..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/css/file_manager.css +++ /dev/null @@ -1,2075 +0,0 @@ -/* 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. */ - -/* The order of z-index: - * - 2: drag-selection-bodrder - * - 3: preview-panel - * - 500: scrollbar - * - 500: splitter - * - 525: spinner - * - 550: autocomplete-suggestions - * - 600: menus - * - 600: tooltip - * - 1000: preview thumbnail popup - * - 1000: overlay panel (ie. image editor) - */ - -/* Special attribute used in HTML to hide elements. */ -body[type='folder'] [invisibleif~='folder'], -body[type='upload-folder'] [invisibleif~='upload-folder'], -body[type='saveas-file'] [invisibleif~='saveas-file'], -body[type='open-file'] [invisibleif~='open-file'], -body[type='open-multi-file'] [invisibleif~='open-multi-file'], -body[type='full-page'] [invisibleif~='full-page'], - -body[type='folder'] [visibleif]:not([visibleif~='folder']), -body[type='upload-folder'] [visibleif]:not([visibleif~='upload-folder']), -body[type='saveas-file'] [visibleif]:not([visibleif~='saveas-file']), -body[type='open-file'] [visibleif]:not([visibleif~='open-file']), -body[type='open-multi-file'] [visibleif]:not([visibleif~='open-multi-file']), -body[type='full-page'] [visibleif]:not([visibleif~='full-page']) { - display: none !important; -} - -html { - height: 100%; -} - -html.col-resize * { - cursor: col-resize !important; -} - -/* Outer frame of the dialog. */ -body { - -webkit-box-flex: 1; - -webkit-box-orient: vertical; - -webkit-tap-highlight-color: transparent; - -webkit-user-select: none; - cursor: default; - display: -webkit-box; - height: 100%; - margin: 0; - padding: 0; - width: 100%; -} - -/* Drop opacity of selected rows to give a visual feedback on copy/cut - * operation. */ -.blink { - opacity: 0.8; -} - -::-webkit-scrollbar { - height: 0; - width: 0; -} - -/* TODO(mtomasz): Flip scrollbars to the opposite side for RTL languages. */ -.scrollbar-vertical { - bottom: 0; - position: absolute; - right: 0; - top: 0; - width: 10px; - z-index: 500; /* Must be below the contextmenu (600). */ -} - -.scrollbar-button { - background-color: black; - border: 1px solid #ccc; - border-radius: 3px; - box-sizing: border-box; - height: 50%; - margin-right: 2px; - opacity: 0; - position: absolute; - transition: opacity 100ms; - width: 8px; -} - -:hover > .scrollbar-vertical > .scrollbar-button { - opacity: 0.3; -} - -.scrollbar-vertical > .scrollbar-button:hover { - opacity: 0.4; -} - -.scrollbar-vertical > .scrollbar-button.pressed { - opacity: 0.5; -} - -/* Main part of the dialog between header and footer. */ -.dialog-container { - -webkit-box-align: stretch; - -webkit-box-flex: 1; - -webkit-box-orient: horizontal; - background-color: white; /* Makes #drag-container invisible. */ - border-radius: 2px; - display: -webkit-box; - overflow: hidden; - position: relative; -} - -/* The style applied when a modal dialog box overlap the dialog container. */ -.dialog-container.disable-header-drag .dialog-navigation-list-header, -.dialog-container.disable-header-drag .dialog-header { - -webkit-app-region: no-drag; -} - -/* List/grid and preview are inside this container. */ -.dialog-main { - -webkit-box-align: stretch; - -webkit-box-flex: 1; - -webkit-box-orient: vertical; - display: -webkit-box; -} - -/* Directory tree at the left. */ -.dialog-navigation-list { - -webkit-border-end: 1px solid rgba(20, 20, 22, 0.1); - -webkit-box-flex: 0; - -webkit-box-orient: vertical; - background-color: #f1f1f1; - display: flex; - flex-direction: column; - max-width: 50%; - min-width: 100px; - overflow: hidden; - position: relative; - width: 150px; -} - -.dialog-navigation-list-header { - -webkit-app-region: drag; - flex: none; - height: 48px; /* Keep in sync with #dialog-header. */ - line-height: 45px; -} - -.dialog-navigation-list-header #app-name { - -webkit-margin-start: 15px; - color: #303030; - font-size: 130%; -} - -.dialog-navigation-list-contents { - display: -webkit-box; - flex: 1 1 auto; - position: relative; -} - -.dialog-navigation-list-footer { - display: -webkit-flex; - flex: none; - flex-direction: column; -} - -/* A vertical splitter between the roots list and the file list. It is actually - a transparent area centered on the roots list right border.*/ -div.splitter { - -webkit-box-flex: 0; - cursor: col-resize; - margin-left: -3px; - margin-right: -3px; - position: relative; - width: 6px; - z-index: 500; /* Must be below the contextmenu (600). */ -} - -#navigation-list { - -webkit-box-flex: 1; - -webkit-box-orient: vertical; - display: -webkit-box; -} - -#navigation-list > * { - height: 40px; - padding: 0 5px; -} - -#navigation-list > .accepts, -#navigation-list > [lead][selected], -#navigation-list > [lead], -#navigation-list > [selected], -#navigation-list > [anchor] { - background-color: rgb(225, 225, 225); -} - -#navigation-list:focus > .accepts, -#navigation-list:focus > [lead][selected], -#navigation-list:focus > [lead], -#navigation-list:focus > [selected], -#navigation-list:focus > [anchor] { - background-color: rgb(66, 129, 244); - color: white; -} - -#navigation-list li.root-item { - -webkit-box-align: center; - display: -webkit-box; - line-height: 22px; /* To accomodate for icons. */ - padding-left: 11px; -} - -#navigation-list li.root-item > .root-label { - -webkit-box-flex: 1; - margin: 0 2px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -#navigation-list .volume-icon { - background-position: center 2px; - background-repeat: no-repeat; - height: 24px; - width: 24px; -} - -#middlebar-header { - -webkit-border-end: 1px solid rgba(20, 20, 22, 0.1); - -webkit-box-sizing: border-box; - -webkit-padding-start: 20px; - color: rgb(100, 100, 100); - height: 47px; - line-height: 40px; - overflow-x: hidden; - position: absolute; - text-overflow: ellipsis; - width: 100%; -} - -#directory-tree { - -webkit-border-end: 1px solid rgba(20, 20, 22, 0.1); - bottom: 0; - left: 0; - overflow-x: hidden; - overflow-y: auto; - padding-bottom: 0; /* For the preview panel. Will be overridden by JS. */ - position: absolute; - right: 0; - top: 47px; -} - -#directory-tree .tree-row { - cursor: pointer; - display: -webkit-box; - line-height: 29px; - padding: 0 3px; -} - -/* For rows of subitems (non-top items) */ -#directory-tree .tree-children .tree-row { - line-height: 29px; -} - -#directory-tree .tree-row > .expand-icon { - height: 37px; - left: 3px; - margin: -13px; - right: 3px; - top: 0; - vertical-align: middle; - width: 37px; -} - -#directory-tree:focus .tree-row[selected] > .expand-icon { - background-image: -webkit-canvas(tree-triangle-inverted); -} - -#directory-tree .tree-row > .volume-icon { - background-position: center 2px; - background-repeat: no-repeat; - height: 24px; - vertical-align: middle; - width: 24px; -} - -#directory-tree .tree-row > .label { - -webkit-box-flex: 1; - display: block; - margin: 0 3px; - overflow-x: hidden; - text-overflow: ellipsis; -} - -#directory-tree .tree-item.accepts > .tree-row, -#directory-tree .tree-row[lead][selected], -#directory-tree .tree-row[lead], -#directory-tree .tree-row[selected], -#directory-tree .tree-row[anchor] { - background-color: rgb(204, 204, 204); -} - -#directory-tree .tree-item.accepts > .tree-row, -#directory-tree .tree-row[lead][selected], -#directory-tree .tree-row[lead], -#directory-tree .tree-row[selected], -#directory-tree .tree-row[anchor] { - background-color: rgb(225, 225, 225); -} - -#directory-tree:focus .tree-item.accepts > .tree-row, -#directory-tree:focus .tree-row[lead][selected], -#directory-tree:focus .tree-row[lead], -#directory-tree:focus .tree-row[selected], -#directory-tree:focus .tree-row[anchor] { - background-color: rgb(193, 209, 232); -} - -#directory-tree:focus .tree-item.accepts > .tree-row, -#directory-tree:focus .tree-row[lead][selected], -#directory-tree:focus .tree-row[lead], -#directory-tree:focus .tree-row[selected], -#directory-tree:focus .tree-row[anchor] { - background-color: rgb(66, 129, 244); - color: white; -} - -#navigation-list .root-item > div.root-eject { - background-image: -webkit-image-set( - url('../images/files/ui/eject.png') 1x, - url('../images/files/ui/2x/eject.png') 2x); - background-position: center center; - background-repeat: no-repeat; - cursor: pointer; - height: 20px; - margin-right: 6px; - opacity: 0.7; - transition: opacity 70ms linear; - vertical-align: middle; - width: 20px; -} - -#navigation-list:focus .root-item[selected] > div.root-eject { - -webkit-filter: brightness(0) invert(); - opacity: 1; -} - -#directory-tree .root-item[disabled] { - opacity: 0.5; - pointer-events: none; -} - -/* Breadcrumbs and things under the title but above the list view. */ -.dialog-header { - -webkit-app-region: drag; - -webkit-box-align: center; - -webkit-box-orient: horizontal; - display: flex; - height: 48px; - margin: 0; - transition: all 180ms ease; -} - -/* Search box */ - -#search-box { - display: flex; - flex: auto; -} - -#search-box.too-short { - visibility: hidden; -} - -#search-box .icon { - -webkit-app-region: no-drag; - -webkit-padding-end: 0; - -webkit-padding-start: 10px; - background: transparent -webkit-image-set( - url(../images/files/ui/search_icon_inactive.png) 1x, - url(../images/files/ui/2x/search_icon_inactive.png) 2x) - no-repeat center; - flex: none; - height: 32px; - padding-bottom: 8px; - padding-top: 8px; - width: 32px; -} - -#search-box .icon:hover, -#search-box.has-cursor .icon, -#search-box.has-text .icon { - background-image: -webkit-image-set( - url(../images/files/ui/search_icon_active.png) 1x, - url(../images/files/ui/2x/search_icon_active.png) 2x); -} - -#search-box .full-size { - flex: 1 0 0; -} - -#search-box input { - -webkit-app-region: no-drag; - background-color: #fff; - border-style: none; - color: #333; - cursor: default; - display: block; - height: 48px; - line-height: 1em; - margin: 0; - max-width: 100%; - outline: none; - padding: 0; -} - -#search-box input::-webkit-search-cancel-button { - -webkit-appearance: none; -} - -#search-box.has-cursor input, -#search-box.has-text input { - cursor: text; -} - -#search-box .clear { - -webkit-app-region: no-drag; - -webkit-margin-end: 30px; - align-self: center; - background: -webkit-image-set( - url(../images/files/ui/search_clear.png) 1x, - url(../images/files/ui/2x/search_clear.png) 2x) - no-repeat center; - border: none; - display: none; - flex: none; - height: 12px; - min-height: 0; - min-width: 0; - outline: none; - padding: 0; - width: 12px; -} - -#search-box.has-text .clear { - display: block; -} - -#search-box .clear:hover { - background-image: -webkit-image-set( - url(../images/files/ui/search_clear_hover.png) 1x, - url(../images/files/ui/2x/search_clear_hover.png) 2x); -} - -#search-box .clear:active { - background-image: -webkit-image-set( - url(../images/files/ui/search_clear_pressed.png) 1x, - url(../images/files/ui/2x/search_clear_pressed.png) 2x); -} - -.topbutton-bar { - flex: none; -} - -/* Container for the detail and thumbnail list views. */ -.dialog-body { - -webkit-box-flex: 1; - -webkit-transition: all 180ms ease; - border-top: 1px solid rgba(20, 20, 22, 0.1); - position: relative; -} - -.main-panel { - bottom: 0; - display: -webkit-box; - left: 0; - position: absolute; - right: 0; - top: 0; -} - -.dialog-middlebar-contents { - display: -webkit-box; - max-width: 50%; - min-width: 45px; - position: relative; - width: 180px; -} - -/* Container for the ok/cancel buttons. */ -.dialog-footer { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - border-top: 1px solid rgb(225, 225, 225); - display: -webkit-box; - outline: none; - padding: 10px; -} - -.progressable:not([progress]) .progress-bar, -.progressable:not([progress]) .preparing-label { - display: none; -} - -.progressable[progress] .ok, -.progressable[progress] #filename-input-box, -.progressable[progress] #preview-lines, -.progressable[progress] .file-type { - display: none; -} - -.progressable .progress-bar { - -webkit-box-flex: 1; - -webkit-margin-end: 20px; - -webkit-margin-start: 20px; -} - -select.file-type:hover { - /* Original value is '5 fill', which hides the dropdown triangle. */ - border-image-slice: 5; -} - -/* The container for breadcrumb elements. */ -.breadcrumbs { - -webkit-box-align: center; - -webkit-box-flex: 1; - -webkit-box-orient: horizontal; - display: -webkit-box; - line-height: 20px; - overflow: hidden; - padding-top: 1px; -} - -#dir-breadcrumbs { - -webkit-margin-end: 5px; - -webkit-margin-start: 10px; -} - -/* The icon for offline mode */ -.offline-icon { - -webkit-margin-end: 0; - -webkit-margin-start: 10px; - background-image: -webkit-image-set( - url('../images/files/ui/offline.png') 1x, - url('../images/files/ui/2x/offline.png') 2x); - height: 16px; - opacity: 0; - transition-duration: 200ms; - transition-property: opacity; - transition-timing-function: ease-out; - width: 16px; -} - -/* Transition for '-webkit-margin-start' (or -end) property is not working. - * So I added .offline-icon-space to animate 'width' property. */ -.offline-icon-space { - -webkit-margin-end: 0; - -webkit-margin-start: -26px; /* Clear width of .offline-icon */ - transition-duration: 200ms; - transition-property: width; - transition-timing-function: ease-out; - width: 0; -} - -body[drive] .dialog-container[connection='offline'] .offline-icon, -body[drive] .dialog-container[connection='metered'] .offline-icon { - opacity: 1; -} - -body[drive] .dialog-container[connection='offline'] .offline-icon-space, -body[drive] .dialog-container[connection='metered'] .offline-icon-space { - width: 26px; -} - -.breadcrumbs > [collapsed]::before { - content: '...'; -} - -.breadcrumbs > [collapsed] { - width: 1em; -} - -/* A single directory name in the list of path breadcrumbs. */ -.breadcrumb-path { - color: #969696; - cursor: pointer; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -/* The final breadcrumb, representing the current directory. */ -#search-breadcrumbs .breadcrumb-path.breadcrumb-last { - color: #141414; - cursor: default; -} - -/* The > arrow between breadcrumbs. */ - -.breadcrumbs .separator { - background-image: -webkit-image-set( - url('../images/files/ui/breadcrumb-separator.png') 1x, - url('../images/files/ui/2x/breadcrumb-separator.png') 2x); - background-position: center center; - background-repeat: no-repeat; - height: 10px; - overflow: hidden; - width: 25px; -} - -#filename-input-box input { - border: 1px solid #c8c8c8; - border-radius: 1px; - box-sizing: border-box; - height: 31px; /* border-box */ - margin-right: 30px; -} - -.filelist-panel { - -webkit-box-flex: 1; - -webkit-box-orient: vertical; - display: -webkit-box; -} - -#list-container { - -webkit-box-flex: 1; - -webkit-box-orient: vertical; - display: -webkit-box; - position: relative; -} - -#detail-table { - -webkit-box-flex: 1; - -webkit-box-orient: vertical; - display: -webkit-box; -} - -#detail-table > list, -.thumbnail-grid { - -webkit-box-flex: 1; - padding-bottom: 0; /* For the preview panel. Will be overridden by JS. */ -} - -#file-list .drag-selection-border { - -webkit-box-sizing: border-box; - background-color: rgba(255, 255, 255, 0.3); - border: 2px solid rgba(255, 255, 255, 0.6); - outline: 1px solid rgba(0, 0, 0, 0.1); - position: absolute; - z-index: 2; -} - -.spinner { - background: 100% url(../images/common/spinner.svg); - height: 16px; - left: 50%; - margin-left: -8px; - margin-top: -8px; - opacity: 0.5; - position: absolute; - top: 50%; - width: 16px; -} - -.spinner-layer { - background: url(../images/common/spinner.svg) center / 16px no-repeat; - bottom: 0; - left: 0; - position: absolute; - right: 0; - top: 0; - z-index: 525; -} - -.downloads-warning { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - background-color: #f0f0f0; - background-image: -webkit-image-set( - url('../images/files/ui/warning_icon_square.png') 1x, - url('../images/files/ui/2x/warning_icon_square.png') 2x); - background-position: 15px center; - background-repeat: no-repeat; - color: #666; - display: -webkit-box; - font-size: 13px; - height: 57px; - overflow: hidden; - padding-left: 57px; /* Make space for the icon. */ - transition: height 70ms linear; -} - -.downloads-warning[hidden] { - display: -webkit-box !important; /* Overrides [hidden] for animation. */ - height: 0; -} - -@-webkit-keyframes heightAnimation { - 0% { - height: 0; - display: -webkit-box; - } -} - -/* Drive space warning banner. */ -.volume-warning { - -webkit-animation: heightAnimation 70ms linear; - -webkit-box-align: center; - -webkit-box-orient: horizontal; - background-image: url(chrome://resources/images/clouds.png); - background-repeat: repeat-x; - background-size: 150px 44px; - color: #333; - display: -webkit-box; - font-size: 13px; - height: 44px; - overflow: hidden; - position: relative; -} - -.volume-warning[hidden] { - border-top-width: 0; - height: 0; -} - -.volume-warning .drive-icon { - background-image: -webkit-image-set( - url('../images/files/ui/drive_logo.png') 1x, - url('../images/files/ui/2x/drive_logo.png') 2x); - background-position: center; - background-repeat: no-repeat; - background-size: 25px 22px; - height: 44px; - width: 50px; -} - -.volume-warning .drive-text { - margin-right: 11px; -} - -/* The cr.ui.Grid representing the detailed file list. */ -.thumbnail-grid { - overflow-y: auto; - padding-bottom: 0; /* For the preview panel. Will be overridden by JS. */ - width: 100%; -} - -body[type='full-page'] .thumbnail-frame > .img-container { - position: relative; -} - -body[type='full-page'] .thumbnail-frame > .img-container, -body[type='full-page'] .detail-name .detail-icon { - cursor: pointer; -} - -.img-container > img { - -webkit-user-drag: none; - position: absolute; -} - -.img-container > img:not(.cached):not(.drag-thumbnail) { - -webkit-animation: fadeIn 250ms linear; -} - -.thumbnail-bottom { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - bottom: 0; - cursor: auto; - display: -webkit-box; - left: 0; - padding: 0 10px; - position: absolute; - right: 0; -} - -.thumbnail-bottom .filename-label { - -webkit-box-flex: 1; -} - -/* Styles specific for the grid view. */ - -.thumbnail-grid .thumbnail-item { - -webkit-margin-start: 21px; - border: 3px solid transparent; /* Selection will make the border visible. */ - margin-top: 20px; - position: relative; -} - -.thumbnail-grid .thumbnail-frame { - background-color: rgb(245, 245, 245); - height: 120px; - overflow: hidden; - position: relative; - width: 160px; -} - -.thumbnail-grid .thumbnail-item[selected] .thumbnail-frame, -.thumbnail-grid .thumbnail-item.accepts .thumbnail-frame { - border-color: white; -} - -.thumbnail-grid .img-container { - height: 100%; - width: 100%; -} - -.thumbnail-grid .thumbnail-bottom { - background: rgba(0, 0, 0, 0.55); - color: #fff; - height: 30px; -} - -/* Padding counterweights negative margins of items, thus eliminating scroll - bar when it's not needed. Max height is set to fit 8 items before showing - scroll bar. */ -#default-actions-list { - max-height: 328px; - padding: 1px 0; -} - -#default-actions-list > li > * { - background-position: 5px center; - background-repeat: no-repeat; - background-size: 16px 16px; - padding-left: 26px; -} - -#list-container list > li[selected], -#list-container grid > li[selected], -#default-actions-list > li[selected] { - background-color: rgb(225, 225, 225); -} - -#list-container list:focus > li[selected], -#list-container grid:focus > li[selected], -#default-actions-list:focus > li[selected] { - background-color: rgb(66, 129, 244); - color: white; -} - -#list-container list > li.accepts[selected], -#list-container grid > li.accepts[selected] { - background-color: rgb(215, 215, 215); -} - -#list-container list:focus > li.accepts[selected], -#list-container grid:focus > li.accepts[selected] { - background-color: rgb(48, 125, 254); -} - -#list-container list > li.accepts, -#list-container grid > li.accepts { - background-color: #f1f1f1; -} - -#list-container.nohover grid > .accepts { - background-color: transparent; -} - -#directory-tree .tree-item.accepts > .tree-row, -#navigation-list > .accepts, -#list-container list > li.accepts, -#list-container grid > li.accepts { - -webkit-animation: acceptsBlink 200ms linear 1s 3; -} - -@-webkit-keyframes acceptsBlink { - 0% { - background-color: transparent; - } -} - -.table-row-cell .selection-label { - -webkit-margin-end: 10px; - height: 15px; -} - -.table-row-cell .filename-label, -.thumbnail-item .filename-label, -/* Show ellipsis in cells. The name column has different structure and overrides - this rule. */ -.table-row-cell > div { - display: block; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -/* Text box used for renaming in the detail list. */ -.table-row-cell input.rename { - border-width: 0; - padding: 2px 0; -} - -input.rename:focus { - outline-color: rgb(77, 144, 254); -} - -input.rename { - font: inherit; - line-height: 1; - text-align: inherit; -} - -.table-row-cell .filename-label, -.table-row-cell input.rename { - -webkit-box-flex: 1; -} - -[renaming] > .filename-label { - display: none; -} - -/* Text box used for renaming in the thumbnail list. */ -.thumbnail-grid input.rename { - -webkit-margin-start: -1px; - box-sizing: border-box; - height: 20px; - width: 114px; -} - -/* The cr.ui.Table representing the detailed file list. */ -.detail-table { - width: 100%; -} - -/* Bottom pane describing current selection. */ -.preview-panel { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-transition: background-color 150ms ease; - background: linear-gradient( - to bottom, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 1)); - border-top: 1px solid rgba(20, 20, 22, 0.1); - bottom: 0; - display: -webkit-box; - height: 51px; - left: 0; - opacity: 1; - padding: 0 10px 0 7px; - position: absolute; - right: 0; - z-index: 3; -} - -.preview-panel[visibility=hiding] { - -webkit-transform: translate(0, 5px); - opacity: 0; - /* Using all seems to cause preview panel and checkbox flicking issue. */ - transition: opacity 220ms ease, - -webkit-transform 220ms ease; -} - -.preview-panel[visibility=hidden] { - display: none; - opacity: 0; -} - -.preview-panel > .left, -.dialog-footer > .left { - -webkit-box-align: center; - -webkit-box-flex: 1; - -webkit-box-orient: horizontal; - display: -webkit-box; -} - -.preview-panel > .right, -.dialog-footer > .right { - -webkit-box-pack: end; -} - -.preview-panel .preparing-label { - -webkit-margin-start: 30px; -} - -.preview-panel .progress-bar { - -webkit-box-flex: 1; -} - -.preview-thumbnails { - -webkit-box-orient: horizontal; - display: -webkit-box; - padding-left: 25px; -} - -.preview-thumbnails > .img-container { - background-color: white; - background-size: 35px 35px; /* For file icons. */ - border: 2px solid white; - box-shadow: 0 1px 1px rgba(80, 80, 80, 0.5); - box-sizing: border-box; - cursor: pointer; - height: 35px; - margin: 0 0 0 -25px; /* Overlapped images. */ - overflow: hidden; - position: relative; - width: 35px; -} - -.preview-thumbnails > .popup { - -webkit-transform: translate(0, 3px) scale(0.95); - background-color: #f2f2f2; - border: 2px solid #fff; - bottom: 8px; - box-shadow: 0 0 0 1px #F0F0F0, - 0 0 0 2px #D0D0D0, - 2px 2px 6px rgba(0, 0, 0, 0.2); - display: -webkit-flex; - left: -8px; - opacity: 0; - pointer-events: none; - position: absolute; - transition: opacity 180ms ease-in 300ms, - -webkit-transform 180ms ease-in 300ms; - z-index: 1000; -} - -.preview-thumbnails.has-zoom:hover > .popup { - -webkit-transform: translate(0, 0) scale(1.0); - opacity: 1; - pointer-events: auto; -} - -@-webkit-keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -.preview-thumbnails img { - -webkit-animation: fadeIn 180ms ease-in-out; -} - -.preview-thumbnails > .popup > img { - -webkit-flex: 1 1 0; - -webkit-user-drag: none; -} - -/* Table splitter element */ -.table-header-splitter { - background-image: -webkit-image-set( - url('../images/files/ui/vertical_separator.png') 1x, - url('../images/files/ui/2x/vertical_separator.png') 2x); - background-position: center; - background-repeat: repeat-y; - height: 20px; - top: 10px; - width: 5px; -} - -.table-header-splitter:last-child { - display: none; -} - -/* Container for a table header. */ -.table-header { - box-sizing: border-box; - height: 47px; -} - -.table-header-sort-image-desc::after { - -webkit-padding-start: 13px; - background-image: -webkit-image-set( - url('../images/files/ui/sort_desc.png') 1x, - url('../images/files/ui/2x/sort_desc.png') 2x); - background-position: center center; - background-repeat: no-repeat; - color: #888; - content: '\00a0'; - position: relative; - top: 1px; -} - -.table-header-sort-image-asc::after { - -webkit-padding-start: 13px; - background-image: -webkit-image-set( - url('../images/files/ui/sort_asc.png') 1x, - url('../images/files/ui/2x/sort_asc.png') 2x); - background-position: center center; - background-repeat: no-repeat; - color: #888; - content: '\00a0'; - position: relative; - top: -1px; -} - -.preview-container .table-header { - border-radius: 0 4px 0 0; -} - -/* Text label in a table header. */ -.table-header-label { - color: rgb(100, 100, 100); - line-height: 40px; - margin: 0 7px; -} - -.table-row-cell > * { - -webkit-box-align: center; - -webkit-box-flex: 1; - -webkit-box-orient: horizontal; - padding: 0 10px; -} - -.table-row-cell { - color: rgb(100, 100, 100); -} - -.table-row-cell > .detail-name { - display: -webkit-box; -} - -.table-row-cell > .detail-name { - color: rgb(0, 0, 0); -} - - -#list-container list:focus > [selected] .table-row-cell, -#list-container list:focus > [selected] .detail-name { - color: white; -} - -.table-row-cell { - -webkit-box-align: center; -} - -.file-checkbox { - -webkit-margin-end: 0; - -webkit-margin-start: 0; - position: relative; - z-index: 2; -} - -#select-all-checkbox { - -webkit-margin-end: 13px; - -webkit-margin-start: 3px; - margin-bottom: 0; - margin-top: 0; - vertical-align: middle; -} - -#list-container .table-header #select-all-checkbox, -#list-container li.table-row .file-checkbox { - -webkit-appearance: none; - background-image: -webkit-image-set( - url('../images/files/ui/select_checkbox.png') 1x, - url('../images/files/ui/2x/select_checkbox.png') 2x); - background-position: center; - background-repeat: no-repeat; - border-style: none; - height: 15px; - width: 15px; -} - -#list-container li.table-row .file-checkbox { - vertical-align: top; -} - -#list-container .table-header #select-all-checkbox::after, -#list-container li.table-row .file-checkbox::after { - content: none; -} - -#list-container .table-header #select-all-checkbox:checked, -#list-container li.table-row .file-checkbox:checked { - background-image: -webkit-image-set( - url('../images/files/ui/select_checkbox_checked.png') 1x, - url('../images/files/ui/2x/select_checkbox_checked.png') 2x); -} - -#list-container .table-header #select-all-checkbox:checked, -#list-container list li.table-row[selected] .file-checkbox { - -webkit-filter: brightness(0) opacity(40%); -} - -#list-container list:focus li.table-row[selected] .file-checkbox { - -webkit-filter: brightness(0) invert(); -} - -#list-container li.table-row, -#default-actions-list li { - height: 29px; - line-height: 29px; -} - -/* The icon in the name column. See file_types.css for specific icons. */ -.detail-icon { - height: 24px; - width: 24px; -} - -#detail-table .detail-icon { - /* To shift the icon position. */ - margin-bottom: 2px; -} - -.metadata-item { - -webkit-box-flex: 1; - -webkit-box-orient: horizontal; - -webkit-padding-start: 8px; - display: -webkit-box; -} - -.metadata-label { - -webkit-margin-end: 6px; -} - -.preview-panel .spacer { - -webkit-box-flex: 1; -} - -#delete-button { - min-width: 21px; /* overrride */ - padding: 0; /* overrride */ - width: 21px; -} - -#delete-button::before { - /* Background image should be specified in the before pseudo element because - * border image fill is specified to delete-button. */ - background: -webkit-image-set( - url(../images/files/ui/onbutton_trash.png) 1x, - url(../images/files/ui/2x/onbutton_trash.png) 2x) no-repeat center; - content: ''; - display: block; - height: 100%; - width: 100%; -} - -#delete-button[disabled] { - display: none; -} - -#tasks-menu menuitem:not(.change-default) { - background-position: left 10px center; - padding-left: 32px; -} - -#share-button { - display: block; - min-width: 0; /* overrride */ -} - -#preview-lines { - -webkit-box-flex: 1; - -webkit-margin-end: 10px; - -webkit-margin-start: 10px; - vertical-align: middle; -} - -/* The selection summary text at the bottom of the preview pane. */ -.preview-summary { - color: #666; - overflow: hidden; - text-overflow: ellipsis; - vertical-align: middle; - white-space: nowrap; -} - -.preview-summary .calculating-size { - margin-left: 5px; - opacity: 0.5; -} - -.detail-name > * { - -webkit-box-align: center; - display: -webkit-box; -} - -/* Overriding input.common[type='checkbox'] rule in common.css. */ -.detail-name > input.common[type='checkbox'] { - -webkit-margin-end: 4px; - -webkit-margin-start: -1px; - border-color: #444; -} - -list .detail-name > .file-checkbox::before, -.pin::before { - /* Invisible area that reacts on mouse events. */ - content: ''; - display: -webkit-box; - height: 38px; - left: -8px; - position: absolute; - right: -9px; - top: -14px; -} - -#filename-input-box { - -webkit-box-align: center; - -webkit-box-flex: 1; - display: -webkit-box; -} - -#filename-input-box input { - -webkit-box-flex: 1; - display: -webkit-box; - padding: 1px 2px; -} - -#filename-input-box .filename-label { - -webkit-box-orient: horizontal; - background-color: white; - color: #333; - display: -webkit-box; - padding-right: 4px; -} - -body:not([type='saveas-file']) #filename-input-box { - display: none; -} - -/* A vertical spring. */ -.vertical-spacer { - -webkit-box-flex: 1; - -webkit-box-orient: vertical; - display: -webkit-box; -} - -/* Dimmed items */ - -body[type='folder'] .file, -body[type='upload-folder'] .file, -body[drive] .dialog-container[connection='offline'] .dim-offline { - opacity: 0.4; -} - -/* Overlay pane covering the entire file manager window (e.g. image editor)*/ -.overlay-pane { - -webkit-app-region: no-drag; - border: none; - height: 100%; - left: 0; - position: absolute; - top: 0; - width: 100%; - z-index: 1000; /* Must be above all elements in file manager container. */ -} - -/* When the overlay pane is visible hide everything else so that the tab order - is not confused. */ -body[overlay-visible] > :not(.overlay-pane) { - display: none !important; -} - -/* Invisible container for elements representing files while dragging. */ -#drag-container { - left: 0; - /* Hack for extra margins caused by setDragImage(). */ - padding: 1000px 0 0 1000px; - position: fixed; - top: 0; - z-index: -1; /* below .dialog-container */ -} - -#drag-container .drag-contents { - -webkit-box-orient: horizontal; - background-color: #fafafa; - border: 1px solid #bbb; - border-radius: 3px; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .2); - display: -webkit-box; - margin-bottom: 5px; - padding: 6px; - transition: opacity 200ms ease-in; -} - -#drag-container .drag-contents.for-image { - padding: 2px; -} - -#drag-container .thumbnail-item { - -webkit-box-orient: horizontal; - display: -webkit-box; -} - -/* When changing these properties please preserve these conditions: - 1. width == height (so that the rotated thumbnail does not look off-center) - 2. width % 8 == 0 (to minimize rounding errors in the centering code) */ -#drag-container .img-container { - -webkit-box-flex: 0; - display: -webkit-box; - height: 64px; - overflow: hidden; - position: relative; - width: 64px; -} - -#drag-container .label { - -webkit-box-flex: 1; - font-weight: bold; - line-height: 24px; - max-width: 320px; - overflow: hidden; - padding: 0 5px; - text-overflow: ellipsis; - white-space: nowrap; -} - -menu.file-context-menu { - z-index: 600; /* Must be below the overlay pane (1000). */ -} - -menu.chrome-menu hr { - color: transparent; - font-size: 0; -} - -div.offline { - -webkit-box-pack: center; - display: -webkit-box; -} - -div.offline > * { - -webkit-box-align: center; - display: -webkit-box; -} - -div.shade { - /* transition: opacity 1000ms linear; */ - background-color: rgba(255, 255, 255, 0.8); - bottom: 0; - left: 0; - opacity: 0; - position: absolute; - right: 0; - top: 0; -} - -div.shade[fadein] { - opacity: 1; -} - -/* Message panel for unmounted Drive */ -#unmounted-panel, -#format-panel { - bottom: 0; - color: #333; - display: none; - left: 0; - padding-left: 50px; - padding-top: 20px; - position: absolute; - right: 0; - top: 0; -} - -body[drive='mounting'] .dialog-container #unmounted-panel, -body[drive='error'] .dialog-container #unmounted-panel, -body[unformatted] .dialog-container #format-panel { - display: block; -} - -body[drive='unmounted'] .dialog-container .filelist-panel, -body[drive='mounting'] .dialog-container .filelist-panel, -body[drive='error'] .dialog-container .filelist-panel, -body[unformatted] .dialog-container .filelist-panel { - /* Hide file list when Drive is not mounted. - Use opacity to avoid manual resizing.*/ - opacity: 0; -} - -#unmounted-panel > *, -#format-panel > * { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: start; - display: none; - height: 22px; - margin-bottom: 10px; -} - -#unmounted-panel > .loading { - position: relative; -} - -#unmounted-panel > .loading > .spinner-box { - bottom: 0; - position: absolute; - right: 100%; - top: 0; - width: 40px; -} - -body[unformatted] #format-panel > .error, -body[drive='mounting'] #unmounted-panel > .loading, -body[drive='error'] #unmounted-panel > .error, -#format-panel > #format-button, -#unmounted-panel.retry-enabled > .learn-more { - display: -webkit-box; -} - -.plain-link { - color: rgb(17, 85, 204); - cursor: pointer; - text-decoration: none; -} - -.buttonbar > * { - position: relative; -} - -.buttonbar .tooltip, -.topbutton-bar .tooltip { - right: -12px; - top: 35px; -} - -/* Tooltips */ -.tooltip { - background: #2d2d2d; - border-radius: 0; - box-shadow: 1px 2px 4px #ccc; - box-sizing: border-box; - color: white; - display: block; - font-size: 11px; - font-weight: bold; - height: 29px; - line-height: 29px; - margin-left: -20px; - min-width: 50px; - opacity: 0; - outline: 1px solid rgba(255, 255, 255, 0.5); - padding: 0 10px; - pointer-events: none; - position: absolute; - text-align: center; - top: 5px; - white-space: nowrap; - z-index: 600; /* Must be below the overlay pane (1000). */ -} - -.tooltip::after, -.tooltip::before { - border-left: 5px solid transparent; - border-right: 5px solid transparent; - border-top: transparent; - content: ''; - display: block; - margin-left: -5px; - position: absolute; - right: 24px; - top: -5px; -} - -.tooltip::after { - border-bottom: 5px solid #2d2d2d; -} - -.tooltip::before { - border-bottom: 5px solid rgba(255, 255, 255, 0.5); -} - -/* Show with delay, disappear instantly */ -@-webkit-keyframes tooltip-show { - 0% { opacity: 0; } - 90% { opacity: 0; } - 100% { opacity: 1; } -} - -:hover > .tooltip { - -webkit-animation-duration: 800ms; - -webkit-animation-iteration-count: 1; - -webkit-animation-name: tooltip-show; - -webkit-animation-timing-function: linear; - opacity: 1; -} - -#no-search-results { - bottom: 0; - display: none; - left: 0; - padding: 10px; - position: absolute; - right: 0; - top: 28px; /* Leave room for the file list header. */ -} - -.dialog-container:not([drive-welcome='page']) #no-search-results[show] { - display: block; -} - -#volume-space-info-contents { - -webkit-box-align: center; - display: -webkit-box; -} - -#volume-space-info-contents > div { - -webkit-box-flex: 1; - -webkit-margin-start: 15px; - display: -webkit-box; -} - -#list-container .table-header-inner { - height: 100%; -} - -#list-container .table-header-cell:hover { - background-color: inherit; -} - -#list-container .table-header-cell:first-child { - -webkit-box-sizing: border-box; - -webkit-padding-start: 8px; -} - -button:focus { - outline-color: rgb(77, 144, 254); -} - -#new-folder-button { - margin-right: 30px; -} - -#default-action-dialog { - min-width: 300px; - width: auto; -} - -.drive-welcome-wrapper { - /* drive_welcome.css will override it once loaded. */ - display: none; -} - -list.autocomplete-suggestions { - -webkit-margin-before: -7px; - -webkit-margin-start: -38px; - background-color: rgb(250, 250, 250); - border-radius: 3px; - box-shadow: 0 1px 4px 0 rgba(0, 0, 0, .5); - box-sizing: border-box; /* To match the width with the search box's. */ - color: rgb(34, 34, 34); - overflow: hidden; - padding: 5px 0; - position: fixed; - width: 300px !important; /* This overrides the value specified by script. */ - z-index: 550; -} - -list.autocomplete-suggestions > li { - -webkit-box-align: center; - display: -webkit-box; - padding: 3px 0; -} - -list.autocomplete-suggestions > li > div.detail-icon { - -webkit-margin-end: 6px; - -webkit-margin-start: 6px; -} - -list.autocomplete-suggestions > li > div.detail-text { - -webkit-box-flex: 1; - overflow-x: hidden; - text-overflow: ellipsis; -} - -list.autocomplete-suggestions > li > div.detail-text em { - color: rgb(150, 150, 150); - font-style: normal; -} - -list.autocomplete-suggestions > li > div[search-icon] { - background: -webkit-image-set( - url('../images/files/ui/search_icon_active.png') 1x, - url('../images/files/ui/2x/search_icon_active.png') 2x); - background-position: center; - background-repeat: no-repeat; -} - -list.autocomplete-suggestions > li[selected] > div[search-icon], -list.autocomplete-suggestions > li[lead] > div[search-icon] { - -webkit-filter: brightness(0) invert(); -} - -list.autocomplete-suggestions > [selected], -list.autocomplete-suggestions > [lead] { - background-color: rgb(66, 129, 244); - color: white; -} - -list.autocomplete-suggestions > [selected] > div.detail-text em, -list.autocomplete-suggestions > [lead] > div.detail-text em { - color: white; -} - -#gear-menu { - margin-top: 8px; -} - -#gear-menu > menuitem:not(.menuitem-button) { - margin-right: 50px; -} - -/* View buttons in the gear menu. */ - -menuitem#detail-view { - background-image: -webkit-image-set( - url('../images/files/ui/button_list_view.png') 1x, - url('../images/files/ui/2x/button_list_view.png') 2x); -} - -menuitem#detail-view[selected]:not([disabled]), -menuitem#detail-view[lead]:not([disabled]) { - background-image: -webkit-image-set( - url('../images/files/ui/button_list_view_white.png') 1x, - url('../images/files/ui/2x/button_list_view_white.png') 2x); -} - -menuitem#thumbnail-view { - background-image: -webkit-image-set( - url('../images/files/ui/button_mosaic_view.png') 1x, - url('../images/files/ui/2x/button_mosaic_view.png') 2x); -} - -menuitem#thumbnail-view[selected]:not([disabled]), -menuitem#thumbnail-view[lead]:not([disabled]) { - background-image: -webkit-image-set( - url('../images/files/ui/button_mosaic_view_white.png') 1x, - url('../images/files/ui/2x/button_mosaic_view_white.png') 2x); -} - -#iframe-drag-area { - -webkit-app-region: drag; - height: 48px; - left: 64px; - position: absolute; - right: 92px; - top: 0; - width: auto; - z-index: 101; -} - -#suggest-app-dialog { - background-color: #fff; - border: 0; - padding: 0; - width: auto; -} - -#suggest-app-dialog .cr-dialog-title { - /* Entire height: 44px (content-box 22px + padding 11px * 2) */ - font-size: 16px; - height: 22px; - margin: 0; - padding: 11px 18px; -} - -#suggest-app-dialog #webview-container { - border-bottom: solid 1px #bbb; - border-top: solid 1px #bbb; - position: relative; -} - -#suggest-app-dialog.show-spinner #webview-container webview { - pointer-events: none; -} - -#suggest-app-dialog:not(.show-spinner) .spinner-layer { - display: none; -} - -#suggest-app-dialog .spinner-layer { - background-color: rgba(255, 255, 255, 0.7); -} - -#suggest-app-dialog .cr-dialog-buttons, -#suggest-app-dialog .cr-dialog-ok, -#suggest-app-dialog .cr-dialog-cancel { - display: none; -} - -#suggest-app-dialog .cr-dialog-text { - -webkit-padding-after: 10px; - -webkit-padding-before: 0; - -webkit-padding-end: 20px; - -webkit-padding-start: 20px; - margin: 0; -} - -#suggest-app-dialog #buttons { - background: #eee; - width: 100%; -} - -#suggest-app-dialog #buttons > #webstore-button { - -webkit-padding-after: 10px; - -webkit-padding-before: 10px; - -webkit-padding-end: 10px; - -webkit-padding-start: 36px; - background-image: -webkit-image-set( - url('chrome://theme/IDR_WEBSTORE_ICON_16') 1x, - url('chrome://theme/IDR_WEBSTORE_ICON_16@2x') 2x); - background-position: 12px center; - background-repeat: no-repeat; - color: #00f; - cursor: pointer; - display: inline-block; - height: 16px; -} - -.cr-dialog-frame.error-dialog-frame { - width: 300px; -} - -.error-dialog-frame .error-dialog-img { - background-image: -webkit-image-set( - url('chrome://theme/IDR_ERROR_NETWORK_GENERIC') 1x, - url('chrome://theme/IDR_ERROR_NETWORK_GENERIC@2x') 2x); - background-position: center; - background-repeat: no-repeat; - height: 40px; -} - -.error-dialog-frame .cr-dialog-cancel { - display: none; -} - -.error-dialog-frame .cr-dialog-close, -.error-dialog-frame .cr-dialog-title { - display: none; -} - -.error-dialog-frame .cr-dialog-text { - text-align: center; -} - -.cr-dialog-frame.share-dialog-frame { - background-color: white; - width: auto; -} - -.share-dialog-webview-wrapper { - height: 100px; - margin-top: 10px; - min-width: 300px; - overflow: hidden; - transition: height 200ms ease; -} - -.share-dialog-webview { - height: 100%; - width: 100%; -} - -.share-dialog-webview-wrapper:not(.loaded) .share-dialog-webview { - visibility: hidden; -} - -.share-dialog-frame .cr-dialog-text, -.share-dialog-frame .cr-dialog-buttons { - display: none; -} - -#conflict-confirm-dialog .cr-dialog-buttons { - align-items: baseline; - display: flex; -} - -#conflict-confirm-dialog input[type=checkbox] { - -webkit-margin-start: -2px; - width: auto; -} - -#conflict-confirm-dialog label { - flex: 1 0 auto; -} - -/* Progress center */ - -@-webkit-keyframes progress-center-toggle { - /* Height values of each frame are set by script. */ - from { - } - to { - } -} - -#progress-center { - background-color: transparent; - border-top: 1px solid transparent; - overflow: hidden; - position: relative; - transition: background-color 300ms linear, - border 300ms linear; -} - -#progress-center.opened { - background-color: #ebebeb; - border-top: 1px solid #d8d8d8; -} - -#progress-center.animated { - -webkit-animation: progress-center-toggle 300ms ease-out; -} - -#progress-center-open-view { - opacity: 1; - padding-top: 42px; - transition: opacity 300ms linear; -} - -#progress-center:not(.opened) #progress-center-open-view { - opacity: 0; - pointer-events: none; - position: absolute; -} - -#progress-center-close-view { - opacity: 1; - transition: opacity 300ms linear; -} - -#progress-center.opened #progress-center-close-view { - opacity: 0; - pointer-events: none; - position: absolute; -} - -#progress-center.animated #progress-center-open-view, -#progress-center.animated #progress-center-close-view { - left: 0; - pointer-events: none; - position: absolute; - right: 0; - top: 0; - z-index: 1; -} - -#progress-center li { - display: block; - min-height: 29px; /* label 17px + frame 12px */ - padding-bottom: 20px; -} - -#progress-center label { - color: #777; - display: block; - font: 12px/17px normal; - min-height: 17px; - overflow: hidden; - padding: 0 20px; - text-overflow: ellipsis; - white-space: nowrap; -} - -#progress-center li.error label { - white-space: normal; -} - -#progress-center .progress-frame { - -webkit-padding-end: 10px; - -webkit-padding-start: 20px; - align-items: center; - display: flex; - margin-top: 4px; -} - -#progress-center li.error .progress-frame { - height: 0; -} - -#progress-center .progress-bar { - -webkit-margin-end: 24px; - background: #d8d8d8; - border-radius: 3px; - flex: 1 0 0; - height: 6px; - opacity: 1; - overflow: hidden; -} - -#progress-center li.error .progress-bar, -#progress-center li.canceled .progress-bar { - visibility: hidden; -} - -#progress-center .progress-track { - background: #787878; - height: 100%; -} - -#progress-center .progress-track.animated { - transition: width 300ms linear; -} - -#progress-center button { - background: orange; - border: none; - cursor: pointer; - flex: 0 0 auto; - height: 12px; - min-height: 0; - min-width: 0; - outline: none; - padding: 0; - width: 12px; - z-index: 0; -} - -#progress-center button.toggle { - background: -webkit-image-set( - url(../images/files/ui/process_drawer_button_opened.png) 1x, - url(../images/files/ui/2x/process_drawer_button_opened.png) 2x) - no-repeat; - position: absolute; - right: 10px; - top: 17px; /* label height */ - transition: top 300ms ease-out; - z-index: 1; -} - -#progress-center button.toggle:hover { - background: -webkit-image-set( - url(../images/files/ui/process_drawer_button_opened_hover.png) 1x, - url(../images/files/ui/2x/process_drawer_button_opened_hover.png) 2x) - no-repeat; -} - -#progress-center button.toggle:active { - background: -webkit-image-set( - url(../images/files/ui/process_drawer_button_opened_pressed.png) 1x, - url(../images/files/ui/2x/process_drawer_button_opened_pressed.png) 2x) - no-repeat; -} - -/* - * If the closed progress center has only one item, - * toggle button turned into cancel button the item. - */ -#progress-center:not(.opened) #progress-center-close-view.single ~ - button.toggle, -#progress-center button.cancel { - background: -webkit-image-set( - url(../images/files/ui/close_bar.png) 1x, - url(../images/files/ui/2x/close_bar.png) 2x) - no-repeat; -} - -#progress-center:not(.opened) - #progress-center-close-view.single:not(.cancelable) button.toggle, -#progress-center li:not(.cancelable) button.cancel { - visibility: hidden; -} - -#progress-center.opened button.toggle { - background: -webkit-image-set( - url(../images/files/ui/process_drawer_button_closed.png) 1x, - url(../images/files/ui/2x/process_drawer_button_closed.png) 2x) - no-repeat; - top: 10px; -} - -#progress-center.opened button.toggle:hover { - background: -webkit-image-set( - url(../images/files/ui/process_drawer_button_closed_hover.png) 1x, - url(../images/files/ui/2x/process_drawer_button_closed_hover.png) 2x) - no-repeat; -} - -#progress-center.opened button.toggle:active { - background: -webkit-image-set( - url(../images/files/ui/process_drawer_button_closed_pressed.png) 1x, - url(../images/files/ui/2x/process_drawer_button_closed_pressed.png) 2x) - no-repeat; -} diff --git a/chromium/chrome/browser/resources/file_manager/foreground/css/file_types.css b/chromium/chrome/browser/resources/file_manager/foreground/css/file_types.css deleted file mode 100644 index 75603497f07..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/css/file_types.css +++ /dev/null @@ -1,477 +0,0 @@ -/* 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. */ - -/* Small icons for file types, used in lists and menus. */ -[file-type-icon] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/generic.png') 1x, - url('../../common/images/file_types/200/generic.png') 2x); - background-position: center; - background-repeat: no-repeat; -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon], -list:focus [selected] [file-type-icon], -list.autocomplete-suggestions [selected] [file-type-icon] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/generic_white.png') 1x, - url('../../common/images/file_types/200/generic_white.png') 2x); -} - -[file-type-icon='archive'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/archive.png') 1x, - url('../../common/images/file_types/200/archive.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='archive'], -list:focus [selected] [file-type-icon='archive'], -list.autocomplete-suggestions [selected] [file-type-icon='archive'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/archive_white.png') 1x, - url('../../common/images/file_types/200/archive_white.png') 2x); -} - -[file-type-icon='audio'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/audio.png') 1x, - url('../../common/images/file_types/200/audio.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='audio'], -list:focus [selected] [file-type-icon='audio'], -list.autocomplete-suggestions [selected] [file-type-icon='audio'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/audio_white.png') 1x, - url('../../common/images/file_types/200/audio_white.png') 2x); -} - -[file-type-icon='excel'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/excel.png') 1x, - url('../../common/images/file_types/200/excel.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='excel'], -list:focus [selected] [file-type-icon='excel'], -list.autocomplete-suggestions [selected] [file-type-icon='excel'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/excel_white.png') 1x, - url('../../common/images/file_types/200/excel_white.png') 2x); -} - -[file-type-icon='folder'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/folder.png') 1x, - url('../../common/images/file_types/200/folder.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='folder'], -list:focus [selected] [file-type-icon='folder'], -list.autocomplete-suggestions [selected] [file-type-icon='folder'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/folder_white.png') 1x, - url('../../common/images/file_types/200/folder_white.png') 2x); -} - -[file-type-icon='form'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/form.png') 1x, - url('../../common/images/file_types/200/form.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='form'], -list:focus [selected] [file-type-icon='form'], -list.autocomplete-suggestions [selected] [file-type-icon='form'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/form_white.png') 1x, - url('../../common/images/file_types/200/form_white.png') 2x); -} - -[file-type-icon='gdoc'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/gdoc.png') 1x, - url('../../common/images/file_types/200/gdoc.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='gdoc'], -list:focus [selected] [file-type-icon='gdoc'], -list.autocomplete-suggestions [selected] [file-type-icon='gdoc'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/gdoc_white.png') 1x, - url('../../common/images/file_types/200/gdoc_white.png') 2x); -} - -[file-type-icon='gdraw'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/gdraw.png') 1x, - url('../../common/images/file_types/200/gdraw.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='gdraw'], -list:focus [selected] [file-type-icon='gdraw'], -list.autocomplete-suggestions [selected] [file-type-icon='gdraw'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/gdraw_white.png') 1x, - url('../../common/images/file_types/200/gdraw_white.png') 2x); -} - -[file-type-icon='glink'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/glink.png') 1x, - url('../../common/images/file_types/200/glink.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='glink'], -list:focus [selected] [file-type-icon='glink'], -list.autocomplete-suggestions [selected] [file-type-icon='glink'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/glink_white.png') 1x, - url('../../common/images/file_types/200/glink_white.png') 2x); -} - -[file-type-icon='gsheet'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/gsheet.png') 1x, - url('../../common/images/file_types/200/gsheet.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='gsheet'], -list:focus [selected] [file-type-icon='gsheet'], -list.autocomplete-suggestions [selected] [file-type-icon='gsheet'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/gsheet_white.png') 1x, - url('../../common/images/file_types/200/gsheet_white.png') 2x); -} - -[file-type-icon='gslides'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/gslides.png') 1x, - url('../../common/images/file_types/200/gslides.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='gslides'], -list:focus [selected] [file-type-icon='gslides'], -list.autocomplete-suggestions [selected] [file-type-icon='gslides'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/gslides_white.png') 1x, - url('../../common/images/file_types/200/gslides_white.png') 2x); -} - -[file-type-icon='gtable'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/gtable.png') 1x, - url('../../common/images/file_types/200/gtable.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='gtable'], -list:focus [selected] [file-type-icon='gtable'], -list.autocomplete-suggestions [selected] [file-type-icon='gtable'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/gtable_white.png') 1x, - url('../../common/images/file_types/200/gtable_white.png') 2x); -} - -[file-type-icon='gform'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/form.png') 1x, - url('../../common/images/file_types/200/form.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='gform'], -list:focus [selected] [file-type-icon='gform'], -list.autocomplete-suggestions [selected] [file-type-icon='gform'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/form_white.png') 1x, - url('../../common/images/file_types/200/form_white.png') 2x); -} - -[file-type-icon='image'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/image.png') 1x, - url('../../common/images/file_types/200/image.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='image'], -list:focus [selected] [file-type-icon='image'], -list.autocomplete-suggestions [selected] [file-type-icon='image'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/image_white.png') 1x, - url('../../common/images/file_types/200/image_white.png') 2x); -} - -[file-type-icon='pdf'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/pdf.png') 1x, - url('../../common/images/file_types/200/pdf.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='pdf'], -list:focus [selected] [file-type-icon='pdf'], -list.autocomplete-suggestions [selected] [file-type-icon='pdf'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/pdf_white.png') 1x, - url('../../common/images/file_types/200/pdf_white.png') 2x); -} - -[file-type-icon='ppt'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/ppt.png') 1x, - url('../../common/images/file_types/200/ppt.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='ppt'], -list:focus [selected] [file-type-icon='ppt'], -list.autocomplete-suggestions [selected] [file-type-icon='ppt'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/ppt_white.png') 1x, - url('../../common/images/file_types/200/ppt_white.png') 2x); -} - -[file-type-icon='script'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/script.png') 1x, - url('../../common/images/file_types/200/script.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='script'], -list:focus [selected] [file-type-icon='script'], -list.autocomplete-suggestions [selected] [file-type-icon='script'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/script_white.png') 1x, - url('../../common/images/file_types/200/script_white.png') 2x); -} - -[file-type-icon='sites'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/sites.png') 1x, - url('../../common/images/file_types/200/sites.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='sites'], -list:focus [selected] [file-type-icon='sites'], -list.autocomplete-suggestions [selected] [file-type-icon='sites'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/sites_white.png') 1x, - url('../../common/images/file_types/200/sites_white.png') 2x); -} - -[file-type-icon='video'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/video.png') 1x, - url('../../common/images/file_types/200/video.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='video'], -list:focus [selected] [file-type-icon='video'], -list.autocomplete-suggestions [selected] [file-type-icon='video'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/video_white.png') 1x, - url('../../common/images/file_types/200/video_white.png') 2x); -} - -[file-type-icon='word'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/word.png') 1x, - url('../../common/images/file_types/200/word.png') 2x); -} - -tree:focus .tree-item[selected] > .tree-row > [file-type-icon='word'], -list:focus [selected] [file-type-icon='word'], -list.autocomplete-suggestions [selected] [file-type-icon='word'] { - background-image: -webkit-image-set( - url('../../common/images/file_types/100/word_white.png') 1x, - url('../../common/images/file_types/200/word_white.png') 2x); -} - -[file-type-icon='drive'] { - background-image: -webkit-image-set( - url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_DRIVE') 1x, - url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_DRIVE@2x') 2x); -} - -/* Large generic thumbnails, used when a file does not have a thumbnail. */ -[generic-thumbnail] { - background-image: -webkit-image-set( - url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_GENERIC') 1x, - url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_GENERIC@2x') 2x); - background-position: center center; - background-repeat: no-repeat; -} - -[generic-thumbnail='audio'] { - background-image: -webkit-image-set( - url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_AUDIO') 1x, - url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_AUDIO@2x') 2x); -} - -[generic-thumbnail='folder'] { - background-image: -webkit-image-set( - url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_FOLDER') 1x, - url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_FOLDER@2x') 2x); -} - -[generic-thumbnail='image'] { - background-image: -webkit-image-set( - url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_IMAGE') 1x, - url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_IMAGE@2x') 2x); -} - -[generic-thumbnail='video'] { - background-image: -webkit-image-set( - url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_VIDEO') 1x, - url('chrome://theme/IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_VIDEO@2x') 2x); -} - -/* Icons for volume types. */ - -[volume-type-icon='archive'] { - background-image: -webkit-image-set( - url('../images/volumes/black_archive.png') 1x, - url('../images/volumes/2x/black_archive.png') 2x); -} - -list:focus li[selected] [volume-type-icon='archive'], -tree:focus .tree-item[selected] > .tree-row > [volume-type-icon='archive'] { - background-image: -webkit-image-set( - url('../images/volumes/white_archive.png') 1x, - url('../images/volumes/2x/white_archive.png') 2x); -} - -[volume-type-icon='downloads'] { - background-image: -webkit-image-set( - url('../images/volumes/black_downloads.png') 1x, - url('../images/volumes/2x/black_downloads.png') 2x); -} - -list:focus li[selected] [volume-type-icon='downloads'], -tree:focus .tree-item[selected] > .tree-row > [volume-type-icon='downloads'] { - background-image: -webkit-image-set( - url('../images/volumes/white_downloads.png') 1x, - url('../images/volumes/2x/white_downloads.png') 2x); -} - -[volume-type-icon='drive'] { - background-image: -webkit-image-set( - url('../images/volumes/black_drive.png') 1x, - url('../images/volumes/2x/black_drive.png') 2x); -} - -list:focus li[selected] [volume-type-icon='drive'], -tree:focus .tree-item[selected] > .tree-row > [volume-type-icon='drive'] { - background-image: -webkit-image-set( - url('../images/volumes/white_drive.png') 1x, - url('../images/volumes/2x/white_drive.png') 2x); -} - -[volume-type-icon='drive_offline'] { - background-image: -webkit-image-set( - url('../images/volumes/black_offline.png') 1x, - url('../images/volumes/2x/black_offline.png') 2x); -} - -list:focus li[selected] [volume-type-icon='drive_offline'], -tree:focus .tree-item[selected] > .tree-row > - [volume-type-icon='drive_offline'] { - background-image: -webkit-image-set( - url('../images/volumes/white_offline.png') 1x, - url('../images/volumes/2x/white_offline.png') 2x); -} - -[volume-type-icon='drive_shared_with_me'] { - background-image: -webkit-image-set( - url('../images/volumes/black_shared.png') 1x, - url('../images/volumes/2x/black_shared.png') 2x); -} - -list:focus li[selected] [volume-type-icon='drive_shared_with_me'], -tree:focus .tree-item[selected] > .tree-row > - [volume-type-icon='drive_shared_with_me'] { - background-image: -webkit-image-set( - url('../images/volumes/white_shared.png') 1x, - url('../images/volumes/2x/white_shared.png') 2x); -} - -[volume-type-icon='drive_recent'] { - background-image: -webkit-image-set( - url('../images/volumes/black_recent.png') 1x, - url('../images/volumes/2x/black_recent.png') 2x); -} - -list:focus li[selected] [volume-type-icon='drive_recent'], -tree:focus .tree-item[selected] > .tree-row > - [volume-type-icon='drive_recent'] { - background-image: -webkit-image-set( - url('../images/volumes/white_recent.png') 1x, - url('../images/volumes/2x/white_recent.png') 2x); -} - -[volume-type-icon='removable'] { - background-image: -webkit-image-set( - url('../images/volumes/black_usb.png') 1x, - url('../images/volumes/2x/black_usb.png') 2x); -} - -list:focus li[selected] [volume-type-icon='removable'], -tree:focus .tree-item[selected] > .tree-row > - [volume-type-icon='removable'] { - background-image: -webkit-image-set( - url('../images/volumes/white_usb.png') 1x, - url('../images/volumes/2x/white_usb.png') 2x); -} - -[volume-type-icon='removable'][volume-subtype='sd'] { - background-image: -webkit-image-set( - url('../images/volumes/black_sd.png') 1x, - url('../images/volumes/2x/black_sd.png') 2x); -} - -list:focus li[selected] [volume-type-icon='removable'][volume-subtype='sd'], -tree:focus .tree-item[selected] > .tree-row > - [volume-type-icon='removable'][volume-subtype='sd'] { - background-image: -webkit-image-set( - url('../images/volumes/white_sd.png') 1x, - url('../images/volumes/2x/white_sd.png') 2x); -} - -[volume-type-icon='removable'][volume-subtype='optical'] { - background-image: -webkit-image-set( - url('../images/volumes/black_optical.png') 1x, - url('../images/volumes/2x/black_optical.png') 2x); -} - -list:focus div[selected] - [volume-type-icon='removable'][volume-subtype='optical'], -tree:focus .tree-item[selected] > .tree-row > - [volume-type-icon='removable'][volume-subtype='optical'] { - background-image: -webkit-image-set( - url('../images/volumes/white_optical.png') 1x, - url('../images/volumes/2x/white_optical.png') 2x); -} - -list:focus li[selected] - [volume-type-icon='removable'][volume-subtype='optical'], -tree:focus .tree-item[selected] > .tree-row > - [volume-type-icon='removable'][volume-subtype='optical'] { - background-image: -webkit-image-set( - url('../images/volumes/white_optical.png') 1x, - url('../images/volumes/2x/white_optical.png') 2x); -} - -/* TODO(kaznacheev): consider a better icon for volume-subtype=unknown. - Also find out if we need an icon for volume-subtype=mobile */ -[volume-type-icon='removable'][volume-subtype='unknown'] { - background-image: -webkit-image-set( - url('../images/volumes/black_hdd.png') 1x, - url('../images/volumes/2x/black_hdd.png') 2x); -} - -list:focus li[selected] - [volume-type-icon='removable'][volume-subtype='unknown'], -tree:focus .tree-item[selected] > .tree-row > - [volume-type-icon='removable'][volume-subtype='unknown'] { - background-image: -webkit-image-set( - url('../images/volumes/white_hdd.png') 1x, - url('../images/volumes/2x/white_hdd.png') 2x); -} diff --git a/chromium/chrome/browser/resources/file_manager/foreground/css/gallery.css b/chromium/chrome/browser/resources/file_manager/foreground/css/gallery.css deleted file mode 100644 index 7680f4d3100..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/css/gallery.css +++ /dev/null @@ -1,1374 +0,0 @@ -/* 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. */ - -body { - -webkit-user-select: none; - font-family: Open Sans, Droid Sans Fallback, sans-serif; - font-size: 84%; - margin: 0; -} - -.gallery, -.gallery .content { - bottom: 0; - left: 0; - overflow: hidden; - position: absolute; - right: 0; - top: 0; -} - -/* Common background for both mosaic and slide mode. */ -.gallery .content { - background-color: black; -} - -/* Close button */ - -/* We actually want (left,top) to be (0,0) but for some weird reason - this triggers :hover style on page reload which is ugly. */ -.gallery > .back-button { - cursor: pointer; - left: 1px; - position: absolute; - top: 1px; - z-index: 200; -} - -/* The close icon is in a nested div so that its opacity can be manipulated - independently from its parent (which can be dimmed when the crop frame - overlaps it) */ -.gallery > .back-button div { - background-image: -webkit-image-set( - url('../images/gallery/back_to_files.png') 1x, - url('../images/gallery/2x/back_to_files.png') 2x); - background-position: center center; - background-repeat: no-repeat; - height: 40px; - opacity: 0; - width: 64px; -} - -.gallery[tools] > .back-button div { - opacity: 0.5; -} - -.gallery[tools] > .back-button div:hover { - opacity: 1; -} - -/* Image container and canvas elements */ - -.gallery .image-container { - cursor: none; /* Only visible when the toolbar is active */ - height: 100%; - position: absolute; - width: 100%; -} - -.gallery[tools] .image-container[cursor='default'] { - cursor: default; -} - -.gallery[tools] .image-container[cursor='move'] { - cursor: -webkit-image-set( - url('../images/gallery/cursor_move.png') 1x, - url('../images/gallery/2x/cursor_move.png') 2x) 15 15, auto; -} - -.gallery[tools] .image-container[cursor='crop'] { - cursor: -webkit-image-set( - url('../images/gallery/cursor_crop.png') 1x, - url('../images/gallery/2x/cursor_crop.png') 2x) 15 15, auto; -} - -.gallery[tools] .image-container[cursor='n-resize'], -.gallery[tools] .image-container[cursor='s-resize'] { - cursor: -webkit-image-set( - url('../images/gallery/cursor_updown.png') 1x, - url('../images/gallery/2x/cursor_updown.png') 2x) 15 15, auto; -} - -.gallery[tools] .image-container[cursor='e-resize'], -.gallery[tools] .image-container[cursor='w-resize'] { - cursor: -webkit-image-set( - url('../images/gallery/cursor_leftright.png') 1x, - url('../images/gallery/2x/cursor_leftright.png') 2x) 15 15, auto; -} - -.gallery[tools] .image-container[cursor='nw-resize'], -.gallery[tools] .image-container[cursor='se-resize'] { - cursor: -webkit-image-set( - url('../images/gallery/cursor_nwse.png') 1x, - url('../images/gallery/2x/cursor_nwse.png') 2x) 15 15, auto; -} - -.gallery[tools] .image-container[cursor='ne-resize'], -.gallery[tools] .image-container[cursor='sw-resize'] { - cursor: -webkit-image-set( - url('../images/gallery/cursor_swne.png') 1x, - url('../images/gallery/2x/cursor_swne.png') 2x) 15 15, auto; -} - -.gallery .image-container > .image { - pointer-events: none; - position: absolute; - /* Duration and timing function are set in Javascript. */ - transition-property: -webkit-transform, opacity; -} - -.gallery .image-container > .image[fade] { - opacity: 0; -} - -/* Full resolution image is invisible unless printing. */ -.gallery .image-container > canvas.fullres { - display: none; -} - -@media print { - /* Do not print anything but the image content. */ - .gallery > :not(.content) { - display: none !important; - } - - /* Center the printed image. */ - .gallery .image-container { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - display: -webkit-box; - } - - /* Do not print the screen resolution image. */ - .gallery .image-container > canvas.image { - display: none !important; - } - - /* Print the full resolution image instead. */ - .gallery .image-container > canvas.fullres { - display: block !important; - max-height: 100%; - max-width: 100%; - } - - /* Print video at the center of the page */ - .gallery .image-container > video.image { - position: auto !important; - } -} - -/* Toolbar */ - -.gallery > .header, -.gallery > .toolbar { - -webkit-box-align: stretch; - -webkit-box-orient: horizontal; - -webkit-box-pack: start; - background-color: rgba(30, 30, 30, 0.8); - display: -webkit-box; - left: 0; - opacity: 0; - padding: 0 10px; - pointer-events: none; - position: absolute; - right: 0; - transition: opacity 300ms ease; -} - -.gallery > .header { - -webkit-box-align: center; - -webkit-box-pack: end; - border-bottom: 1px solid rgba(50, 50, 50, 0.8); - display: -webkit-box; - height: 45px; - top: 0; -} - -.gallery > .toolbar { - border-top: 1px solid rgba(50, 50, 50, 0.8); - bottom: 0; - height: 55px; - min-width: 800px; -} - -.gallery[tools]:not([slideshow]) > .header, -.gallery[tools]:not([slideshow]) > .toolbar { - opacity: 1; - pointer-events: auto; -} - -/* Hide immediately when entering the slideshow. */ -.gallery[tools][slideshow] > .toolbar { - transition-duration: 0; -} - -.gallery[tools][locked] > .toolbar { - pointer-events: none; -} - -.gallery .arrow-box { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - display: -webkit-box; - height: 100%; - pointer-events: none; - position: absolute; - width: 100%; - z-index: 100; -} - -.gallery .arrow-box .arrow { - opacity: 0; - pointer-events: none; -} - -.gallery .arrow-box .arrow-spacer { - -webkit-box-flex: 1; - pointer-events: none; -} - -.gallery[tools] .arrow-box[active] .arrow { - cursor: pointer; - opacity: 1; - pointer-events: auto; -} - -/* The arrow icons are in nested divs so that their opacity can be manipulated - * independently from their parent (which can be dimmed when the crop frame - * overlaps it) */ -.gallery .arrow div { - background-position: center center; - background-repeat: no-repeat; - height: 193px; - opacity: 0; - width: 105px; -} - -.gallery[tools] .arrow-box[active] .arrow div { - opacity: 0.25; -} - -.gallery[tools] .arrow-box[active] .arrow div:hover { - opacity: 1; -} - -.gallery .arrow.left div { - background-image: -webkit-image-set( - url('../images/gallery/arrow_left.png') 1x, - url('../images/gallery/2x/arrow_left.png') 2x); -} - -.gallery .arrow.right div { - background-image: -webkit-image-set( - url('../images/gallery/arrow_right.png') 1x, - url('../images/gallery/2x/arrow_right.png') 2x); -} - -/* Special behavior on mouse drag. - Redundant .gallery attributes included to make the rules more specific */ - -/* Everything but the image container should become mouse-transparent */ -.gallery[tools][editing][mousedrag] * { - pointer-events: none; -} - -.gallery[tools][editing][mousedrag] .image-container { - pointer-events: auto; -} - -/* The editor marks elements with 'dimmed' attribute to get them out of the way - of the crop frame */ -.gallery[tools][editing] [dimmed], -.gallery[tools][editing] [dimmed] * { - pointer-events: none; -} - -.gallery[tools][editing] [dimmed] { - opacity: 0.2; -} - -/* Filename */ - -.gallery .filename-spacer { - position: relative; - width: 270px; -} - -.gallery .filename-spacer > * { - background-color: transparent; - overflow: hidden; - position: absolute; - transition: visibility 0 linear 180ms, all 180ms linear; - width: 260px; -} - -.gallery .filename-spacer * { - color: white; -} - -.gallery .filename-spacer .namebox { - height: 22px; - top: 15px; -} - -.gallery[editing] .filename-spacer .namebox { - height: 21px; - top: 5px; -} - - -.gallery .filename-spacer .namebox { - background-color: transparent; - border: none; - box-sizing: border-box; - cursor: pointer; - display: block; - font-size: 120%; - outline: none; - overflow: hidden; - padding: 0 3px; - position: absolute; - text-overflow: ellipsis; - white-space: nowrap; -} - -.gallery .filename-spacer .namebox[disabled] { - -webkit-user-select: none; - cursor: default; -} - -.gallery .filename-spacer .namebox:not([disabled]):not(:focus):hover { - background-color: rgba(48, 48, 48, 1.0); -} - -.gallery .filename-spacer .namebox:focus { - background-color: white; - color: black; - cursor: text; -} - -.gallery .filename-spacer .options { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: start; - display: -webkit-box; - opacity: 0; - top: 50px; - visibility: hidden; -} - -.gallery[editing] .filename-spacer .options { - opacity: 1; - top: 28px; - visibility: visible; -} - -.gallery .filename-spacer .saved, -.gallery .filename-spacer .overwrite-original { - cursor: inherit; - font-size: 90%; - margin-left: 3px; - margin-right: 18px; - opacity: 0; - pointer-events: none; - transition: all linear 120ms; -} - -.gallery[editing] .filename-spacer .saved { - color: white; - opacity: 0.5; -} - -.gallery[editing] .filename-spacer .overwrite-original, -.gallery[editing] .filename-spacer .overwrite-original > * { - cursor: pointer; - opacity: 1; - pointer-events: auto; -} - -.gallery[editing] .options[saved] .overwrite-original { - opacity: 0.5; -} - -.gallery[editing] .options[saved] .overwrite-original, -.gallery[editing] .options[saved] .overwrite-original > * { - cursor: default; - pointer-events: none; -} - -.gallery .filename-spacer .overwrite-original input { - margin-bottom: -2px; - margin-right: 6px; -} - -.gallery .filename-spacer .saved[highlighted] { - -webkit-transform: scaleX(1.1) scaleY(1.1) rotate(0); - opacity: 1; -} - -/* Bubble */ -.gallery .toolbar .bubble { - bottom: 65px; - font-size: 85%; - left: 50px; - position: absolute; - width: 220px; -} - -.gallery:not([editing]) .toolbar .bubble { - display: none; -} - -/* Toolbar buttons */ - -.gallery .button-spacer { - -webkit-box-flex: 1; - display: -webkit-box; -} - -/* Thumbnails */ - -.gallery .ribbon-spacer { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - display: -webkit-box; - height: 100%; - left: 280px; - position: absolute; - right: 280px; -} - -.gallery .toolbar .ribbon { - -webkit-box-flex: 0; - -webkit-box-orient: horizontal; - -webkit-box-pack: start; - display: -webkit-box; - height: 100%; - overflow: hidden; - transition: opacity 180ms linear, visibility 0 linear; - z-index: 0; -} - -.gallery[editing] .toolbar .ribbon { - opacity: 0; - transition-delay: 0, 180ms; - visibility: hidden; -} - -.gallery .ribbon-image { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - border: 2px solid rgba(255, 255, 255, 0); /* transparent white */ - cursor: pointer; - display: -webkit-box; - height: 47px; - margin: 2px; - overflow: hidden; - transition: all 180ms linear; - width: 47px; -} - -.ribbon-image[vanishing='smooth'] { - border-left-width: 0; - border-right-width: 0; - margin-left: 0; - margin-right: 0; - width: 0; -} - -.gallery .ribbon-image[selected] { - border: 2px solid rgba(255, 233, 168, 1); -} - -.gallery .toolbar .ribbon.fade-left { - -webkit-mask-image: linear-gradient(to right, rgba(0, 0, 0, 0) 0, - rgba(0, 0, 0, 1) 40px); -} - -.gallery .toolbar .ribbon.fade-right { - -webkit-mask-image: linear-gradient(to left, rgba(0, 0, 0, 0) 0, - rgba(0, 0, 0, 1) 40px); -} - -.gallery .toolbar .ribbon.fade-left.fade-right { - -webkit-mask-image: linear-gradient(to right, rgba(0, 0, 0, 0) 0, - rgba(0, 0, 0, 1) 40px, - rgba(0, 0, 0, 1) 230px, - rgba(0, 0, 0, 0) 100%); -} - -.gallery .image-wrapper { - background-size: 45px 45px; - border: 1px solid rgba(0, 0, 0, 0); /* transparent black */ - height: 45px; - overflow: hidden; - position: relative; - width: 45px; -} - -.gallery .image-wrapper > img { - position: absolute; -} - -.gallery .image-wrapper > img:not(.cached) { - -webkit-animation: fadeIn 500ms ease-in; -} - -/* Editor buttons */ - -.gallery .edit-bar-spacer { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - display: -webkit-box; - height: 100%; - left: 280px; - opacity: 0; - position: absolute; - right: 280px; - transition: opacity 180ms linear, visibility 0 linear 180ms; - visibility: hidden; -} - -.gallery .toolbar .edit-main { - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - color: white; - display: -webkit-box; - height: 55px; - overflow: visible; -} - -.gallery[editing] .edit-bar-spacer { - opacity: 1.0; - pointer-events: auto; - transition-delay: 100ms, 100ms; - visibility: visible; -} - -.gallery .header button, -.gallery .toolbar button, -.gallery .header button[disabled], -.gallery .toolbar button[disabled] { - -webkit-box-align: center; - -webkit-box-flex: 0; - -webkit-box-orient: horizontal; - -webkit-box-pack: end; - background-color: rgba(0, 0, 0, 0); - background-position: center; - background-repeat: no-repeat; - border: none; - box-shadow: none; - color: white; - cursor: pointer; - display: -webkit-box; - opacity: 0.99; /* Workaround for http://crosbug.com/21065 */ - padding: 1px; /* Instead of a border. */ - position: relative; - z-index: 10; -} - -.gallery .header button, -.gallery .toolbar button { - height: 40px; - margin: 6px 0; - min-width: 40px; /* Reset. */ - width: 40px; -} - -/* By default, labels are hidden. */ -.gallery > .toolbar button span { - display: none; -} - -/* Show labels if there is enough space. */ -@media (min-width: 1180px) { - - .gallery .edit-main button, - .gallery .edit-main button[disabled] { - background-position: 5px center; - max-width: 60px; - min-width: 0; /* Reset. */ - padding: 0 10px 0 35px; - width: auto; - } - - .gallery > .toolbar button span { - display: inline; - } - -} - -.gallery .header button:hover, -.gallery .toolbar button:hover { - background-color: rgba(31, 31, 31, 1); - color: white; -} - -.gallery .header button:active, -.gallery .toolbar button:active, -.gallery .header button[pressed], -.gallery .toolbar button[pressed], -.gallery .header button[pressed]:hover, -.gallery .toolbar button[pressed]:hover { - background-color: rgba(240, 240, 240, 1); - color: black; -} - -.gallery > .toolbar button.autofix { - background-image: -webkit-image-set( - url('../images/gallery/icon_autofix.png') 1x, - url('../images/gallery/2x/icon_autofix.png') 2x); -} - -.gallery > .toolbar button.autofix:active, -.gallery > .toolbar button.autofix[pressed] { - background-image: -webkit-image-set( - url('../images/gallery/icon_autofix_selected.png') 1x, - url('../images/gallery/2x/icon_autofix_selected.png') 2x); -} - -.gallery > .toolbar button.crop { - background-image: -webkit-image-set( - url('../images/gallery/icon_crop.png') 1x, - url('../images/gallery/2x/icon_crop.png') 2x); -} - -.gallery > .toolbar button.crop:active, -.gallery > .toolbar button.crop[pressed] { - background-image: -webkit-image-set( - url('../images/gallery/icon_crop_selected.png') 1x, - url('../images/gallery/2x/icon_crop_selected.png') 2x); -} - -.gallery > .toolbar button.exposure { - background-image: -webkit-image-set( - url('../images/gallery/icon_brightness.png') 1x, - url('../images/gallery/2x/icon_brightness.png') 2x); -} - -.gallery > .toolbar button.exposure:active, -.gallery > .toolbar button.exposure[pressed] { - background-image: -webkit-image-set( - url('../images/gallery/icon_brightness_selected.png') 1x, - url('../images/gallery/2x/icon_brightness_selected.png') 2x); -} - -.gallery > .toolbar button.rotate_right { - background-image: -webkit-image-set( - url('../images/gallery/icon_rotate.png') 1x, - url('../images/gallery/2x/icon_rotate.png') 2x); -} - -.gallery > .toolbar button.rotate_right:active, -.gallery > .toolbar button.rotate_right[pressed] { - background-image: -webkit-image-set( - url('../images/gallery/icon_rotate_selected.png') 1x, - url('../images/gallery/2x/icon_rotate_selected.png') 2x); -} - -.gallery > .toolbar button.rotate_left { - background-image: -webkit-image-set( - url('../images/gallery/icon_rotate_left.png') 1x, - url('../images/gallery/2x/icon_rotate_left.png') 2x); -} - -.gallery > .toolbar button.rotate_left:active, -.gallery > .toolbar button.rotate_left[pressed] { - background-image: -webkit-image-set( - url('../images/gallery/icon_rotate_left_selected.png') 1x, - url('../images/gallery/2x/icon_rotate_left_selected.png') 2x); -} - -.gallery > .toolbar button.undo { - background-image: -webkit-image-set( - url('../images/gallery/icon_undo.png') 1x, - url('../images/gallery/2x/icon_undo.png') 2x); -} - -.gallery > .toolbar button.undo:active, -.gallery > .toolbar button.undo[pressed] { - background-image: -webkit-image-set( - url('../images/gallery/icon_undo_selected.png') 1x, - url('../images/gallery/2x/icon_undo_selected.png') 2x); -} - -.gallery > .toolbar button.redo { - background-image: -webkit-image-set( - url('../images/gallery/icon_redo.png') 1x, - url('../images/gallery/2x/icon_redo.png') 2x); - position: absolute; /* Exclude from center-packing*/ -} - -.gallery > .toolbar button.redo:active, -.gallery > .toolbar button.redo[pressed] { - background-image: -webkit-image-set( - url('../images/gallery/icon_redo_selected.png') 1x, - url('../images/gallery/2x/icon_redo_selected.png') 2x); -} - -.gallery > .toolbar button[disabled], -.gallery[tools][locked] > .toolbar button { - opacity: 0.5; - pointer-events: none; -} - -.gallery > .toolbar button[hidden] { - display: none; -} - -.gallery[mode='slide'] > .toolbar > button.mode { - background-image: -webkit-image-set( - url('../images/gallery/icon_mosaic.png') 1x, - url('../images/gallery/2x/icon_mosaic.png') 2x); -} - -.gallery[mode='slide'] > .toolbar > button.mode:active { - background-image: -webkit-image-set( - url('../images/gallery/icon_mosaic_selected.png') 1x, - url('../images/gallery/2x/icon_mosaic_selected.png') 2x); -} - -.gallery[mode='mosaic'] > .toolbar > button.mode { - background-image: -webkit-image-set( - url('../images/gallery/icon_1up.png') 1x, - url('../images/gallery/2x/icon_1up.png') 2x); -} - -.gallery[mode='mosaic'] > .toolbar > button.mode:active { - background-image: -webkit-image-set( - url('../images/gallery/icon_1up_selected.png') 1x, - url('../images/gallery/2x/icon_1up_selected.png') 2x); -} - -.gallery > .toolbar > button.slideshow { - background-image: -webkit-image-set( - url('../images/gallery/icon_slideshow.png') 1x, - url('../images/gallery/2x/icon_slideshow.png') 2x); -} - -.gallery > .toolbar > button.slideshow:active, -.gallery > .toolbar > button.slideshow[pressed] { - background-image: -webkit-image-set( - url('../images/gallery/icon_slideshow_selected.png') 1x, - url('../images/gallery/2x/icon_slideshow_selected.png') 2x); -} - -.gallery > .toolbar > button.delete { - background-image: -webkit-image-set( - url('../images/gallery/icon_delete.png') 1x, - url('../images/gallery/2x/icon_delete.png') 2x); -} - -.gallery > .toolbar > button.delete:active { - background-image: -webkit-image-set( - url('../images/gallery/icon_delete_selected.png') 1x, - url('../images/gallery/2x/icon_delete_selected.png') 2x); -} - -.gallery > .toolbar > button.edit { - background-image: -webkit-image-set( - url('../images/gallery/icon_edit.png') 1x, - url('../images/gallery/2x/icon_edit.png') 2x); -} - -.gallery > .toolbar > button.edit:active, -.gallery > .toolbar > button.edit[pressed] { - background-image: -webkit-image-set( - url('../images/gallery/icon_edit_selected.png') 1x, - url('../images/gallery/2x/icon_edit_selected.png') 2x); -} - -.gallery > .toolbar > button.print { - background-image: -webkit-image-set( - url('../images/gallery/icon_print.png') 1x, - url('../images/gallery/2x/icon_print.png') 2x); -} - -.gallery > .toolbar > button.print:active, -.gallery > .toolbar > button.print[pressed] { - background-image: -webkit-image-set( - url('../images/gallery/icon_print_selected.png') 1x, - url('../images/gallery/2x/icon_print_selected.png') 2x); -} - -.gallery > .toolbar > button.share { - background-image: -webkit-image-set( - url('../images/gallery/icon_share.png') 1x, - url('../images/gallery/2x/icon_share.png') 2x); -} - -.gallery > .toolbar > button.share:active, -.gallery > .toolbar > button.share[pressed] { - background-image: -webkit-image-set( - url('../images/gallery/icon_share_selected.png') 1x, - url('../images/gallery/2x/icon_share_selected.png') 2x); -} - -.gallery > .toolbar > button.share[disabled] { - display: none; -} - -/* Secondary toolbar (mode-specific tools) */ - -.gallery .edit-modal { - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - bottom: 80px; - display: -webkit-box; - height: 40px; - pointer-events: none; - position: absolute; - width: 100%; -} - -.gallery .edit-modal-wrapper[hidden] { - display: none; -} - -.gallery .edit-modal-wrapper { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - background-color: rgba(0, 0, 0, 0.75); - color: white; - display: -webkit-box; - padding-right: 5px; - pointer-events: auto; -} - -.gallery .edit-modal .label { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - background-position: 20px center; - background-repeat: no-repeat; - display: -webkit-box; - height: 20px; - padding-left: 50px; - padding-right: 10px; -} - -.gallery .edit-modal .label.brightness { - background-image: -webkit-image-set( - url('../images/gallery/icon_brightness.png') 1x, - url('../images/gallery/2x/icon_brightness.png') 2x); -} - -.gallery .edit-modal .label.contrast { - background-image: -webkit-image-set( - url('../images/gallery/icon_contrast.png') 1x, - url('../images/gallery/2x/icon_contrast.png') 2x); - height: 24px; - margin-left: 15px; -} - -.gallery .edit-modal .range { - -webkit-appearance: none !important; - height: 3px; - margin-right: 10px; - margin-top: 1px; -} - -.gallery .edit-modal .range::-webkit-slider-thumb { - -webkit-appearance: none; - background-image: -webkit-image-set( - url('../images/gallery/slider_thumb.png') 1x, - url('../images/gallery/2x/slider_thumb.png') 2x); - height: 29px; - width: 16px; -} - -/* Crop frame */ - -.gallery .crop-overlay { - -webkit-box-orient: vertical; - display: -webkit-box; - pointer-events: none; - position: absolute; -} - -.gallery .crop-overlay .shadow { - background-color: rgba(0, 0, 0, 0.65); -} - -.gallery .crop-overlay .middle-box { - -webkit-box-flex: 1; - -webkit-box-orient: horizontal; - display: -webkit-box; -} - -.gallery .crop-frame { - -webkit-box-flex: 1; - display: -webkit-box; - position: relative; -} - -.gallery .crop-frame div { - background-color: rgba(255, 255, 255, 1); - box-shadow: 0 0 3px rgba(0, 0, 0, 0.75); - position: absolute; -} - -.gallery .crop-frame .horizontal { - height: 1px; - left: 7px; - right: 7px; -} - -.gallery .crop-frame .horizontal.top { - top: 0; -} - -.gallery .crop-frame .horizontal.bottom { - bottom: 0; -} - -.gallery .crop-frame .vertical { - bottom: 7px; - top: 7px; - width: 1px; -} - -.gallery .crop-frame .vertical.left { - left: 0; -} - -.gallery .crop-frame .vertical.right { - right: 0; -} - -.gallery .crop-frame .corner { - border-radius: 6px; - height: 13px; - width: 13px; -} - -.gallery .crop-frame .corner.left { - left: -6px; -} - -.gallery .crop-frame .corner.right { - right: -6px; -} - -.gallery .crop-frame .corner.top { - top: -6px; -} - -.gallery .crop-frame .corner.bottom { - bottom: -6px; -} - -/* Prompt/notification panel */ - -.gallery .prompt-wrapper { - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - display: -webkit-box; - height: 100%; - pointer-events: none; - position: absolute; - width: 100%; -} - -.gallery .prompt-wrapper[pos=top] { - -webkit-box-align: start; -} - -.gallery .prompt-wrapper[pos=center] { - -webkit-box-align: center; -} - -.gallery .prompt-wrapper[pos=center] .back-button { - display: none; -} - -.gallery .prompt-wrapper > div.dimmable { - opacity: 1; - transition: opacity 220ms ease; -} - -.gallery .prompt { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - background-color: rgba(0, 0, 0, 0.8); - color: white; - display: -webkit-box; - font-size: 120%; - height: 40px; - opacity: 0; - padding: 0 20px; - position: relative; - top: 5px; - transition: all 180ms ease; -} - -.gallery .prompt[state='fadein'] { - opacity: 1; - top: 0; -} - -.gallery .prompt[state='fadeout'] { - opacity: 0; - top: 0; -} - -.gallery .prompt-wrapper[pos=top] .prompt { - padding-right: 10px; -} - -.gallery .prompt .back-button { - background-image: -webkit-image-set( - url('../images/gallery/butterbar_close_button.png') 1x, - url('../images/gallery/2x/butterbar_close_button.png') 2x); - background-position: center center; - background-repeat: no-repeat; - height: 16px; - margin-left: 16px; - opacity: 0.65; - pointer-events: auto; - width: 16px; -} - -.gallery .prompt .back-button:hover { - background-color: rgba(81, 81, 81, 1); - opacity: 1.0; -} - -.gallery .share-menu { - -webkit-box-align: stretch; - -webkit-box-orient: vertical; - -webkit-box-pack: start; - background-color: white; - border: 1px solid #7f7f7f; - border-radius: 1px; - bottom: 60px; - display: -webkit-box; - opacity: 1.0; - padding: 8px; - position: absolute; - right: 10px; - transition: opacity 500ms ease-in-out; -} - -.gallery .share-menu .bubble-point { - background-image: -webkit-image-set( - url('../images/gallery/bubble_point.png') 1x, - url('../images/gallery/2x/bubble_point.png') 2x); - background-position: center top; - background-repeat: no-repeat; - bottom: -8px; - height: 8px; - padding: 0; - position: absolute; - right: 20px; - width: 20px; -} - -.gallery .share-menu[hidden] { - bottom: -100%; /* Offscreen so that 'dimmed' attribute does not show it. */ - opacity: 0; - pointer-events: none; -} - -.gallery .share-menu > .item { - background-color: rgba(0, 0, 0, 0); - background-position: 5px center; - background-repeat: no-repeat; - cursor: pointer; - padding: 5px; - padding-left: 26px; -} - -.gallery .share-menu > .item:hover { - background-color: rgba(240, 240, 240, 1); -} - -.gallery .share-menu > div > img { - display: block; - margin-right: 5px; -} - -/* Load spinner and error banner. */ - -.gallery .spinner { - background-image: url(../images/common/spinner.svg); - background-size: 100%; - height: 16px; - left: 50%; - margin-left: -8px; - margin-top: -8px; - position: absolute; - top: 50%; - width: 16px; -} - -.gallery:not([spinner]) .spinner { - display: none; -} - -.gallery .error-banner { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - background-color: rgba(24, 24, 24, 1); - background-image: -webkit-image-set( - url('../images/media/error.png') 1x, - url('../images/media/2x/error.png') 2x); - background-position: 25px center; - background-repeat: no-repeat; - color: white; - display: -webkit-box; - height: 54px; - padding-left: 70px; - padding-right: 35px; -} - -.gallery:not([error]) .error-banner { - display: none; -} - -/* Video playback support. */ - -.gallery video { - height: 100%; - position: absolute; - width: 100%; -} - -.gallery .video-controls-spacer { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - bottom: 60px; /* Just above the toolbar */ - display: -webkit-box; - height: 30px; - left: 0; - opacity: 0; - pointer-events: none; - position: absolute; - right: 0; -} - -.gallery[video] .video-controls-spacer { - /* Animate opacity on 'tools' attribute toggle. */ - /* Change opacity immediately on 'video' attribute change. */ - transition: opacity 280ms ease; -} - -.gallery[video][tools] .video-controls-spacer { - opacity: 1; -} - -.gallery .video-controls { - display: none; - max-width: 800px; -} - -.gallery[video] .video-controls { - -webkit-box-flex: 1; - display: -webkit-box; -} - -.gallery[video] > .toolbar .edit-main { - display: none; -} - -/* Mosaic view. */ -.mosaic { - bottom: 55px; /* Toolbar height. */ - left: 0; - overflow-x: scroll; - overflow-y: hidden; - position: absolute; - right: 0; - top: 0; - - /* transition-duration is set in Javascript. */ - transition-property: -webkit-transform; - transition-timing-function: linear; -} - -.mosaic::-webkit-scrollbar { - background: transparent; -} - -.mosaic::-webkit-scrollbar-thumb { - background: rgb(31, 31, 31); -} - -.gallery:not([mode='mosaic']) .mosaic::-webkit-scrollbar-thumb { - background: transparent; -} - -.mosaic-tile { - position: absolute; - /* Tile's zoom factor is animated on hover. We apply the transform to - the entire tile so that the image outline is included into the animation. */ - transition: -webkit-transform 150ms linear; -} - -/* Mosaic tile's opacity is controlled by |visible| attribute which changes - separately from .gallery[mode] */ -.mosaic:not([visible]) .mosaic-tile .img-border { - opacity: 0; -} - -/* Animate tile's opacity, except for the selected tile which should show/hide - instantly (this looks better when zooming to/from the slide mode). */ -.mosaic-tile:not([selected]) .img-border { - transition: opacity 350ms linear; -} - -/* Must be in sync with mosaic_mode.js. - Mosaic.Layout.SPACING should be equal to - top + bottom + border-top-width + border-bottom-width AND - left + right + border-left-width + border-right-width */ -.mosaic-tile .img-border { - border: 1px solid black; /* Space between the outline and the image. */ - bottom: 4px; - left: 4px; - outline: 2px solid transparent; - overflow: hidden; - position: absolute; - right: 4px; - top: 4px; -} - -/* Selected and hover state are only visible when zoom transition is over. */ -.mosaic[visible='normal'] .mosaic-tile[selected] .img-border { - outline-color: rgb(51, 153, 255); -} - -.mosaic[visible='normal'].hover-visible .mosaic-tile:hover { - -webkit-transform: scale(1.05); - z-index: 50; -} - -.mosaic[visible='normal'].hover-visible - .mosaic-tile:hover:not([selected]) .img-border { - outline-color: rgb(182, 212, 252); -} - -.mosaic-tile .img-wrapper { - bottom: 0; - left: 0; - position: absolute; - right: 0; - top: 0; -} - -.mosaic-tile .img-wrapper[generic-thumbnail], -.mosaic-tile .img-wrapper.animated:not([generic-thumbnail]) - canvas:not(.cached) { - -webkit-animation: fadeIn ease-in 1; - -webkit-animation-duration: 500ms; - -webkit-animation-fill-mode: forwards; -} - -@-webkit-keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -/* In order to do mode animated transitions smoothly we keep both mosaic and - image-container but transparent. */ -.gallery:not([mode='mosaic']) .mosaic, -.gallery:not([mode='slide']) .image-container { - pointer-events: none; -} - -.gallery:not([mode='slide']) .ribbon, -.gallery:not([mode='slide']) .arrow-box { - opacity: 0; - pointer-events: none; -} - -/* Temporary. Remove this along with the delete confirmation dialog - when Undo delete is implemented. */ -.cr-dialog-shield { - background-color: black; -} - -/* Slideshow controls */ - -.slideshow-toolbar { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - bottom: 0; - display: none; - left: 0; - padding-bottom: 6px; - pointer-events: none; - position: absolute; - right: 0; -} - -.gallery[tools][slideshow] .slideshow-toolbar { - display: -webkit-box; -} - -.slideshow-toolbar > div { - background-position: center; - background-repeat: no-repeat; - height: 68px; - opacity: 0.5; - pointer-events: auto; - width: 68px; -} - -.slideshow-toolbar > div:hover { - opacity: 1; -} - -.slideshow-toolbar > .slideshow-play { - background-image: -webkit-image-set( - url('../images/gallery/slideshow-play.png') 1x, - url('../images/gallery/2x/slideshow-play.png') 2x); - margin-right: -2px; -} - -.gallery[slideshow='playing'] .slideshow-toolbar > .slideshow-play { - background-image: -webkit-image-set( - url('../images/gallery/slideshow-pause.png') 1x, - url('../images/gallery/2x/slideshow-pause.png') 2x); -} - -.slideshow-toolbar > .slideshow-end { - background-image: -webkit-image-set( - url('../images/gallery/slideshow-end.png') 1x, - url('../images/gallery/2x/slideshow-end.png') 2x); - margin-left: -2px; -} - -.gallery > .header > button { - -webkit-margin-start: 10px; - cursor: default; - height: 32px; - min-width: 32px; - width: 32px; -} - -.gallery > .header > .maximize-button { - background: -webkit-image-set( - url('chrome://resources/images/apps/topbar_button_maximize.png') 1x, - url('chrome://resources/images/2x/apps/topbar_button_maximize.png') 2x) - center; -} - -.gallery > .header > .close-button { - background: -webkit-image-set( - url('chrome://resources/images/apps/topbar_button_close.png') 1x, - url('chrome://resources/images/2x/apps/topbar_button_close.png') 2x) - center; -} diff --git a/chromium/chrome/browser/resources/file_manager/foreground/css/list.css b/chromium/chrome/browser/resources/file_manager/foreground/css/list.css deleted file mode 100644 index d102d696dcd..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/css/list.css +++ /dev/null @@ -1,73 +0,0 @@ -/* Copyright 2013 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. */ - -/* Derived from /ui/webui/resources/css/list.css. */ - -list, -grid { - display: block; - outline: none; - overflow: auto; - position: relative; /* Make sure that item offsets are relative to the - list. */ -} - -list > *, -grid > * { - -webkit-user-select: none; - position: relative; /* to allow overlap */ - text-overflow: ellipsis; - white-space: pre; -} - -list > * { - display: block; -} - -grid > * { - display: inline-block; -} - -list:focus > [lead], -grid:focus > [lead] { - z-index: 2; -} - -list:not([disabled]) > :hover, -grid:not([disabled]) > :hover { - z-index: 1; -} - -list > [selected], -grid > [selected] { - z-index: 2; -} - -list > .spacer, -grid > .spacer { - box-sizing: border-box; - display: block; - overflow: hidden; - visibility: hidden; -} - -list :-webkit-any( - input[type='input'], - input[type='password'], - input[type='search'], - input[type='text'], - input[type='url']), -list :-webkit-any( - button, - input[type='button'], - input[type='submit'], - select):not(.custom-appearance):not(.link-button) { - line-height: normal; - vertical-align: middle; -} - -list > [hidden], -grid > [hidden] { - display: none; -} diff --git a/chromium/chrome/browser/resources/file_manager/foreground/css/media_controls.css b/chromium/chrome/browser/resources/file_manager/foreground/css/media_controls.css deleted file mode 100644 index ba167eec138..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/css/media_controls.css +++ /dev/null @@ -1,605 +0,0 @@ -/* 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. */ - -.media-button { - height: 28px; - position: relative; - width: 26px; -} - -.media-button > div { - height: 100%; - opacity: 0; - pointer-events: none; - position: absolute; - transition: opacity 100ms linear; - width: 100%; -} - -.media-button[state='default']:not(.disabled):not(:hover):not(:active) > - .default.normal, -.media-button[state='default']:not(.disabled):hover > .default.hover, -.media-button[state='default']:not(.disabled):active > .default.active, -.media-button[state='playing']:not(.disabled):not(:hover):not(:active) > - .playing.normal, -.media-button[state='playing']:not(.disabled):hover > .playing.hover, -.media-button[state='playing']:not(.disabled):active > .playing.active, -.media-button[state='ended']:not(.disabled):not(:hover):not(:active) > - .ended.normal, -.media-button[state='ended']:not(.disabled):hover > .ended.hover, -.media-button[state='ended']:not(.disabled):active > .ended.active, -.media-button.disabled > .disabled { - opacity: 1; -} - -/* Custom sliders for progress and volume. */ - -/* Customize the standard input[type='range']. */ -.custom-slider > input[type='range'] { - -webkit-appearance: none !important; /* Hide the default thumb icon. */ - background: transparent; /* Hide the standard slider bar */ - height: 100%; - left: -2px; /* Required to align the input element with the parent. */ - outline: none; - position: absolute; - top: -2px; - width: 100%; -} - -/* Custom thumb icon. */ -.custom-slider > input[type='range']::-webkit-slider-thumb { - -webkit-appearance: none; - background-position: center center; - background-repeat: no-repeat; - height: 24px; - position: relative; - z-index: 2; -} - -/* Custom slider bar (we hide the standard one). */ -.custom-slider > .bar { - /* In order to match the horizontal position of the standard slider bar - left and right must be equal to 1/2 of the thumb icon width. */ - border-bottom-style: solid; - border-top-style: solid; - border-width: 1px; - bottom: 11px; - pointer-events: none; /* Mouse events pass through to the standard input. */ - position: absolute; - top: 11px; -} - -.custom-slider > .bar > .filled, -.custom-slider > .bar > .cap { - border-style: solid; - border-width: 1px; - bottom: -1px; - position: absolute; - top: -1px; -} - -/* The filled portion of the slider bar to the left of the thumb. */ -.custom-slider > .bar > .filled { - border-left-style: none; - border-right-style: none; - left: 0; - width: 0; /* The element style.width is manipulated from the code. */ -} - -/* Rounded caps to the left and right of the slider bar. */ -.custom-slider > .bar > .cap { - width: 4px; -} - -/* Left cap is always filled, should be the same color as .filled. */ -.custom-slider > .bar > .cap.left { - border-bottom-left-radius: 4px; - border-right-style: none; - border-top-left-radius: 4px; - right: 100%; -} - -/* Right cap is always not filled. */ -.custom-slider > .bar > .cap.right { - border-bottom-right-radius: 4px; - border-left-style: none; - border-top-right-radius: 4px; - left: 100%; -} - -.custom-slider > .bar, -.custom-slider > .bar > .cap.right { - background-color: rgba(0, 0, 0, 0.5); - border-color: #808080; -} - -.custom-slider > .bar > .filled, -.custom-slider > .bar > .cap.left { - background-image: linear-gradient(#c3c3c3, #d9d9d9); - border-color: #d9d9d9; -} - -.custom-slider.disabled > .bar > .filled, -.custom-slider.disabled > .bar > .cap.left { - background-color: rgba(0, 0, 0, 0.5); - background-image: none; -} - -.custom-slider.disabled > .bar, -.custom-slider.disabled > .bar > .filled, -.custom-slider.disabled > .bar > .cap { - border-color: #404040; -} - -.media-button.disabled, -.custom-slider.disabled, -.custom-slider.readonly { - pointer-events: none; -} - -/* Progress seek marker (precise time shown on mouse hover. */ - -/* Thin vertical line across the slider bar */ -.custom-slider > .bar > .seek-mark { - background-color: #202020; - bottom: -1px; - left: 0; - position: absolute; - top: -1px; - width: 0; -} - -.custom-slider > .bar > .seek-mark.visible { - width: 1px; -} - -.custom-slider > .bar > .seek-mark.inverted { - background-color: #808080; -} - -/* Text label giving the precise time corresponding to the hover position. */ -.custom-slider > .bar > .seek-mark > .seek-label { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - background: #202020; - border-top-left-radius: 2px; - border-top-right-radius: 2px; - bottom: 19px; - color: white; - display: -webkit-box; - font-size: 13px; - height: 15px; - left: 0; - opacity: 0; - overflow: hidden; - position: absolute; - transition: opacity 150ms ease; -} - -.custom-slider > .bar > .seek-mark.visible > .seek-label { - opacity: 1; -} - -/* Media controls in order of appearance. */ - -/* Play/pause button. */ - -.media-button.play { - margin-left: -7px; - margin-right: -7px; -} - -.media-button.play > .default.normal { - background-image: -webkit-image-set( - url('../images/media/media_play.png') 1x, - url('../images/media/2x/media_play.png') 2x); -} - -.media-button.play > .default.hover { - background-image: -webkit-image-set( - url('../images/media/media_play_hover.png') 1x, - url('../images/media/2x/media_play_hover.png') 2x); -} - -.media-button.play > .default.active { - background-image: -webkit-image-set( - url('../images/media/media_play_down.png') 1x, - url('../images/media/2x/media_play_down.png') 2x); -} - -.media-button.play > .playing.normal { - background-image: -webkit-image-set( - url('../images/media/media_pause.png') 1x, - url('../images/media/2x/media_pause.png') 2x); -} - -.media-button.play > .playing.hover { - background-image: -webkit-image-set( - url('../images/media/media_pause_hover.png') 1x, - url('../images/media/2x/media_pause_hover.png') 2x); -} - -.media-button.play > .playing.active { - background-image: -webkit-image-set( - url('../images/media/media_pause_down.png') 1x, - url('../images/media/2x/media_pause_down.png') 2x); -} - -.media-button.play > .ended.normal { - background-image: -webkit-image-set( - url('../images/media/media_loop.png') 1x, - url('../images/media/2x/media_loop.png') 2x); -} - -.media-button.play > .ended.hover { - background-image: -webkit-image-set( - url('../images/media/media_loop_hover.png') 1x, - url('../images/media/2x/media_loop_hover.png') 2x); -} - -.media-button.play > .ended.active { - background-image: -webkit-image-set( - url('../images/media/media_loop_down.png') 1x, - url('../images/media/2x/media_loop_down.png') 2x); -} - -.media-button.play > .disabled { - background-image: -webkit-image-set( - url('../images/media/media_play_disabled.png') 1x, - url('../images/media/2x/media_play_disabled.png') 2x); -} - -/* Time controls: a slider and a text time display. */ - -.time-controls { - -webkit-box-align: center; - -webkit-box-flex: 1; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - display: -webkit-box; - height: 100%; -} - -.custom-slider.progress { - -webkit-box-flex: 1; - display: -webkit-box; - height: 100%; - margin-left: -9px; /* Set the margins at the edges of the slider bar. */ - margin-right: -9px; - position: relative; -} - -.custom-slider.progress > input[type='range']::-webkit-slider-thumb { - background-image: -webkit-image-set( - url('../images/media/media_slider_thumb.png') 1x, - url('../images/media/2x/media_slider_thumb.png') 2x); - width: 28px; -} - -.custom-slider.progress > input[type='range']::-webkit-slider-thumb:hover { - background-image: -webkit-image-set( - url('../images/media/media_slider_thumb_hover.png') 1x, - url('../images/media/2x/media_slider_thumb_hover.png') 2x); -} - -.custom-slider.progress > input[type='range']::-webkit-slider-thumb:active { - background-image: -webkit-image-set( - url('../images/media/media_slider_thumb_down.png') 1x, - url('../images/media/2x/media_slider_thumb_down.png') 2x); -} - -.custom-slider.progress.disabled > input[type='range']::-webkit-slider-thumb { - background-image: none; -} - -.custom-slider.progress > .bar { - left: 14px; /* Exactly 1/2 of the thumb width */ - right: 14px; -} - -/* Time display. */ - -.time-controls > .time { - cursor: default; - height: 100%; - margin-left: 15px; - position: relative; -} - -.time-controls > .time.disabled { - opacity: 0; -} - -/* Invisible div used to compute the width required for the elapsed time. */ -.time-controls > .time > .duration { - color: transparent; -} - -.time-controls > .time > .current { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: end; - color: white; - display: -webkit-box; - height: 100%; - position: absolute; - right: 0; - top: -1px; -} - -/* Volume controls: sound button and volume slider */ - -.volume-controls { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - display: -webkit-box; - height: 100%; -} - -/* Sound button */ - -.media-button.sound { - margin-left: -4px; - width: 31px; -} - -.media-button.sound[level='0'] > .normal { - background-image: -webkit-image-set( - url('../images/media/media_sound_disabled.png') 1x, - url('../images/media/2x/media_sound_disabled.png') 2x); -} - -.media-button.sound[level='0'] > .hover { - background-image: -webkit-image-set( - url('../images/media/media_sound_disabled_hover.png') 1x, - url('../images/media/2x/media_sound_disabled_hover.png') 2x); -} - -.media-button.sound[level='0'] > .active { - background-image: -webkit-image-set( - url('../images/media/media_sound_disabled_down.png') 1x, - url('../images/media/2x/media_sound_disabled_down.png') 2x); -} - - -.media-button.sound[level='1'] > .normal { - background-image: -webkit-image-set( - url('../images/media/media_sound_level1.png') 1x, - url('../images/media/2x/media_sound_level1.png') 2x); -} - -.media-button.sound[level='1'] > .hover { - background-image: -webkit-image-set( - url('../images/media/media_sound_level1_hover.png') 1x, - url('../images/media/2x/media_sound_level1_hover.png') 2x); -} - -.media-button.sound[level='1'] > .active { - background-image: -webkit-image-set( - url('../images/media/media_sound_level1_down.png') 1x, - url('../images/media/2x/media_sound_level1_down.png') 2x); -} - - -.media-button.sound[level='2'] > .normal { - background-image: -webkit-image-set( - url('../images/media/media_sound_level2.png') 1x, - url('../images/media/2x/media_sound_level2.png') 2x); -} - -.media-button.sound[level='2'] > .hover { - background-image: -webkit-image-set( - url('../images/media/media_sound_level2_hover.png') 1x, - url('../images/media/2x/media_sound_level2_hover.png') 2x); -} - -.media-button.sound[level='2'] > .active { - background-image: -webkit-image-set( - url('../images/media/media_sound_level2_down.png') 1x, - url('../images/media/2x/media_sound_level2_down.png') 2x); -} - - -.media-button.sound[level='3'] > .normal { - background-image: -webkit-image-set( - url('../images/media/media_sound_full.png') 1x, - url('../images/media/2x/media_sound_full.png') 2x); -} - -.media-button.sound[level='3'] > .hover { - background-image: -webkit-image-set( - url('../images/media/media_sound_full_hover.png') 1x, - url('../images/media/2x/media_sound_full_hover.png') 2x); -} - -.media-button.sound[level='3'] > .active { - background-image: -webkit-image-set( - url('../images/media/media_sound_full_down.png') 1x, - url('../images/media/2x/media_sound_full_down.png') 2x); -} - - -.media-button.sound > .disabled { - background-image: -webkit-image-set( - url('../images/media/media_sound_full_disabled.png') 1x, - url('../images/media/2x/media_sound_full_disabled.png') 2x); -} - -/* Volume slider. */ - -.custom-slider.volume { - height: 100%; - margin-left: -4px; - margin-right: -4px; - position: relative; - width: 60px; -} - -.custom-slider.volume > input[type='range']::-webkit-slider-thumb { - background-image: -webkit-image-set( - url('../images/media/media_volume_slider_thumb.png') 1x, - url('../images/media/2x/media_volume_slider_thumb.png') 2x); - width: 20px; -} - -.custom-slider.volume > input[type='range']::-webkit-slider-thumb:hover { - background-image: -webkit-image-set( - url('../images/media/media_volume_slider_thumb_hover.png') 1x, - url('../images/media/2x/media_volume_slider_thumb_hover.png') 2x); -} - -.custom-slider.volume > input[type='range']::-webkit-slider-thumb:active { - background-image: -webkit-image-set( - url('../images/media/media_volume_slider_thumb_down.png') 1x, - url('../images/media/2x/media_volume_slider_thumb_down.png') 2x); -} - -.custom-slider.volume.disabled > input[type='range']::-webkit-slider-thumb { - background-image: none; -} - -.custom-slider.volume > .bar { - left: 10px; /* Exactly 1/2 of the thumb width */ - right: 10px; -} - -/* Horizontal video control bar, all controls in a row. */ - -.video-controls { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - background: #202020; - border-radius: 5px; - display: -webkit-box; - font-size: 15px; - height: 30px; - opacity: 0.8; - padding-left: 15px; - padding-right: 15px; - pointer-events: auto; -} - -.video-controls .time-controls, -.video-controls .volume-controls { - margin-left: 15px; -} - -/* Fullscreen button. */ -/* There is no final decision whether we need a separate icon when toggled. */ - -.media-button.fullscreen { - margin-left: 9px; /* 15px visible margin - 6px whitespace in the icon. */ - margin-right: -6px; -} - -.media-button.fullscreen > .normal { - background-image: -webkit-image-set( - url('../images/media/media_fullscreen.png') 1x, - url('../images/media/2x/media_fullscreen.png') 2x); -} - -.media-button.fullscreen > .hover { - background-image: -webkit-image-set( - url('../images/media/media_fullscreen_hover.png') 1x, - url('../images/media/2x/media_fullscreen_hover.png') 2x); -} - -.media-button.fullscreen > .active { - background-image: -webkit-image-set( - url('../images/media/media_fullscreen_down.png') 1x, - url('../images/media/2x/media_fullscreen_down.png') 2x); -} - -.media-button.fullscreen > .disabled { - background-image: -webkit-image-set( - url('../images/media/media_fullscreen_disabled.png') 1x, - url('../images/media/2x/media_fullscreen_disabled.png') 2x); -} - -.playback-state-icon { - background-color: #202020; - background-position: center center; - background-repeat: no-repeat; - border-radius: 2.5px; - height: 32px; - left: 50%; - margin-left: -16px; - margin-top: -16px; - opacity: 0; - pointer-events: none; - position: absolute; - top: 50%; - width: 32px; - z-index: 2; -} - -.text-banner { - background-color: black; - border-radius: 10px; - color: white; - font-size: 18px; - left: 50%; - margin-left: -250px; - opacity: 0; - padding: 10px; - pointer-events: none; - position: absolute; - text-align: center; - text-shadow: 0 0 10px black; - top: 20%; - width: 500px; - z-index: 2; -} - -.text-banner[visible] { - -webkit-animation: text-banner-blowup 3000ms; -} - -.playback-state-icon[state] { - -webkit-animation: blowup 500ms; -} - -@-webkit-keyframes blowup { - from { - opacity: 1; - } - to { - -webkit-transform: scale(3); - opacity: 0; - } -} - -@-webkit-keyframes text-banner-blowup { - from { - -webkit-transform: scale(0.5); - opacity: 0; - } - 20% { - -webkit-transform: scale(1); - opacity: 0.75; - } - 80% { - -webkit-transform: scale(1); - opacity: 0.75; - } - to { - -webkit-transform: scale(3); - opacity: 0; - } -} - -.playback-state-icon[state='play'] { - background-image: -webkit-image-set( - url('../images/media/media_play.png') 1x, - url('../images/media/2x/media_play.png') 2x); -} - -.playback-state-icon[state='pause'] { - background-image: -webkit-image-set( - url('../images/media/media_pause.png') 1x, - url('../images/media/2x/media_pause.png') 2x); -} diff --git a/chromium/chrome/browser/resources/file_manager/foreground/css/menu.css b/chromium/chrome/browser/resources/file_manager/foreground/css/menu.css deleted file mode 100644 index 2f32d05752f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/css/menu.css +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright 2013 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. */ - -/* Derived from /ui/webui/resources/css/menu.css. */ - -menu { - position: fixed; - white-space: nowrap; - z-index: 3; -} - -menu:not(.decorated) { - display: none; -} - -menu > * { - box-sizing: border-box; - display: block; - text-align: start; - width: 100%; -} - -menu > hr { - border: 0; - height: 1px; -} - -menu > [hidden] { - display: none; -} - -menu > [shortcutText]::after { - -webkit-padding-start: 30px; - color: #999; - content: attr(shortcutText); - float: right; -} diff --git a/chromium/chrome/browser/resources/file_manager/foreground/css/table.css b/chromium/chrome/browser/resources/file_manager/foreground/css/table.css deleted file mode 100644 index 83516993103..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/css/table.css +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright 2013 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. */ - -/* Derived from /ui/webui/resources/css/table.css. */ - -html.col-resize * { - cursor: col-resize !important; -} - -.table[hasElementFocus] > list > [lead] { - z-index: 2; -} - -.table-row { - display: -webkit-box; - text-align: start; - width: 100%; -} - -.table-row-cell { - display: -webkit-box; - overflow: hidden; -} - -.table-row-cell > * { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.table-header { - overflow: hidden; - position: relative; -} - -.table-header-inner { - -webkit-user-select: none; - cursor: default; - display: -webkit-box; - position: relative; - text-align: start; -} - -.table-header-cell { - font-weight: normal; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.table-header-label { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.table-header-splitter { - cursor: col-resize; - height: 100%; - left: 0; - position: absolute; - top: 0; -} diff --git a/chromium/chrome/browser/resources/file_manager/foreground/css/tree.css b/chromium/chrome/browser/resources/file_manager/foreground/css/tree.css deleted file mode 100644 index e151977f754..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/css/tree.css +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright 2013 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. */ - -/* Derived from /ui/webui/resources/css/table.css. */ - -tree { - display: block; - outline: none; - overflow: auto; -} - -.tree-item > .tree-row { - -webkit-user-select: none; - cursor: default; - position: relative; - white-space: nowrap; -} - -.expand-icon { - -webkit-transform: rotate(-90deg); - -webkit-transition: all 150ms; - background-image: -webkit-canvas(tree-triangle); - background-position: 50% 50%; - background-repeat: no-repeat; - background-size: 8px 5px; - display: inline-block; - height: 16px; - position: relative; - vertical-align: top; -} - -html[dir=rtl] .expand-icon { - -webkit-transform: rotate(90deg); -} - -.tree-item[expanded] > .tree-row > .expand-icon { - -webkit-transform: rotate(0); - background-image: -webkit-canvas(tree-triangle); -} - -.tree-row .expand-icon { - visibility: hidden; -} - -.tree-row[may-have-children] .expand-icon { - visibility: visible; -} - -.tree-row[has-children=false] .expand-icon { - visibility: hidden; -} - -.tree-row[selected] { - z-index: 2; -} - -.tree-children[expanded] { - display: block; -} - -.tree-children { - display: none; -} - -.tree-item > .tree-row > * { - display: inline-block; -} - -.tree-label { - white-space: pre; -} - -/* We need to ensure that even empty labels take up space */ -.tree-label:empty::after { - content: ' '; - white-space: pre; -} - -.tree-rename > .tree-row > .tree-label { - -webkit-user-modify: read-write-plaintext-only; - -webkit-user-select: auto; -} diff --git a/chromium/chrome/browser/resources/file_manager/foreground/css/video_player.css b/chromium/chrome/browser/resources/file_manager/foreground/css/video_player.css deleted file mode 100644 index decb63dfee8..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/css/video_player.css +++ /dev/null @@ -1,103 +0,0 @@ -/* 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. */ - -body { - -webkit-user-select: none; - background: black; - font-family: Noto Sans UI,Droid Sans Fallback,sans-serif; - font-size: 84%; - margin: 0; - overflow: hidden; -} - -#video-player { - height: 100%; - left: 0; - position: absolute; - top: 0; - width: 100%; -} - -#video-container { - height: 100%; - left: 0; - position: absolute; - top: 0; - width: 100%; -} - -video { - height: 100%; - left: 0; - pointer-events: none; - position: absolute; - top: 0; - width: 100%; -} - -#controls-wrapper { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - bottom: 0; - display: -webkit-box; - left: 0; - position: absolute; - right: 0; -} - -#controls { - -webkit-box-flex: 1; - display: -webkit-box; -} - -#video-player:not([tools]) .tool { - opacity: 0; -} - -#video-player:not([tools]) { - cursor: none; -} - -#video-player[disabled] .tool { - display: none; -} - -.tool { - transition: opacity 180ms linear; -} - -#error-wrapper { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - display: -webkit-box; - height: 100%; - left: 0; - pointer-events: none; - position: absolute; - top: 0; - width: 100%; -} - -#error { - -webkit-box-align: center; - -webkit-box-orient: horizontal; - -webkit-box-pack: center; - background-color: rgba(24, 24, 24, 1); - background-image: -webkit-image-set( - url('../images/media/error.png') 1x, - url('../images/media/2x/error.png') 2x); - background-position: 25px center; - background-repeat: no-repeat; - color: white; - display: -webkit-box; - height: 54px; - padding-left: 70px; - padding-right: 35px; -} - -#error:not([visible]) { - display: none; -} diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/bubble_point_white.png b/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/bubble_point_white.png Binary files differdeleted file mode 100644 index 643847baee3..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/bubble_point_white.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/check_no_box.png b/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/check_no_box.png Binary files differdeleted file mode 100644 index 8dddff8fa17..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/check_no_box.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/checkbox_white_checked.png b/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/checkbox_white_checked.png Binary files differdeleted file mode 100644 index 466fa2266b3..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/checkbox_white_checked.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/checkbox_white_unchecked.png b/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/checkbox_white_unchecked.png Binary files differdeleted file mode 100644 index 88d97d7dd15..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/checkbox_white_unchecked.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/close_x_gray.png b/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/close_x_gray.png Binary files differdeleted file mode 100644 index 8a2930af8bd..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/close_x_gray.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/disclosure_arrow_dk_grey.png b/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/disclosure_arrow_dk_grey.png Binary files differdeleted file mode 100644 index 8f3531966e3..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/common/2x/disclosure_arrow_dk_grey.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/common/bubble_point_white.png b/chromium/chrome/browser/resources/file_manager/foreground/images/common/bubble_point_white.png Binary files differdeleted file mode 100644 index ec5dbe9580e..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/common/bubble_point_white.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/common/check_no_box.png b/chromium/chrome/browser/resources/file_manager/foreground/images/common/check_no_box.png Binary files differdeleted file mode 100644 index 3006dcd62f9..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/common/check_no_box.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/common/checkbox_white_checked.png b/chromium/chrome/browser/resources/file_manager/foreground/images/common/checkbox_white_checked.png Binary files differdeleted file mode 100644 index b24de30f8c8..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/common/checkbox_white_checked.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/common/checkbox_white_unchecked.png b/chromium/chrome/browser/resources/file_manager/foreground/images/common/checkbox_white_unchecked.png Binary files differdeleted file mode 100644 index c92eaaa2d91..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/common/checkbox_white_unchecked.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/common/close_x_gray.png b/chromium/chrome/browser/resources/file_manager/foreground/images/common/close_x_gray.png Binary files differdeleted file mode 100644 index 3ee375a32b5..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/common/close_x_gray.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/common/disclosure_arrow_dk_grey.png b/chromium/chrome/browser/resources/file_manager/foreground/images/common/disclosure_arrow_dk_grey.png Binary files differdeleted file mode 100644 index dd2f925b573..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/common/disclosure_arrow_dk_grey.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/common/spinner.svg b/chromium/chrome/browser/resources/file_manager/foreground/images/common/spinner.svg deleted file mode 100644 index 66b05c38ad2..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/common/spinner.svg +++ /dev/null @@ -1,13 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> -<svg viewBox="0 0 32 32" version="1.1" - xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> - -<g> - <animateTransform attributeName="transform" type="translate" - values="0 0; -32 0; -64 0; -96 0; -128 0; -160 0; -192 0; -224 0; -256 0; -288 0; -320 0; -352 0; -384 0; -416 0; -448 0; -480 0; -512 0; -544 0; -576 0; -608 0; -640 0; -672 0; -704 0; -736 0; -768 0; -800 0; -832 0; -864 0; -896 0; -928 0; -960 0; -992 0; -1024 0; -1056 0; -1088 0; -1120 0" - dur="1s" calcMode="discrete" repeatCount="indefinite" /> - <image width="1152" height="32" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABIAAAAAgCAYAAABq+wOnAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAQa9JREFUeNrsnQd8FFX+wKduTTaFQAghhBZ6R5oCFkBUBJWTZgHP3u487Hf27p2eXTw8CzZAxIKCgBRBOJVDEAXpoff0um3K//dLXnAz+ybZ3ew87q87Hx5JdmfmO6/+yrz3e3xGRgsuwoOH5IBkgyRnDX8iN6XLpc8JkqM/fGXjdK1M1/X9nK7+xAnCMp6XFsF5FY3ddOuMNjHxIUn4We64D/o6W552B8+Lybqu/KyrgVW6pi2QnOkVkdy0qXzynQ5JgRTsMHFpji2tg86Ltq3kc6Z8SAFIvm43H9BPRf7r+JHkPcojwU/wE/wEP8FP8BP8BD9mPuhGUcNBTzql/GDVcZdoS7qe0/Ucb8HPn+9fMHkHS76/eKdNcmVcIMjuqYBtpVYXfLbzvSHvsOIHyg86IP8X8pJ9JOj63TlBbAs/m6PtoQWrPt332cRbfQWbqyNtf9E+g+ItTuYF4SLQ688C26YX2DgteU5Iwa90XS0B++cY/NwJ9bMJymamnNLW35B+HS1fC1Rm6Jx2MS/IZ/KC1IXj+RaQ/wz4SgRmqa4pe3UtuEFX/SvUQNVimyfH15CeHwO/GfAnAP8M4PerYfNCGhSzDv/KgJ8P9tdPuuJfrqmBL2V3ZnVj9kY0z6Ap3tZQxsCXzoG67w58MFx5d02b07ViKPvjkP8fdTW4QtfUzxqz//A5ouFDuXaCPI6H/J8Fdd8N2kBOyLdB+G432r6a4v8K6uYz0eYpidT2iuQ5IE9DOF0Zz/ES1L/QjeQ99IQCeIaNUAYroF7mCpLzYCz2n8mz8MAfDvyJwD+bF8Q8Mv6FPkAl2N2/6Jp/KZTNPOgnv8Rqf1KeAfnDgD8Fyv9syB/yBQPfD/zNcM438P0cOO+Hptq/oc8B5ToA/rsS8j+K5F80nK7C97vgvK/hnNlwztp42d/4HCh/2l78UVtny35vQ95OJzLI2Ejygb8K+JB/cWUkMliK4BnxnCRIzhCBw6V0ufR5aGTDfq0iIYPnORiQxP7w19XA9kKF/Bse5B/w9+EmCH4qH4+M/rdmuLPPmAvs5FoNwTaAk1zXANsHQmG25it9QkrO3tNExcOUb1BObJ2v3fIydPzJpMNuhXHhWV50oJDUWPBJwoFBP7zsVq3FoLsdsqfNflb5D+VD8kKqhMarNLEDNIlPFJNTlv8EP8FP8BP8BD/BT/CjN/xAPzil+Q+W7WstJWW93O2mfedoqv+Xyr1L7z207M+72fH354iujDtkV/OrQM9FhwPnzh5yS+64OZfu/3zKRkb8u+1pHa8AfurJRpGcPajD5OXF+XNHLrSSr3iLOgqS4x6bp/VEwHho5wiye3zOuTO+3fXBsDnx5qu+km5gzP5FcqZNMuPzvJAOPzpAIZxR84GLGwXt9sq48P1lfYB/u2BzT6p50U5/gEw4B9NgTnbfItpTyzXFuwiMwefAHvmhSfxA+WmCaL8P+BfQ+TzymwO7Odhfg8H+ukHUtTK0vxRfyTO25NZ7m8KH+5zFC9J9YGueE2701xwytMtMHpMg94LRaho6I+C6D8H+e7Kp9p+mVI+B+97Di/ahkEzGH16Gc7rCo3QVRQfYf/qrcN08Leh7SnKm72iK01tXfVPg9n8DO7p7uM8h9EwB62A0JvjrKV31L4bx6iGo/41N4UM7mswLtoeB36lBPscnwTmDeME1CP54ANreal0NPA59c0UT+ROBfz/cu0cjfDuccxqcA4m7HfjfA/9h4C9tSv2j/Ol8zeYHRHvKg42cKkIddIE20gV+vwns/826FngU2u38pspfeIYa+edo3uM1dAA30AY6AL8D/HZNrTMq8CgvOj5oyBEkNFSikHDAa14zpBmELwzK/RqpOydUyJ/hl3xITxMBHlXlN8THIzXvkjPqnD+GSx1Q8VdLya22a4HKf4IQt8fS+Brjhx65F83tX+f8qa0LEQSH4y1oCBuhIfa0mh96gGAelz3q5d2yp80+4H8H/B4s+eRcvKY5NF4PeXt2SvjkHgl+gp/gJ/gJfoL/u+ejA6axdKrzjzMuFG/hTR0vW31TcttRGaz5VUe+k1R/6X1ySu52UKovBoXOA8r8kOT2F7zMgu87sVlWAxUPyylttoEue1ud86fO2AFjYLKVfNSZCX8n8G8Ndf6ctEzcmcOt4uOMI9DdnwUDeivwrzVzvpwE2pLaxTX/VcddWrDqedGR9hPwr2uMb3BIXdis7w2tm8KvmXGj+t4Hw3MjtLsrTZ0/dEMQ2+oUUU5aXr7rs7xY9G/Ie3Nd9c8Dm2ZdTfuPjp8CZXCTLTl7K+TjHzh7KQbHSxbwP4f7fA38kY3YqmHOCLjuGrD/fgH2U9iWouVD2bfRteBXguRaCEb3sOjqkHfCddMkZ9pm4D+Hs9ei5/s7gu32LRrwtc6fqA4RyuxCqLv1UI6v41gaY/5XQzuaXev8iU524UwpqIPl2IZiqX9ss9AGXwD+3FrnT5QPIMiDgb8E+J9iW45F/qLt6kjv1Eq0e+6Jni/2hGf/CMpwJZRlbjzkPy/Z+0bxAHnQdt6DNrQWyiAvWgcQvnXBSksya/ia4ovUs4jOFyhAfR387Bip16sxPh6BykP7GikFWbAl3S4lZ/8XOkHnaLxukfDruaGdzXNMGkJvXpTXQSP4o5X8uiOl49gke3reP3EQJPzBwF/Pih96dLryu+u63rRnR9cb9+7QFO8k1nxybRK5l2Si6DLjn+r8J/gJfoKf4Cf4CX4jyreU1Obs7FPFB4OtJRi+GyRnxgxbaruXWo9+bYGr1SA7K36gdE+2K7Pf16I99XHjUgtetPWwmh8sP5Brb9Z5rWhLfihsqUedgaap1Zbxy/ZDA2hVxzc1XvVA5S4r+KirQ72vA939DtThI7hE9Rfv+CpefDVQ3k9yNfsFDMi/RNlv60rGW7X/6/JY+WAwDxFk189gwF3epP7HCymOjJ7nR80PVp0JxutPvGifEJ3jJewBHFCHd/Gy4/vKA197ouCfI4iOX4A/lmvSUcO/F9rS99HYfzWzfkT7Jl6QRzWRj/bndDmp5bpg5ZEOUfAvhHHmR7TdmsbnBEFyXYdjqeor7hpF/8/hBdtG4vhqWglAG4L63wB9qn808seZ2b8V9IGb4sC/GNryZjVQMTAm+SvYsP+JsXdB+Wwoyx+hTY9sqvzXg751MTiiToe2hI7AMWagMF8GpGYmHV/laqdW+mGQmgYF+zr8jm8BIvCw8jgLBtfF4YD0Y0O+lEj4KCcOLJy2pNtN+x6BXN7X0ACHUwMlR+p/YBA4T3KmNzYlMmI+9+vSLlENVH4OVfQI0CjeTt4Jg/mbuur3QIN80Qo+SXZP3kUdwpUG3lHLD+A0wX9YyedqZ3qJ7ScsOkdKzn6EiOGWvOCcA/nPgvy/wIIfelFqp0vS03pOHQqK5QZ7eqcDrPnkntguirjadfIJfoKf4Cf4Cf7vkN/QEihQfk9p/sFQGNT1pj1zeV7K1VXf+hPrX7i2aOOMIlb8QPnBtmCwLQPFtWOI06Vb1vAnRubPHfm51fxg5dE8OaXNcsh/GxPHywZyH0v4SvWJ7lJyqyXAb92Ag+EwpytPwi9HreDLnhyMI5LZiJNjvqZrfyd1Ecf2VzIYdPUva+PLNHjgvTC8QYGmeF/fv2Dy0rjwA+WjRFvyp2aON0NfxPvhMi8PuX9NEYIBfb+veKcSCx/sqrGCzT2vIceb4RnKCZ9qpAarj++NgT8/qhk/jVl+vNTBltR6Ioxt7zTGhzHnMjD8Z0Xo+IvUCO8rOdN+hLY1QnSkfdcI/wpBcr3F0WKsxM7vJblbrFW8RedLzmabGnb+eCcD//0InQ56JA5CjFkj2lPXRGL/ovzJm/r9lXBRs8b8RKTty8RR0VD9t4E+tVL1l40V7SnfRCJ/9WCFSNq3WT1gjKsS0udTG3RUwlgm2pJWQN++RLR5lkcj/32FW4Kqr/QdaDfXGM4r4GpjHNvJ+Y4G+GnQphdB35og2JI+j1X/KN4862/N+lwvgTwcAn9Wk2fA81BWNDBe8imC5PwU2hb6bOY05ACSTOB1A403RHnBgaXOQ4oV0I44gy6GdKZJw0ShggM1BjHabeKQapBf90HIczwM6RVIZ0NCj/VFVIcUNGgQLEuUisMDG1gXGjE/9CBxbg6RfD8HaTS1H4j256ESThgroal8oowo8BwojGGA0/cBrm043/a0rgWLYEB6M958UgbIL4dBxCknZ59Gyz8MsKW86JgVLz5pBwpJJ/l1QjH3orkD3K0Gv8XVrNPWgzgTiqyLjJlPUeBN+aHeeHLvwtC4SIYYSE2q/zo+UYJM+Zz5uvQEP8FP8BP8BP8U8Em8G1M+yA1TPlzbZL7vxOYMe/Ou8+qcHyAnB2b0u/n+oo0z/mzGJ/IrLvn3FWxpbs/oshL47cIqxt2iCvjHTeRmXPiBkvxWcmruauBnmZTz12BMXUP0rNBniA+/4lA7Oanlsgb4aLy9BjUzT3K1qCTBQePGBwM1T3SmL2/A+YMbmzwDCYwYvtjmyakLUBoXPhjo3cFAXFJ/uVu9A2OJvgrpY0g7T95YctbpZH54lpj5YKCdDobqAnxha8Ivg4ROjPmkLkL7AxpgvSDt2vXB8JKY+Djzxeb+uAHnRymk2ZAw7hKuwDhBnAAisb+GQsJZQyOwOJXqEy/sXzB5QxT8EY3wsWw/gfQFyf8xrjboNua1C7F/cKZ/2GwPNVhV3Shfqb5AkFzvNuD8wPzPg/QlpE2ErxHnFs6wOQvSZZAos10wJIl8B7SPyWZxSXHmDfBnNcBHBxraDjjbbDOkI2Rsxp2UukE6h5R/O4oTpKXkTF+jBirQwfi9SfmfKciudxrgo42Jz7cK0s+kLPHc5oQ/ivBbm9q/3qLBkrPZ7obknx6oKjX5fj3J/3LS/+qceVj/uDwJJ3dMg9SSUv4e0e75QvUVDxYd6dsak7/oQFWqC16Cce7ukO/XQML2sZr4D+pi2zgJ/0JIUyFlU/hJUO6fqYHyM0WbZ0M08j9/zlkPdLjsm9UwNnUm9b6SOF9Cr0P+BZCupZY/x9ugb82FMWakYEv6Nhb9I6P/rUcIg3Zg/7uEw/g/tX3ByJcFyfEOtLFjuKwydFA6eQYZxASKp+1EA8pPXcfEWT0vEkdMP9JJaUdzMoAbB9mm8LEjfARpIimID008cc1Ed4uPg5VHaQN8U/ihAvI8Ugb51CeQambidLOIT5QB/lzSUMPHIUF6VdeCfSzkozD2CnYP1dMOSuVM4Pe1ml93jatlv/trnT+1nYAX7W8CvzcrfujnLc94sHX2iOd6mqzJjhufnEu7RiCMBD/BT/AT/N81nxLzxpSPY3qEsXMa5dPGf4wT0eW6be92u3n/vq435n/b7pJPTzfy45V/Gr9g/fOCvVne+8aZL2Bcd2HGT+/4Ec35g7qMaE/91Eo+xtyRPTmfmThfjhG9Dg28vVbwMeaO7M5cYMIvI4r9AEg4O6Ey3vyaXbbsnvloqJro97dA6k0M0OJ488HYc4Nh9LGJ8wf7AMbhwFlhT4U6f+I1/mCcEDC+PzFx/gQJtxWk24gharx3CTFMj5jpfw3ylepW0Nc+NHG+oGPtCUi5pB4WQzoeYgCrxCCeRZwAzRVvcfrOWac9GQU/q/bFtCn/ScL/I3ECHSDOnzrH0H+Jc/A04ojZElK2yw4smvpNo/kXHWYzX7AcH4KEY9MNkBZwtbO//KRucCYcri55HBLGy8GlY2HBl3Vd9Zm1P9xlDPL/ngkfZ3rcCSmH1P8ikn+F1AHWBRrVD5A2OoU8X5gTghfEh2h8/AxssydMZl6hs+FqSG0JYwX5rG73vaPks3uJ8+lG0mfD7V+75zOTmEQn5d+h5bctgqL6b8h3O4lzZyCx8X/h6s/kKidt/17SRv5MxqwwJ5BgS1mAfT0S+Q/t90V/8c5xnK5NJ05FnGDyBjpZufqBjbF9oFPlb8T5cZsJ3w19fL5JTCRT+a94S46J9hRsG/cT30IB5QUQOsceIeU/3YTv5GXHnGj5Ecrf7WSM6kLqv4TuBHLOgf7YItTjVHfgQxk7fxU9I40e6J0dQ4TWDC58Rk4vUlh3W8BHAT2ZDBKzjGxekPtAJ3iSVBJnUf5XkYFwPvHG12sEHC++Db8MNjTiePJ3kc46m3gFQ/l2aGNvEWVCtYiPHu95ZCC+3PCVjedF7Ex9DG8C4sqHDqPXdAJdSzPmH/gfsOLDwK4KkiM576ofnq0LEu7pOHY+aaMRl38MW6ee5HP1p2giIxnuV04EjyX5r+OTPIbxidCwqv8l+Al+gp/gR8V3pHdyGpZu4KwTJnzRkfpXQXZPITpKrrNl33+n5I3rkj3qlWIW/LQeU2/hRcfocJtBXkJkmaX89J5XTQc+bYcTnDE+MUoHYNR8ObXtA7xoG0C5Dxo7FxCDz7r6d2Y8DmXd00SxR+Nrn5V8yZn+dM0uSuEHGn8XEp3SMr5gc78EfFqcFjSkcVb/T1bywfh+3WTmE26njasaotpNKVT/i4jPSzhLnRYs9wDh/xgFvgjqs252VqT8t3EnKRN7alyoQyeCA50BOAlgeKBkt7h7zjlbIuSnmbQ/zP+2KOp9IXGI/Puk/aFrBZX7lv/LnC/CuXwqzflM+JHuJoYzkuZytRMg3iVt12B/mco/mmNkJRn/iiLko/yaCWkJVztb5wzDeN5dcqQ9ThxaVPmLy57y546akHvh+/3klFwfeYZAhHw872VSB/NJOwjhi3mC7Ho8Uvvbnt7piyj7PToFX+JqZ6l9QRyCoe2srSA7MAzKTZHwY5D/WP4vECfh58QhE8pvEw0f9Z8obb+6+l9KnqGbQaBnQh28ROzPk94midL4vE1QvuoOXGo0iaOv+/wL9+tUJSv4c0jnC2u4oGjdoniLQyObW8EvJQPnf8KVKnGgpnjHW8zHjjuBdEQjv6+u+q60mK8Tr/USiie6u64Fr7OYX8f6wIR/PQs+Olo6TFo2vN4OcaL9UuBfxYpPUZ7dZLmB9eVPXzrhNjifE/wEP8FP8E8J31+4rUWX67fPbz95+Z6uN+avyR03B5VWbxOcP43yQ8ffin3LkkXZfaNBRqVmj3olnQUfl36BUfCIifHxkNX8QPGuLNGRSuPgW+jxFGMpvvyKQ+1EW9KdlGvR6XJmDM6fqPg1W53b3H+mXIuzOobH4PyJkl/c2STgKnJHxOD8iYqv+st6465JlGtxycuwGJw/UfExQGvtTlem/I2W8muCDttGmzifhkbp/Ila/8OlZyb8XYS/JQY02nwrbGkdv2ps/AX+ecA/l3KPLYS/LQY+Mq+ANChYfuDKo6vuHnZ4xfQ9JvyzgH8e5R7rSf3vibHe/8DVvoSvM4kUf9GON4zlT353K5XHjKFB0Il0fhTOH6PjdCRHWYmDY40WqBzakPwNlO2vkFNyPyP2WyAGPjoOz4K0jmJ/34rLTRuT/02Uv3tJ3YWthIGx5lpDUHAr+LvI2L2bwr8uEn4T9R8cu8+hjd286JioBspP40I6gXG3B5WjTSGL7fiM0zXcxnKG4XP0duG0zust5GPjvZ2rjRFUjy3IDpwudpXF+cd1r+i9xfWazerrdxJOl/vYYj7eZxoRoPXXJfIy8mdZzMeB41Ku9i1abn1PqHgn8VRqFre/J4kjsLeBfwf8+BcDPid7csKmVQP/IVL+qtV8ci9bmzHv9HVlDbgR4C61unAmg/ZXj8/9Or22bneM0gQ/wU/wf598ULBKiQJM5ccw67HeETK7scH8yyltHgelbFStXJbbu7IHzcy9+MNcVuXvatn/TwBuYbjmCEePkxh3vuxpfSvl7TsaHRhPw2c1X0zKBB2NN06Lx2VOk4gOZSlfcqTdS1n64yMGXJHVfEF2PUhZ+hEgumOB9XzHXyn8INHdDlnOlxyPceFLb5B/CXGCWMoH45/mfMSZBOM46lKeOPMF+X4T22Eco/w/ZuLAGEvGIav591KuwdlbF8ah/f931/tD0ZHTwrz8pdsp1x0n5d8UIxzl2BW6rsxXqgt7eY+u/+bQV7fsMJO/uz4Y9n77CYuOyJ42Z4u25PXwYG9yjW9a0NBRNwkA4zV1DTX+OEHECRhrLZb/FaQPI79VqMMD+jyMOTUTBKzkYxu6gDhQM+rxZQe2uT9azC8gDjx0IIfKN1GQ7NjmbrCYf5z0Ycy/s575KchY/n+QCNhJ6fw6F6+DF/6la+olvCAat9W7ovM1P9+1481eVvJfJY1wRH0vnHOS6i+9jfs1aJ1VfBxAHyTPEVIk8mm6GuhFPJRW8nEKOTq73q3PFzvrWnAQV/uWzUo+TmPD6X6fGNpEe2gTZ3G1a2et5KMgx7drqyl89JAvY9D+0RH5z3qdnBdyCP8rq/k4Hbn6yDqXq9XAj3Adck37T3GfA3z0kH/fEL+pRhg5dBKcMdTIcIYIV2vLv/ZeCX6Cn+BHyI9x2Y+ZI4bKh89r+B0mLRsvp7S5mtO1ssr9K58FJfn7ePLN8l/H73rTnnp6Cc9LrdythqDCeIwJ/8b8qyjX3NVE5T8ifvMB0/mM0/50HeWaR4gCaSk/9+IPRXfWoKmUa3CHqX1W8ztdtcEluTIup1zzHNe0mR8R8TtfuyUVjL1LKde8yDVh5kek/C7Xbk0XbO5JlGtwmcAGy/nXbWshyG7a7ItXiOFoKb/rDbs786JtKOWaJ1mUP/C7A3+wCX9TvPQ/mv5Vy9/ViRftp1Muw/AcO6zn72zDi47hlMumx8n51iAff+ly/Y4kSlC62+I0/usgTz7d9c7AJZHI3z0fjcFZlx9HGXOtoQMdiTi+rq/3qaYKIbGIrJT/GJ/oZg4ngoTa37Lr0mDl0VuIk8pKPjqw8WX/Owb7/1KluuBWUj5W6l/4EuevnGESCuT/csVbjJMgKi3mYx++n9ifIfl3jFUDFem4BMxB8T7Fq/H92gkEETuUZvjcqauBixjw76FY5ZBvfhyj/L/B/bpl56+FoivjGfFxGVT4NEZdY8XHzh8euE9XJjLiYwC6NRT+pYz4OIV1aThfncSIz7laDTq7zvlDDhHyP5UVnwg0Nef8f3fNm7ruhvYTFo2Q3S2drPjknqExl3jCTvAT/AQ/hB9H5bNRft609aPszTq/AQrZGWAIXuDpMOYj4MvM+JevOQ3jAhjO3RNH50fD/CvWDuAFOY+itM5jwU/tOvlMdHgZzi0mOovlfHtqh1GU2U+VxAFhOZ8X5YsoW35XEQeQ9f1P1y+mzD7Cc59mwdc51AHDthxnxudql+nIFKP1MSb515UplHOLjQaThfyJlHOPsOOrfzAxWt+0Qv8z8jXFN5QLDwqNm+m8x4KPKVi69z2Dwb0k3uNvQ3wG8hcdqf8KMTwqq47+dyZD/oJw+4tPFmTnRYz4WL+GZaQYkFsaw0j/wrI2vEnn3TxfMymFBR+dT4cNfBns/3E4A8hOGSisOLbpWnA1KDtn13eCaPj3cov5+CYDPaD1gvxBA8DB5wsG+cfpvLgW9I56fF4cxKj8NeIEeqB+GxCGMeLj4DqLq32rEcKXBjNsfzigD6ufffkshnws//pvunhxCEN+2FReyP8IhnwOjL2RsjuzZptLOSmL63DZ14O3/7vr/TR+nGYe1dcqZrTBe4c6wewmipJVR4Kf4P9P8V1ZA+XsUS/fIto9/VV/+Q9HVt7+PEs+KIGjuPozI3GpNMrlL5nw7ckjKOfN4eI7A8ucb0ui8XFprsKG7x5JOe9TzjonZD0+LzlHUc7D4JnlTPiijZZ/1AmLGPHPNcl/MRO+INP4+MKukA1fGkY5D4PHljDK/1km/b+KEZ+Wf9wNy8eEz4tnUM57k9X4EyjO3+PM6q8bjOAXuPDJApbJ3/x55y3NvWjuJfb0zqN4XtgrOtJeZTX+M5T/NwXL9n8B9nZexd6la45/9+Qxxvy3jPaXIDkxDu0SRvbnDOKICTG/bDjz7CsGfOxLr3G1u3SF8O0Yo2cVI/8Dbjx1f32+PBwdQJLhZL9V2p+uBecbHUDwGL0Z8T8LcwDV7vrAKv/LwhxAtbs+sOKvNDqAQPh2Zcj/JtwBIXRhyP+aC3+ADq6Wp7mqj/3Agr8mHC928nQY4ynPX6Qw4H9LyX9eWrcpaSVb5/hZ9H/Z3QKn9Z5c6y/Irmuh/J9kVP4195bdLVNaDLm3bfXhb0+UbJtHC25nKd+gAEgJfoJvPMcK5yceW2e0CePnjHnrcdHmub62P7pHt7nwXVz6dCOr/IMBkk057ygzvmjvTTlvBTO+5Ogfiaywii+INhp/FUN+n1Na/oLcj3LeV+z4Eq39LWbHt9F2HlvCsPxPo5y3iGH59zSxFViNfz0o533ETP7Qdz5jlv+9n16yK+/yNffKnpy7OZ736JryOrSJt1jL3/0LJuMEAUxFIH/9rPks9I9dHwzDcXXTKeJ/ThwhIUzdwdD+wzaNs6D4EPt/IEP+4jAHkCCz5C8McwDxUneaA0jhrDu+p7iF2jDih7Fh8G3DMP+bKQZ4luRMsyneEhZ8SiR/PjW53eiUir1LvQz4Wyl8e3LuOZ6K/St9DPi09cxCUtuRWdXHfjjKgI/rmXFqsyuU78oa2Ko8f9EBBnx8o4pe/3oBqZ2ZfXNKts7Zzab/8x5j/Xs6jsmB8j/Igp83bX2m5ExfBgNvp5RO45WMAbc/suvdwW8wHP+M95YiOCfB/43zs0e+0MGZ0bOn98SPmw6vvPM4S74gu84zKCWXW+gACuPzgtiKct52hvw2lPN2M+PzUjsTWcGm/fFiu8hktUV8gcrfzK78qfxt7Nqf1J5y3iaG7b8D5bwNLPio+8KAQ+v//2XB97Q/H/QRnrb1+EYWfGeL3k7K1u9BlvUfrDo+x5bcOsQJrK+GMmE2/hLHBM54el90pAqqr/Rot5sPqKdS/odsHvC75FvELuZ07RVo73+p4/iLd7/B0P4+wdUurc4J0XX6M7S/UaZhzKeUX60/IYth/sPjmQlCdl0Q6NBDs6r1cbp+mPKphxH/EMUBk8Yw/yeoDoics5JLd35awYBPndJrS22L69+9DPjYy3Bgr7fbgzNrYLOK/SsPM+ArYR0QDtmVgX8fZdL+a8vAVW8EdjXDNniAEb/A6AAS7J4UZv2fsqOC5MzA/B9kwZfdmegB71SHlpNaPdis381fFG2cEbrThGbhDAxj3iixBy0t/wQ/Aj7L+u84ZeU4W1pHnHIu2tLzFE/n8eiAmccs/7ruNZRCgG35CzQDzMuMz4vNKOeVs+PzKZHKaov4nlPJ5zkhlXJeEbv8C54IdbW4892thmAcStoyjKMs+J4OY5JMjMBjLPgpXaekmYzBTPLvzh6SbqKjFLPgOzP7uk3yrrBq/7vfO312h0lflcvJrc9Vg5W7ecH2pORMPyXyV/WVagn947fL3/pa29vbT1i0QXRmdPCe2LTm0JIbtjH1P9TO8Mr51R2hHFC8Jcblh5qFZY+KZc9fhZ+YyjD/ASLXM0L4yRLH8Kg68HVhcocLw9xCjPCU7UR1lWH2qYN69fGN1Yz41MCagZI9rPg2LnyrT4xGrzOsA0cYPljtZ8h3hTdBnWX+KQoHzzPkO8M+EW02hvxexj7hTO+MU6ALWMA7/XFTEgw59wi2pB6g7Kzbv2Dia4Gy/WHjgoUOCC5xmAwM6Z2kQPkBVVN8TLlySu4dIeMizgjB4KvzGD6CUeFIYloAPC+bjFNVrJ6A8pmHa9r2v03ly8yKnxNoDgg7w/qn6aBMZKLoSBNMvmKiEwh2j2jyFRO9VLS5xWh01bjnX3Ka2R9BFvxA1THvqap7PIo3zyrLPOOB3bwgdwz5eBVr2Zf/4bm45K5u2V2lVfpHQk9JHGSXs5Wngq0p3r/wvNiRF229dF054T22cTrjRzC8XOPdjoweNl/hliAjPupUGSG2p18iwjZUCRGsEkC2tE60t13Gt21W8WnGdwXD/GdR9JwKMACDhGk1vzlN0FbsW1bJiN+C2iIPrS1kVP/NaYotGH2ljPjJXP1tIGs1reqCYkZ8dLS0DtM0vYVFjPiobLY/hXw8csPK31dcxoovOdPegqGmZstfIcl5TrtLv8jY8WavB1mNv4Z+Hmpo/U/xrZoCDoplGF9OyhLbT1zyuOhIvRzkgU/X1Xu52oCBbPLP80YHaDvSVwNM+LpaYvA32IisOsqIX0Hxd+Bbuu1s+DrN0YTLUg4y4tOC3eIszV0s+DqnlfHhs7AyWfFryp/nkyj532s1X/WVqJyulZCZ4EZd5bDV/Iq9S6u4sLgYNQcq6UVW8ysPrqmk6L944JvpMqv53mMbzBiY/xOWl3/+l2WZg+81zkpPs9AAC2v/FfuWX5Oce87zvCDnasHqb4OVR6bb0zsx49PkL8jJ37X+8Xvn/1brf/vrnXEjnPOb9b42DexetL0DbMtfP1YPpWvlvsItfkb2Nx7u+sJfLRW4yNYFxqf2bUmU9cb8Pkb8vHD/j7qXYf67hfE1ZQ9Dfv9wvnpK+fAAR6uOfFfJiE8J9qiXFP30xnFGfEqwQ726ePOs/Qz5RmNTLd+9iFX/w4DjxhlAWsXe5azyn8sZlr9h24f8H2TEB6OCHx/6gWjzjGU5/na+5ufzu1y79dXOV//0WNbwJ9oQNjM+R1/vfEr5uRfPHys60q6q2RaTF5JBEX+ZtFUmfF3x/4dy3mBmfE2lOTqGMuPr2sHIxkqr+ArtdfcQdu1foxm6A5jxNe1IZLLSqvKntr++7Pg6bblbb4btj1b+3Vnwg5VH/aCD0RxdPVjwKw+sqkQdkHJeRxb8QNk+H5S/If+6Vcu/qPV/aMkNW7fNzBu79bW2vba/0e3G/Lkjq1jyf+/yP8H//fHB5ishM++Z8mG8fRjGuzp5owSrjj/EkI+2T4bB/j4ikQcINQxxloQl0yAFyUnZclD/xfCBVfzTw/0PwZ8Z5j9su1NdDWxgyD87PP9M+edSyp8lP3ztoaZsZMi/iML/OVBes+OAiwH//HC+uq3q8LdVjPjjKPydlQe+rmTEv4TGrz72QzXD/Nd7AwLGzyGW/U+0p+JODDWvIFK7TzkvULZ3IAjDKiPfql0wts5oY6coAJzsbulsN2Hhn+D5YIzQ0Sl/F2dNIN4wvuhIMc5Kwzq6mLMmEGwYX1P8Pwqy+zLD51M5yq6JVvB11f8zVMAkSl/5iAlf8W3iJNcfDJ+jo/R9NvkHHUAKG5tHc7VbEVtf/2rgF1F0GMfmMZCeY5J/0IF40WbUjS6A9BIbvrKNshMU1scMNvzABl5wGl8OngVpFgs+p6k/c6JkXPOCW9N/wqj+t/Ki3TgzeARnzU5cNP5m4GdR+N+y4CvVhY+C/PkXMbxU+Pt+ydXcKhuQKv9Y2V8JfoL//4FPdiv9zeV/17uDd3ran396eq+re3qP/7jv+HdP7mHIR71fC7VBdF0rkggs1ADCt/SWBEEUZOellOdaZvjACj5mfiLFAbOSUf6xnC+jOECWMeJjo5pC4X/NiO+klr+mLGXEd1PLXw0sZ8THKe5XnML6x9hH14R9qisrGPFxgLuBwl/IiI9rTG6i8Fcx4uOge2s4X1vNcPx9mAvdApOXWmX0vxUdQEsY8ft1vubn67Wgt7Bww0vvl/zyQXmdoGv7hwV3Sa4Wd5Hz8O07voHuwsV/KqxxBppfC1R9Kdo8dxk+x7byPCSf5Xxv0UouPOjmZEh3Qiq1nO+vWCY60p8wfI4OGSuWgYXx1WD1CuA/RnGA4DKwg5bnP1i9WrSnPEBxAOGM3a1W83XFt4qzee40fI4va3AWxG7L+agDye4bKQY4OiUOMOB/zUnOKyn5x2Vox63mwxj8H9LfjO0fx+tKy/OvKV/zot34cmoCJIwN5mXEN76cQ10Rl8IGGPBXUPjogH7MAhkUxt/1zsDZ2SOe3+Fq2f+06qPr1x9eecduC2PghLe/2qOe/AUDuPxU8jnrguAn+An+75pfvmdxFaTvTwH/qBqomCfakoms032qr/QViSi5oeuARfIQcRU+MKg5u928v4/hY1WQ7AtJAVjJv4ALm1aqV+matoBR/i/jQqKPE+OvDIwhVvxbuLDlL7qP0/X5jPg3c8bpZ5yOsY9Y8THYl9HKUjhe+IAR/3ZIYbvN8Lz4HiP+vRwtBhUvvMuI/ydiUBj5sxm2v/CF9bw0l8avHasOxJM/laMtK+ClTxjxcUZF2LIWQU7aFcrPPP3+rJROF0/WVZ+fFx2vx9EAHAZpuWhPtUHiWg59ZLz3xM/n+Qo21zhYREfqMMP5OFZfDenf8ZQ/XP1YD5hn3653B63uesPubbxoC132lUP67JNW83fPHfFj1xvzd/CC3DnkO3RYPwrpz1bzS3d+siGj/617gR+6HTY6bHF6cjy3g6fyy7Z/tC7jtD8d4nmptYGPBuBVVvMD5ftWy+7MEzAWhcaow754P0d5aRBvvh6sXg66QCnwUw38xymOibjzNTWwSOT0akCGKqGoF6JT7Dqr+SADP4dfA8APfQuKDvu7iRPEUn6tDqI/V7ME9NcjifT/Ry3PvyCiDvQMV392KOpK10N6kQF/Dvx8wsBvScbff1le/rU62ONc/UBgeRYZf7T65w6vmJ4PP/ZYKH8b5LOwvxL8BD/Bj44f52DkpzT/OKYJkuPOduM/+0pwpLXzHvth+aGvbllTFwTaa/BCeUIMg3jAMXMeTfFtFCRnqLK/ZsebvcpI5q3iyzRBCs/yieRMr9t+3cr8o+H/93C+d5aclOVlwM8hylx9frB6tmhPKWXAR2PuYVr5C7L7GAM+vsm9z/ihrvoXQ1s8yIDfx4S/nBftuxjwBxAHkMH/GFwPRt9GRvxHw/nqRuD/aMaHMcMHSlg8+L1ohjwufwPld63Z+BdHPiqzL1D4vwD/Wwb5R8P6NWr5i7Ytdfxmva/NhrQYFPK6+e84YwuXZuxvIh/v9x4XMs0VnS2tR77Yy5bWscbBpAYqNhAnUejxLCR8O9/UWRiCrivj8qau61a5b/nKo9/cV+fU8taVr+ItfhNkwbOG69ABgjPk1sVL/hk+PslXfcVviY70v1OclgvIM1jJ11VfyduiI83YR9EA/RLS53Fogw3zA+XvijbP3yhOUzSOF1rMV6D9vS/akm83fI/OFzSOv7CY79eCVe+BLPyT4XucMTubQflXa0r1PEFyGZ1t6ADAZXirLeYXgS60EGTxeMP3fyb532Ax/xjI4i9BFhuXAd4DCV8Q7LSYfwD4OAtnhOF71Jk+5eLjhG+Ivx/4K4E/0vD94yT/pRbzD0P9fxFa/9Afvt7+7658nOSfKT9Ev6HKXy5+u9FFzY+n/ZXgJ/gJ/u+XH+J/0fPnnbeUfFyN42ud17/SAEMvVGocHVB4L7F06+w7YLBfw9W8cdJRsb2KAR/jDhmDTwe1YHWowmsV306UKOPsmyq1uuBZBnxsVB+F30uvBv5DDPi46xvOcjDu8qHoivdhBvwWxIgybv+O2z0/wIDfmuTfGHxZ19Xggwz4bQjfHu6ACrDgtyV8Vzjfdw8DfntiQIXztcBjIUyr+DnEgEyh8J+g5T+pzdnOTn/c9FjXG/PR8YBvYJs10fmykKPswAf8p0L56T2mnRvi/MEjg5RdiybwPST/Ybuvie7MgrrfAyX5j1OCoeK1i2jXRnFgv1/A89KnclLWE2k9rliRe9Hc/qSsTy7v8B75diaFbyPP3i1e8i+0+EP5vsKtM6FCjMGA8fyPuVoHsqX8YPmh12p2QwpXWtAB0tdqvlJ++EXcEIfCR9nZz2o+yMLnanUSav4HWZ5/X8nz8JGfwp/FxScgb4N8Leh7mgsPRikQB0AHq/m6FnyKouxKRHfJtpyvBp+h8F3EAZnCgP8IhY/XvBZP/TtKPsqdSSz4wbIDN6uB8tmgk2xR/aXvH1/70F1W2B9mfFb2T4Kf4Cf4CX60fJyJ1JRkxsfv6hxAKPyN0eed8RB+APGQe3HH1j5yePvrnSdvnZGbBfoNvnHYbzW/+tgPlRTjc7bkbBa6vt4qPr5FOc/4oeov/7uc0vaQxXw04JbSFFg1UPkMAz46vdDJ19P4hRaofFF0pG+3mI/G/xqOsqOEplS/LtpTfrKYjzNPcAZDO0r7myPYkr6zmI+zN9ZylK3fddW/QJDdSyzmDzHnB74E/vLG+DB2NIWPgU2/pTkQwOBYLUjOOQ3xHRk9PMGqYxg36U8xGiF1+e9M4a8F/lwaP/vclx+TnOnX8YKMM6duIH0olinxPUn7603hfwP8+XV/d7v5gMJJjhMmbZg2OyeSAw3HVbTxB2NfibbkkzNrnJl9ipTqortNHIjrOUoA+QjHn6+4esHfeZezea9pWNY1eSZHcocLK1VvyQMmDjQcQ0bHwMfthF/QNXVD52u3vNKs1x9DFYp6fHfroWWKt+ivlHtg+1/NUQLYxyJ/zfiOFj0LVX/ZE5TL0QjGOHkXWMm3Z3Q9ATLxWZP8L4+x/EMdiWH8UIeHLbX9YZCJtKDLuBQPZ0GdH29+aP5tya33aoGqV03aEOZ/qJV8GG92gEycadKHvuaatitWo3zR5vkBZOK7lGvbkfbXw0o+yOL/AP9DkzH0Cy58++J489cAfy7l2vMp11rBXwv8D4wXBquOa3Ewfhrv/806H9/xRo+bts3sOHrHm73uKdk2ryIO8j/i/m+l/ZHgJ/gJfoL/v8oPFWw46AYpChDGTuFj8EbxkFCBMc7+QEZFiHcqKn4UimcNf98n44+o/tKTyoWuK+j4eIhySdz5YOiMoBj/q3xFW5+ymI8Fu5GmOILx/b2vcMvjFvLx3HHEcKRsPR/cqHoL77OQj236GpL/ThT+VtVfcaeFfJxtg8bc9xwl7g20v72a4r/FQn4yVxtTAB1MOVx4ARzRNeW6SPnQjtPJFMJID5wx8gpxfmRT+AVQBtdGw9eCVS2IERDJFonocHqJGM6ZFH4xdIJpDfFFR6rQdvzHs2V3yzfIvdBZeR9HmUlEObJI/r+h1T/yofwxtohO4wuy60zD52h8obPyWeKQaOxAx+8/IP1AdxzpJbT8q1Un5sHYtMKkPNEIe5GjxZEKP9DRgTMKNnPU2SN6GfDD6n/XOwNmQz3PM3HCLIb0NhfZbAQUdti/tlAdV4IgkbKud+yc1f9tMII/o9wvnfDfpPan8APftFxJ8n8bL4j9wMC9rPmgu18MlX8m/MUmAhyN0HeIQyyS8XcEtLOHgmX7LzOTv8aLijfPel5X/WtM6hNnkb0bYf3Xk7+R8kEmPgmyaZ2JEwSdMDMibP8n+eTaiPiat+hxkA2bTOof8/8cFxbHrtF6iJivBqseAP52yn0yiRPmMcq94sbXgr6/wrhMW+6JbR4d6RhHT7aMrwamE93MeKAMx3ZxdZQ6UFR8XVVuNeEP0zV1SAyKd7T5vwX4BwyyomjXOwPdUcrfGOvfi/zdIXriliMrpq+IQf7HxI+j/hFXfqz6f4Kf4Cf4Cf7/Oj/UoEKDpIQoOaGOIQcx6jAydaSBiZxEcRWNcoYwaGvb4sYnAS9P8ne82euvrUe9/Lac3CZDDZR+ldTm7HIWfF3x7+Ntct8Q4/9AoHT/ZHerIYqVfFDk7+FFew7N+QBGwXgL+VjeaERR31hj/oOVx/5gS2nrt4CPbysvI86fbib8o8AfY/PkVMeZLxBD/RLCb0WvGK1YC1ReJNpTS6Pl484QDQQmRCMNZ1qMJWWQZtIyytUg8G2eghj5WK64JAXjsuA22aWkr2NbQyX5PFIGdhO+VwtWXyzYko5Gys+7/Jupgux6mtwTFWScubMKfQZot5JBMpOU/xhSBiaGiu7XFO9kQXbvb4jfevS/ThMkZ+jWyDiIotP0LtK+VxAHQxlp85nE2YEzVUZHwA/b3QjX40IZl+hqcCcvSa0o4ykGRMW4MLhzHM7e+gXSCTKgY9vH2TqjSB2YvDXWg8C/UpBc+4zfOFr0DFYe+Hq8O3vIYl50GLeFRjmBMTlwd6ylJG0ifIHkvwthn9uAo0wF/hTgH6DlH/jXubPPyONFW19K/7qKq91JbylxCKCDpYAIszTSLtHhM5Eznb6r+zlNe4YWW4LwpwF/NfD7UIQpGqDTiDNoEXGwocHoJ0K6E2l742mOR6jzsyRnGqd4S6jyD/ne45uudDTvvoYX5K6Uh8eYOFNI3WMbxJlR2I4qSf7xmuFcbeya7hwvcHJKLtfpjz++vPPtvk83Jn+bD5iuBYp3TZLT2q3jeSmHkn90auHuRJ+QMkBnEfbjABkjOpPy76D6ir8hToOI5T/KpED5wclycta3wM+i1P9NpAwwLgrOXsPZbYUh3+MzVNPkfyR8GWSS4i2aKDnSvoOya0bhTydtAGdqfEScEpWx6D+09ie7M6sVb/HFkiP1v8D3UPofBqW+kTgisQzwBYsSLz7GQ1T9ZReLdg/UHZ9s+NpFHGB/4WrjCb7bFP2PxgeZVKIGyi8RbcnId1L4b5L8NsaOiQ8yqUgNVIwXbUnLgV+v/KuPfO/c//mUaAIDx5Z/f9k4yP9SqP9M0BXKfYXb7gxWHbNFIP+bzneklVcd+W6A7GwxRVcDwcMr71jmK9wSjFD/iFr/pwRYbVT/+P9ifyT4CX6Cn+D/f+DzGRlhIR7QeGnG0ae9quQh/EQYayEKkkSMNCcFXAcvoni5mPJBiAUNzhrL+LirTnrPaW/wor0Pvl3T/OWTREf6Oqv5Xa7d+jooNOPq+x6Cu5TqwgvkpKzdVvE7Xvnthbbk1vNNnC/7laqCUcDfFW9+pz9ubCc5m30Pzdn0DTE6f1RvybmSq/mWePG73rC7CxiLb3G1M53EBp1yyPeVjwVFe0NT+MltR6qtz5v5LBiJfyDGl5OLZJq4rpWCgj1OtKeuiYXf8Yr/TLV5cp6M0RuND1AJCvbFoOiuiJSf1nVictbZz/xs2CEmxkOv1gJVk6BfLGyMn3vR3JHu7NO/5OJ66D41UHkpKPiLaPy6rWeDlUc6SM6Mz6Bd9Ygvn0PnzxWC5Jxn5IduewtGQIYrs++XvOgYYAF/mmHpXdjhPbqhhaNFz+WQ/55xLn/g+8Lybzz8xTvb2FLbLYb+1S2udBj/tr3WPg/lj7HMQw+l4nB7MSlzJc9LuXEi+3d/MLxToGx/IFT+mvGDVce7SK5mK4DfKkIA3jesfwbKD/5t9/tnvGMm/03z7y3sJTnSlxl25TI7qgg/raaIteB/Cje8ckPB+udLI9E/aM+g+ooHwBi5BPjpjRUscUDtAoP5xW0zOy6IVP9paJtp1V86FMbIRRQnkPE4AW3qFmhTH0erfzXMLztTtHs+NzpB6p0TqLh8xxvdP4xV/2uQHyg/B8bILwy7kpEXW75V22Z2uqip+mc05a8Fq1bufLvvVAygGS/9tyF+6bYPkyV35sCy7R8dLNv9RaUV+ndDfBibftP6f4Kf4Cf4CX6CX3vQllQEiWKTxoW/ycYbJ3HRTUWuu2cJZ/7Gihk/gq3d4sY//u3jRyGN8XQYI5XnLzoSuu7ZSr6/JP8jZ2bvsXXGOiio/w2U5I/FWAtW8nlNoRotoLitCZTun4Brva3h89MbdP6o/jVK5bEr5JTcA3Hl8zwq/Y0uS4Hy36BUHh0fD37WWU/fDsbptKhMQC24TcO3m/XjLkXFtyVn3xWr80fX1F1asOIPYFhtjobvaNEnPR7OH5zargW9l4Fhsb6xc4mBvqzL9dsXC5LrfC4eh64d0YLVk4C/trFT5aRW+RX5C4e4c856VbAlTY0T/4SmeCcIsvubxk51txpSCPxz3G3OfgvOnxAnfjHwLzfEnaK/usjqf6LqyHfDnS16z45j+ZcA/7JI+Pb0Tgd8JzafaW+W9yEvOs6JV/nrin+a8eUD7ZCSs/cEy/YNlZJafcyLtoHxoGPEb9KnGpU/sjtze6Di0FD4+SmMM5HEfrHR23HLq7jaZWtRyX/JmfGz4i0eJtqTFwC/S2PNlaTa0ViQhzbrfd2jBeuf/3Os+geMketVX8lwAfm81NDYjmMhypzmWE+tz5s5+tCSG7Y3Vf+BMXItOmEEmxv5DSkrLXhe/KBZv5t3FG2cURQv/Uu0p6xWA+UjBNn1sRmf5/hLudpZmHHX/0SbZyXwzwT+p8CvFz9OUwMFVuufWP6Kt7CfrimXav7y0sPL/7KEOH+Y6L+pXSdheITVVurfjejAv2n9P8FP8BP8BD/B/9VzRDsU8hDG6NTRK5+19yiMMPO/SX55/qKDETp/4sLf+/HYld5jGyeDIjlLDVQ8AmlEhM6fJvFLt3+8Ateth2S/HJTp2ws3vnZWhM6fWPm8meGp+kvvrdy37OwInS8R89O6X+4Bg6MR549eCfx7Kvd9NShefDBio9gVSPdpgcq/ByuP9YvQ+UPlC5KD56KL/1DHD2rBqpdAoe4TofOnHv/o6r/9oqu+b5vQ/5D/glJd1DsS50+IE0ip2r9ybLDy6BW6FtzTBL6iKdVvqMGqnhhoM9KLMCjx9je6XVXD15XDTfJ9qb7ZmuLtGYnzpx7/310nKdUnpuHMtSZ5H9TAF5rq7x2J8yXECVVa9OPMC1Vf8W2U3ami5S/VtUCfaPgYFBnGrFHQd/9K2Z0qWv5iTfX1BX7E22ljgP7q4xvOgHH7IcruUFEdGPA/UH7weDTyB4MSK9WFQ7DvRCk3Q1teIFb5KznTd6q+0tOg77wWLZ+X7D2aKv9FR9ovMG72h77zToTyR3K26DMsXvqHaE/ZpAWr+2DfbZjP25JyhreLt/6DQZm1QFVv4L9H48N4st9K/Yvwe0L947IvrbY5Kccq8hc/z0L/k5wZ+bveGfiP/Lkj5/gKtwTirX9GsGtLQv9O8BP8BD/BT/At5UuNXIzrzqqJx8nJRT4DAK/1ErjShIf/zfAjmHkUV/7eTy7GHXA+idLx1CR+wYYXC6SkzLGeDhdcwYt2TVP8L6My33zAdEv5lfuWf5DaZcKVddO2MZgjKJBvBssOvILGHBi0ceeX7fi4ouWwR3fzgtwx3PYBfrD6XdzeGB1v8eSDUfYTGJPnNmx7Kce1oHe25i1+AR1PNltSk/ia4ktSvIUzJVeLOyO7UisEI+FDxVfyTzQm4XmjhpM4BeW+E5svklNz7xJEx2hetPWOkF8O/LeB/2KsfKgznG75QcH65z9O6375NaI99bqI+ZyO/E90xff3KB1vxvx/UJG/cIEza9C1oiP1JmhrnSLkB6DOvsDtlcGY2sCLMfPfBf4nruzTbxXsnluMb+Qb8jvoqn+5rilPoeMjlmljGJMGfrwE9T8b61+Uk66G/h1pEF5cDrQG0tOC5FrMxc5/2l+8c5acnH2fIDlxfIl4VwZgfw/pMeB/yXPRT2IjcdoeDZQffBfG0PsF2XU5dH9HFPw1uhp4RLQlr2hoyYepEyopC+XXdNVf+haM5Q9C/nHpTaRO4GCw+gTGHSpA+ROD7OMkV3Nc3nWz6it+iZecjwAfl7w22pJhfFwfD/kP/R3je12lBSpf50X5figDjO1luhuUUnl0ezz1D4wJAz8uVwPl/xRE+8PAHxPG17UCGJ82W6H/iPYUXEY3VQ1UvCqItrth7BsL7U+Gfr2x6MfX3rBa/yL8axVv0dOar6TLsbUP/1J58JtInaEN8iNsjwn9N8FP8BP8BD/B/83yaTGATM/lagMS2YnjSAp5IJ2AMKGQ9jXRc5Xg/z/n0wIN0o4ojIMG+a3OfiYzqe2oUbwgngiWHZiDQW2t5rce9XJecvvRT3OC1B6MrR/A4F8Hhvfq0m0f/ocYkHHnJ+UMT84ePeMRMAjHcJqGHRw4WglYvMd1NbhNC1avCJTvW2sS6Dtqfp3xiDtxdLrqh/N4QR4IqT0niNk8L6bXlolWpuMyF03ZDPzVmr98tT29U6ApfKPRivz2ExZ1kdwtzwNjsB8vSrkcL7aoKRddLSL8nbriX6MHq76S6YHGG+WbGcvI7zBxaXfRnQl8e18ogzyO51Mh2Thd98EzHNY19RdoB6s1NbAYg7pGw2/MSEd+3hVrBwi25NG8ZB/A8xLUgZDKc4JN19UKeIZjYPRvgTJYC93hc2LARsSPxEFQkb9QdGT2x6UpI8Ag7A9lnwf1n0KcAgG9Jv/KNniG1bwgfS5IriPxHHx8JzbLoitjKPDPF0THcGC043iheW39Q/vntGJo/5vg9zXw3UIwmPPjyQ9WHXdBvY8DQxj7QB9g5NWLU6Jrh3GHQSiHVVA3n8B525ta5vU8av4ybGsTgX0OL9j6wTjXjgt9gVPT/oObgP8d1MscyP+Ohtp6tHwtWIWBrSdAmZ8piPbB8LOlgQ99UN0E7X85PNtcXnTsa6iPR81XvNnAmALlPrJmaVot/+TXNcssVf+qsh3z7zi6+r4CElQ9orEtIo1K9eVC/4byl87moO/xgtCGBCtWVF/J27veG3IfjH3BSORvLA45yH9ryCPyh8HY2wM+OF51+LtHDyyctjla+R8TP1jVPFhxuNW+Ty45oAYqxKboH7HwyU5QCf0rwU/wE/wEP8FP8OPA/z8BBgB0NyAnicwKswAAAABJRU5ErkJggg==" /> -</g> - -</svg> diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/black_folder.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/black_folder.png Binary files differdeleted file mode 100644 index 01ac4929616..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/black_folder.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/breadcrumb-separator.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/breadcrumb-separator.png Binary files differdeleted file mode 100644 index bbbfbffcf82..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/breadcrumb-separator.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/button_list_view.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/button_list_view.png Binary files differdeleted file mode 100644 index 09aa2fd3a58..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/button_list_view.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/button_list_view_white.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/button_list_view_white.png Binary files differdeleted file mode 100644 index f89199a7e40..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/button_list_view_white.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/button_mosaic_view.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/button_mosaic_view.png Binary files differdeleted file mode 100644 index 1961e46e121..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/button_mosaic_view.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/button_mosaic_view_white.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/button_mosaic_view_white.png Binary files differdeleted file mode 100644 index ad6f856c651..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/button_mosaic_view_white.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/close_bar.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/close_bar.png Binary files differdeleted file mode 100644 index 3f9e4528983..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/close_bar.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/drive_logo.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/drive_logo.png Binary files differdeleted file mode 100644 index be900c88b2b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/drive_logo.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/eject.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/eject.png Binary files differdeleted file mode 100644 index f764c0c4c0f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/eject.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/hashed_bg.gif b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/hashed_bg.gif Binary files differdeleted file mode 100644 index 03651e6ef82..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/hashed_bg.gif +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/icon_search.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/icon_search.png Binary files differdeleted file mode 100644 index 7f2ff27ceef..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/icon_search.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/offline.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/offline.png Binary files differdeleted file mode 100644 index 6fe2d25de02..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/offline.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/onbutton_trash.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/onbutton_trash.png Binary files differdeleted file mode 100644 index 593f53fdba4..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/onbutton_trash.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_closed.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_closed.png Binary files differdeleted file mode 100644 index 92e9e784015..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_closed.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_closed_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_closed_hover.png Binary files differdeleted file mode 100644 index 326f26f6ce2..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_closed_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_closed_pressed.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_closed_pressed.png Binary files differdeleted file mode 100644 index 98aca06f061..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_closed_pressed.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_opened.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_opened.png Binary files differdeleted file mode 100644 index 2e019075159..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_opened.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_opened_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_opened_hover.png Binary files differdeleted file mode 100644 index 18481ce2989..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_opened_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_opened_pressed.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_opened_pressed.png Binary files differdeleted file mode 100644 index 6f4e637d152..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/process_drawer_button_opened_pressed.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/search_clear.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/search_clear.png Binary files differdeleted file mode 100644 index a76574afb43..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/search_clear.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/search_clear_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/search_clear_hover.png Binary files differdeleted file mode 100644 index ed7155a8362..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/search_clear_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/search_clear_pressed.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/search_clear_pressed.png Binary files differdeleted file mode 100644 index 2237a085992..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/search_clear_pressed.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/search_icon_active.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/search_icon_active.png Binary files differdeleted file mode 100644 index d58cd100d67..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/search_icon_active.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/search_icon_inactive.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/search_icon_inactive.png Binary files differdeleted file mode 100644 index 553ebbb1a68..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/search_icon_inactive.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/select_checkbox.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/select_checkbox.png Binary files differdeleted file mode 100644 index e85e010f33b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/select_checkbox.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/select_checkbox_checked.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/select_checkbox_checked.png Binary files differdeleted file mode 100644 index e8792487a26..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/select_checkbox_checked.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/sort_asc.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/sort_asc.png Binary files differdeleted file mode 100644 index 419b29ed735..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/sort_asc.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/sort_desc.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/sort_desc.png Binary files differdeleted file mode 100644 index e7e74c58769..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/sort_desc.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/vertical_separator.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/vertical_separator.png Binary files differdeleted file mode 100644 index 9d14b688ebf..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/vertical_separator.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/warning_icon_square.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/warning_icon_square.png Binary files differdeleted file mode 100644 index 52a8b5a4298..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/warning_icon_square.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/white_folder.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/white_folder.png Binary files differdeleted file mode 100644 index 9124621632c..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/2x/white_folder.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/black_folder.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/black_folder.png Binary files differdeleted file mode 100644 index 539f67759a5..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/black_folder.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/breadcrumb-separator.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/breadcrumb-separator.png Binary files differdeleted file mode 100644 index ed941270f61..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/breadcrumb-separator.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/button_list_view.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/button_list_view.png Binary files differdeleted file mode 100644 index c553781c5e1..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/button_list_view.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/button_list_view_white.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/button_list_view_white.png Binary files differdeleted file mode 100644 index 798df51a9c7..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/button_list_view_white.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/button_mosaic_view.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/button_mosaic_view.png Binary files differdeleted file mode 100644 index 5690834ac3b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/button_mosaic_view.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/button_mosaic_view_white.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/button_mosaic_view_white.png Binary files differdeleted file mode 100644 index 9d4d518bfaa..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/button_mosaic_view_white.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/close_bar.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/close_bar.png Binary files differdeleted file mode 100644 index f7232012fc1..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/close_bar.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/drive_logo.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/drive_logo.png Binary files differdeleted file mode 100644 index b9ec5168cac..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/drive_logo.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/eject.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/eject.png Binary files differdeleted file mode 100644 index dbbdb7f6fcb..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/eject.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/hashed_bg.gif b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/hashed_bg.gif Binary files differdeleted file mode 100644 index 1e5bcfa09f8..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/hashed_bg.gif +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/offline.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/offline.png Binary files differdeleted file mode 100644 index 259d3b20e78..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/offline.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/onbutton_trash.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/onbutton_trash.png Binary files differdeleted file mode 100644 index 20ab756dc43..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/onbutton_trash.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_closed.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_closed.png Binary files differdeleted file mode 100644 index 020e2e65f7c..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_closed.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_closed_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_closed_hover.png Binary files differdeleted file mode 100644 index 193a49b37c4..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_closed_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_closed_pressed.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_closed_pressed.png Binary files differdeleted file mode 100644 index bfee4b01376..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_closed_pressed.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_opened.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_opened.png Binary files differdeleted file mode 100644 index c03e33708fb..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_opened.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_opened_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_opened_hover.png Binary files differdeleted file mode 100644 index bf1aad74d5d..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_opened_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_opened_pressed.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_opened_pressed.png Binary files differdeleted file mode 100644 index dbce527cd8b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/process_drawer_button_opened_pressed.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/search_clear.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/search_clear.png Binary files differdeleted file mode 100644 index 6755c4e8b17..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/search_clear.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/search_clear_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/search_clear_hover.png Binary files differdeleted file mode 100644 index bbfd15f4867..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/search_clear_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/search_clear_pressed.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/search_clear_pressed.png Binary files differdeleted file mode 100644 index 1825168c5c9..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/search_clear_pressed.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/search_icon_active.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/search_icon_active.png Binary files differdeleted file mode 100644 index f59dfe340a7..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/search_icon_active.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/search_icon_inactive.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/search_icon_inactive.png Binary files differdeleted file mode 100644 index 2f17e7c8c16..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/search_icon_inactive.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/select_checkbox.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/select_checkbox.png Binary files differdeleted file mode 100644 index 4010b5c7212..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/select_checkbox.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/select_checkbox_checked.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/select_checkbox_checked.png Binary files differdeleted file mode 100644 index d63f1a44143..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/select_checkbox_checked.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/sort_asc.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/sort_asc.png Binary files differdeleted file mode 100644 index ed8c7d5b8af..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/sort_asc.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/sort_desc.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/sort_desc.png Binary files differdeleted file mode 100644 index f0b2af0a667..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/sort_desc.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/vertical_separator.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/vertical_separator.png Binary files differdeleted file mode 100644 index 512f37f09d6..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/vertical_separator.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/view_thumbs_black.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/view_thumbs_black.png Binary files differdeleted file mode 100644 index 54448aee6a0..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/view_thumbs_black.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/warning_icon_square.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/warning_icon_square.png Binary files differdeleted file mode 100644 index 90d6b608fdb..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/warning_icon_square.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/white_folder.png b/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/white_folder.png Binary files differdeleted file mode 100644 index 07b6aa21f7f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/files/ui/white_folder.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/arrow_left.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/arrow_left.png Binary files differdeleted file mode 100644 index 6e4fb6659a7..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/arrow_left.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/arrow_right.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/arrow_right.png Binary files differdeleted file mode 100644 index 22a6c739432..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/arrow_right.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/back_to_files.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/back_to_files.png Binary files differdeleted file mode 100644 index e04d9d317c2..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/back_to_files.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/bubble_point.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/bubble_point.png Binary files differdeleted file mode 100644 index 161e4c06be4..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/bubble_point.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/butterbar_close_button.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/butterbar_close_button.png Binary files differdeleted file mode 100644 index aa6c816938d..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/butterbar_close_button.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_crop.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_crop.png Binary files differdeleted file mode 100644 index 6202fa978a8..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_crop.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_leftright.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_leftright.png Binary files differdeleted file mode 100644 index a7ee09c632e..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_leftright.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_move.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_move.png Binary files differdeleted file mode 100644 index faa3c8ac398..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_move.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_nwse.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_nwse.png Binary files differdeleted file mode 100644 index 0cd6399da7e..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_nwse.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_swne.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_swne.png Binary files differdeleted file mode 100644 index 04d9dc02702..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_swne.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_updown.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_updown.png Binary files differdeleted file mode 100644 index 1e9adfb5165..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/cursor_updown.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_1up.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_1up.png Binary files differdeleted file mode 100644 index 58cbc28c4cb..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_1up.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_1up_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_1up_selected.png Binary files differdeleted file mode 100644 index a0ca726fa0d..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_1up_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_autofix.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_autofix.png Binary files differdeleted file mode 100644 index 8ce4917d4d2..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_autofix.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_autofix_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_autofix_selected.png Binary files differdeleted file mode 100644 index 8838d5ce5fd..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_autofix_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_brightness.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_brightness.png Binary files differdeleted file mode 100644 index ffcd3852947..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_brightness.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_brightness_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_brightness_selected.png Binary files differdeleted file mode 100644 index 90bf03bbd82..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_brightness_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_contrast.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_contrast.png Binary files differdeleted file mode 100644 index eec931d56de..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_contrast.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_crop.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_crop.png Binary files differdeleted file mode 100644 index 7c12fb54231..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_crop.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_crop_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_crop_selected.png Binary files differdeleted file mode 100644 index bb2e9e6cc0f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_crop_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_delete.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_delete.png Binary files differdeleted file mode 100644 index a55ac6c8086..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_delete.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_delete_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_delete_selected.png Binary files differdeleted file mode 100644 index af54168a2e6..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_delete_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_edit.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_edit.png Binary files differdeleted file mode 100644 index 288bc5b7e47..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_edit.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_edit_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_edit_selected.png Binary files differdeleted file mode 100644 index bcf993396dc..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_edit_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_mosaic.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_mosaic.png Binary files differdeleted file mode 100644 index 3e1a621b559..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_mosaic.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_mosaic_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_mosaic_selected.png Binary files differdeleted file mode 100644 index d9e329d9070..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_mosaic_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_print.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_print.png Binary files differdeleted file mode 100644 index b5a9be0c6ba..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_print.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_print_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_print_selected.png Binary files differdeleted file mode 100644 index 048a34172ec..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_print_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_redo.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_redo.png Binary files differdeleted file mode 100644 index 075275da898..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_redo.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_redo_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_redo_selected.png Binary files differdeleted file mode 100644 index beed584ffe3..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_redo_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_rotate.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_rotate.png Binary files differdeleted file mode 100644 index db2c0b09f9f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_rotate.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_rotate_left.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_rotate_left.png Binary files differdeleted file mode 100644 index da57329d898..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_rotate_left.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_rotate_left_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_rotate_left_selected.png Binary files differdeleted file mode 100644 index d1b00a7e732..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_rotate_left_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_rotate_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_rotate_selected.png Binary files differdeleted file mode 100644 index b3a9bf60a28..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_rotate_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_share.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_share.png Binary files differdeleted file mode 100644 index b1da6d96d47..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_share.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_share_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_share_selected.png Binary files differdeleted file mode 100644 index b3cd00f1118..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_share_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_slideshow.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_slideshow.png Binary files differdeleted file mode 100644 index fec87c0ae9a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_slideshow.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_slideshow_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_slideshow_selected.png Binary files differdeleted file mode 100644 index 4e1ed5aabfa..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_slideshow_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_undo.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_undo.png Binary files differdeleted file mode 100644 index c51fd6258ec..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_undo.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_undo_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_undo_selected.png Binary files differdeleted file mode 100644 index 92d3a01d8e1..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/icon_undo_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/slider_thumb.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/slider_thumb.png Binary files differdeleted file mode 100644 index e100da62618..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/slider_thumb.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/slideshow-end.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/slideshow-end.png Binary files differdeleted file mode 100644 index 5e19f8d002b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/slideshow-end.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/slideshow-pause.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/slideshow-pause.png Binary files differdeleted file mode 100644 index 13457d999fa..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/slideshow-pause.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/slideshow-play.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/slideshow-play.png Binary files differdeleted file mode 100644 index aa9bd88fc8d..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/2x/slideshow-play.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/arrow_left.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/arrow_left.png Binary files differdeleted file mode 100644 index 85e687a1168..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/arrow_left.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/arrow_right.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/arrow_right.png Binary files differdeleted file mode 100644 index 0361556bd20..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/arrow_right.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/back_to_files.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/back_to_files.png Binary files differdeleted file mode 100644 index 96e420a657f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/back_to_files.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/bubble_point.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/bubble_point.png Binary files differdeleted file mode 100644 index a4a44e0cf09..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/bubble_point.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/butterbar_close_button.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/butterbar_close_button.png Binary files differdeleted file mode 100644 index 3c65c230151..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/butterbar_close_button.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_crop.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_crop.png Binary files differdeleted file mode 100644 index 6084188e0a7..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_crop.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_leftright.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_leftright.png Binary files differdeleted file mode 100644 index 30eeb03accf..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_leftright.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_move.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_move.png Binary files differdeleted file mode 100644 index c5026d1b419..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_move.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_nwse.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_nwse.png Binary files differdeleted file mode 100644 index 87fb564ba66..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_nwse.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_swne.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_swne.png Binary files differdeleted file mode 100644 index 5e34475c863..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_swne.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_updown.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_updown.png Binary files differdeleted file mode 100644 index f3a422477c8..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/cursor_updown.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_1up.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_1up.png Binary files differdeleted file mode 100644 index 546e87ae49f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_1up.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_1up_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_1up_selected.png Binary files differdeleted file mode 100644 index a3043a8a05a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_1up_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_autofix.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_autofix.png Binary files differdeleted file mode 100644 index 0fb5b827d76..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_autofix.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_autofix_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_autofix_selected.png Binary files differdeleted file mode 100644 index fb5972d4d9d..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_autofix_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_brightness.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_brightness.png Binary files differdeleted file mode 100644 index ec9c114d245..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_brightness.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_brightness_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_brightness_selected.png Binary files differdeleted file mode 100644 index 88ee72290aa..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_brightness_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_contrast.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_contrast.png Binary files differdeleted file mode 100644 index 0188d483448..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_contrast.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_crop.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_crop.png Binary files differdeleted file mode 100644 index efff5ba58ff..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_crop.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_crop_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_crop_selected.png Binary files differdeleted file mode 100644 index 18b8317cbac..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_crop_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_delete.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_delete.png Binary files differdeleted file mode 100644 index efb132aa722..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_delete.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_delete_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_delete_selected.png Binary files differdeleted file mode 100644 index f2f88d8d0f9..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_delete_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_edit.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_edit.png Binary files differdeleted file mode 100644 index fc72ecf3b60..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_edit.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_edit_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_edit_selected.png Binary files differdeleted file mode 100644 index 61540b5b467..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_edit_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_mosaic.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_mosaic.png Binary files differdeleted file mode 100644 index 6e49d3c929a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_mosaic.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_mosaic_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_mosaic_selected.png Binary files differdeleted file mode 100644 index 86edb6e1ec0..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_mosaic_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_print.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_print.png Binary files differdeleted file mode 100644 index b2355367c25..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_print.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_print_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_print_selected.png Binary files differdeleted file mode 100644 index 657b9c8e290..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_print_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_redo.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_redo.png Binary files differdeleted file mode 100644 index 7b4703b6188..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_redo.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_redo_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_redo_selected.png Binary files differdeleted file mode 100644 index 0022a136d09..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_redo_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_rotate.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_rotate.png Binary files differdeleted file mode 100644 index c60f258f6be..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_rotate.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_rotate_left.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_rotate_left.png Binary files differdeleted file mode 100644 index ef2f21f4356..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_rotate_left.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_rotate_left_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_rotate_left_selected.png Binary files differdeleted file mode 100644 index 1e4c1d6d62f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_rotate_left_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_rotate_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_rotate_selected.png Binary files differdeleted file mode 100644 index 445350fcaf6..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_rotate_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_share.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_share.png Binary files differdeleted file mode 100644 index 36bb2218a82..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_share.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_share_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_share_selected.png Binary files differdeleted file mode 100644 index 438e8a2599a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_share_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_slideshow.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_slideshow.png Binary files differdeleted file mode 100644 index 72763d44ed1..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_slideshow.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_slideshow_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_slideshow_selected.png Binary files differdeleted file mode 100644 index 4f80a48d403..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_slideshow_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_undo.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_undo.png Binary files differdeleted file mode 100644 index 79e3fddf26b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_undo.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_undo_selected.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_undo_selected.png Binary files differdeleted file mode 100644 index d5d13a71a9f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/icon_undo_selected.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/slider_thumb.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/slider_thumb.png Binary files differdeleted file mode 100644 index cb2d712068f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/slider_thumb.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/slideshow-end.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/slideshow-end.png Binary files differdeleted file mode 100644 index f4371115363..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/slideshow-end.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/slideshow-pause.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/slideshow-pause.png Binary files differdeleted file mode 100644 index 2170ce90cfc..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/slideshow-pause.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/slideshow-play.png b/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/slideshow-play.png Binary files differdeleted file mode 100644 index f949121d245..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/gallery/slideshow-play.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/audio_player.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/audio_player.png Binary files differdeleted file mode 100644 index ce5fa1ab7a9..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/audio_player.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/drive.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/drive.png Binary files differdeleted file mode 100644 index b2cef7191e7..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/drive.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/error.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/error.png Binary files differdeleted file mode 100644 index 200baf571a3..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/error.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_close.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_close.png Binary files differdeleted file mode 100644 index 2e19603f5cd..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_close.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_collapse.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_collapse.png Binary files differdeleted file mode 100644 index a9400612019..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_collapse.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_expand.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_expand.png Binary files differdeleted file mode 100644 index 20c234003fd..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_expand.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_fullscreen.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_fullscreen.png Binary files differdeleted file mode 100644 index 090c8257ae6..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_fullscreen.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_fullscreen_disabled.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_fullscreen_disabled.png Binary files differdeleted file mode 100644 index 96b3f635a83..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_fullscreen_disabled.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_fullscreen_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_fullscreen_down.png Binary files differdeleted file mode 100644 index 14cbeecaa87..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_fullscreen_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_fullscreen_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_fullscreen_hover.png Binary files differdeleted file mode 100644 index 25daa4fb6e6..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_fullscreen_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_loop.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_loop.png Binary files differdeleted file mode 100644 index 6bea029799a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_loop.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_loop_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_loop_down.png Binary files differdeleted file mode 100644 index 0e4b6e26d00..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_loop_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_loop_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_loop_hover.png Binary files differdeleted file mode 100644 index b3a6c144a3e..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_loop_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_next.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_next.png Binary files differdeleted file mode 100644 index 012af925e4a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_next.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_next_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_next_down.png Binary files differdeleted file mode 100644 index 58d5bf724e5..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_next_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_next_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_next_hover.png Binary files differdeleted file mode 100644 index d8d199575dc..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_next_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause.png Binary files differdeleted file mode 100644 index acebff9d4a0..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause_audio.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause_audio.png Binary files differdeleted file mode 100644 index 7489a7ed43a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause_audio.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause_audio_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause_audio_down.png Binary files differdeleted file mode 100644 index f9242360d7d..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause_audio_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause_audio_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause_audio_hover.png Binary files differdeleted file mode 100644 index 160d3d11145..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause_audio_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause_down.png Binary files differdeleted file mode 100644 index 9caaf7a0e19..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause_hover.png Binary files differdeleted file mode 100644 index beb86f2e89a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_pause_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play.png Binary files differdeleted file mode 100644 index 28e8a25c032..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_audio.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_audio.png Binary files differdeleted file mode 100644 index 16f663260c9..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_audio.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_audio_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_audio_down.png Binary files differdeleted file mode 100644 index 01dcc462306..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_audio_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_audio_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_audio_hover.png Binary files differdeleted file mode 100644 index c64070f4a24..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_audio_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_disabled.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_disabled.png Binary files differdeleted file mode 100644 index 77ea7c01091..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_disabled.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_down.png Binary files differdeleted file mode 100644 index 7c68787119f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_hover.png Binary files differdeleted file mode 100644 index 28ca18b0551..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_play_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_previous.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_previous.png Binary files differdeleted file mode 100644 index 399e5a00e43..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_previous.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_previous_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_previous_down.png Binary files differdeleted file mode 100644 index 94741583314..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_previous_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_previous_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_previous_hover.png Binary files differdeleted file mode 100644 index 0a8a919c330..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_previous_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_slider_thumb.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_slider_thumb.png Binary files differdeleted file mode 100644 index cd20aa2967f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_slider_thumb.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_slider_thumb_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_slider_thumb_down.png Binary files differdeleted file mode 100644 index 931850f3f52..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_slider_thumb_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_slider_thumb_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_slider_thumb_hover.png Binary files differdeleted file mode 100644 index 9fe30ef7442..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_slider_thumb_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_disabled.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_disabled.png Binary files differdeleted file mode 100644 index acbaa71be9b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_disabled.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_disabled_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_disabled_down.png Binary files differdeleted file mode 100644 index f594f47e774..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_disabled_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_disabled_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_disabled_hover.png Binary files differdeleted file mode 100644 index f4cc7b350f5..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_disabled_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_full.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_full.png Binary files differdeleted file mode 100644 index a093e9f6cd0..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_full.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_full_disabled.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_full_disabled.png Binary files differdeleted file mode 100644 index 56635f1d9b7..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_full_disabled.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_full_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_full_down.png Binary files differdeleted file mode 100644 index 7d2a2395049..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_full_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_full_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_full_hover.png Binary files differdeleted file mode 100644 index f183edd7362..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_full_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level1.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level1.png Binary files differdeleted file mode 100644 index 25904c0d176..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level1.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level1_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level1_down.png Binary files differdeleted file mode 100644 index 0ba2886fbfb..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level1_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level1_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level1_hover.png Binary files differdeleted file mode 100644 index be56fc17e6a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level1_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level2.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level2.png Binary files differdeleted file mode 100644 index 24f7ea805c1..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level2.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level2_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level2_down.png Binary files differdeleted file mode 100644 index 34fce547aa9..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level2_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level2_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level2_hover.png Binary files differdeleted file mode 100644 index 2e3f2e80cd5..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_sound_level2_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_volume_slider_thumb.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_volume_slider_thumb.png Binary files differdeleted file mode 100644 index d5cf0c56e52..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_volume_slider_thumb.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_volume_slider_thumb_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_volume_slider_thumb_down.png Binary files differdeleted file mode 100644 index 034c7b807c3..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_volume_slider_thumb_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_volume_slider_thumb_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_volume_slider_thumb_hover.png Binary files differdeleted file mode 100644 index 4d4243d0f0c..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/media_volume_slider_thumb_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/watch.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/watch.png Binary files differdeleted file mode 100644 index f47751be542..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/2x/watch.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/audio_player.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/audio_player.png Binary files differdeleted file mode 100644 index 6921db2f33d..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/audio_player.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/drive.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/drive.png Binary files differdeleted file mode 100644 index 8f4b64ee8bd..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/drive.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/error.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/error.png Binary files differdeleted file mode 100644 index 125c0b75899..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/error.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_close.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_close.png Binary files differdeleted file mode 100644 index 5980ea7504a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_close.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_collapse.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_collapse.png Binary files differdeleted file mode 100644 index 3ab1add2a9c..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_collapse.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_expand.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_expand.png Binary files differdeleted file mode 100644 index a228fbdf275..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_expand.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_fullscreen.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_fullscreen.png Binary files differdeleted file mode 100644 index 24f2ecf2f1d..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_fullscreen.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_fullscreen_disabled.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_fullscreen_disabled.png Binary files differdeleted file mode 100644 index bf74390888c..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_fullscreen_disabled.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_fullscreen_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_fullscreen_down.png Binary files differdeleted file mode 100644 index dd318cec7d6..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_fullscreen_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_fullscreen_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_fullscreen_hover.png Binary files differdeleted file mode 100644 index 42327397887..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_fullscreen_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_loop.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_loop.png Binary files differdeleted file mode 100644 index f3e35dd9d4a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_loop.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_loop_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_loop_down.png Binary files differdeleted file mode 100644 index dda8af53979..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_loop_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_loop_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_loop_hover.png Binary files differdeleted file mode 100644 index a0ed21fccb8..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_loop_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_next.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_next.png Binary files differdeleted file mode 100644 index aec4ee676a8..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_next.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_next_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_next_down.png Binary files differdeleted file mode 100644 index 53cc1062da0..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_next_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_next_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_next_hover.png Binary files differdeleted file mode 100644 index bea50b59347..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_next_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause.png Binary files differdeleted file mode 100644 index 0a304e4bd04..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause_audio.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause_audio.png Binary files differdeleted file mode 100644 index 8e2e87be5c4..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause_audio.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause_audio_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause_audio_down.png Binary files differdeleted file mode 100644 index 11789840f5b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause_audio_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause_audio_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause_audio_hover.png Binary files differdeleted file mode 100644 index 52b6bbcbf37..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause_audio_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause_down.png Binary files differdeleted file mode 100644 index 6e65195cbea..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause_hover.png Binary files differdeleted file mode 100644 index 993ee50a4f3..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_pause_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play.png Binary files differdeleted file mode 100644 index 47bcdc29b17..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_audio.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_audio.png Binary files differdeleted file mode 100644 index eceaa5bb82b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_audio.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_audio_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_audio_down.png Binary files differdeleted file mode 100644 index 98ebeeaa120..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_audio_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_audio_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_audio_hover.png Binary files differdeleted file mode 100644 index f9d97d7714a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_audio_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_disabled.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_disabled.png Binary files differdeleted file mode 100644 index 6e96d4c9c67..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_disabled.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_down.png Binary files differdeleted file mode 100644 index 1759ec39afa..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_hover.png Binary files differdeleted file mode 100644 index 3942d462656..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_play_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_previous.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_previous.png Binary files differdeleted file mode 100644 index 4fded35ad47..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_previous.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_previous_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_previous_down.png Binary files differdeleted file mode 100644 index 2c63184167e..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_previous_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_previous_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_previous_hover.png Binary files differdeleted file mode 100644 index 45ea61b3b59..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_previous_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_slider_thumb.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_slider_thumb.png Binary files differdeleted file mode 100644 index e55b2c25128..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_slider_thumb.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_slider_thumb_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_slider_thumb_down.png Binary files differdeleted file mode 100644 index f0b2be7d653..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_slider_thumb_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_slider_thumb_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_slider_thumb_hover.png Binary files differdeleted file mode 100644 index e216ae6ffbd..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_slider_thumb_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_disabled.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_disabled.png Binary files differdeleted file mode 100644 index 42126de9330..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_disabled.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_disabled_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_disabled_down.png Binary files differdeleted file mode 100644 index 2b494b93652..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_disabled_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_disabled_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_disabled_hover.png Binary files differdeleted file mode 100644 index 5040f8078d3..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_disabled_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_full.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_full.png Binary files differdeleted file mode 100644 index 4a034029d5c..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_full.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_full_disabled.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_full_disabled.png Binary files differdeleted file mode 100644 index cef4bc4c6d0..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_full_disabled.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_full_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_full_down.png Binary files differdeleted file mode 100644 index 55d77e4d496..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_full_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_full_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_full_hover.png Binary files differdeleted file mode 100644 index 881e84305fb..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_full_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level1.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level1.png Binary files differdeleted file mode 100644 index 2f7ceea32e4..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level1.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level1_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level1_down.png Binary files differdeleted file mode 100644 index 9777c9b5a0b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level1_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level1_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level1_hover.png Binary files differdeleted file mode 100644 index fdf3bc1331b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level1_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level2.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level2.png Binary files differdeleted file mode 100644 index 9379a038ba9..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level2.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level2_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level2_down.png Binary files differdeleted file mode 100644 index 422b43518be..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level2_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level2_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level2_hover.png Binary files differdeleted file mode 100644 index 8bf6157edf4..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_sound_level2_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_volume_slider_thumb.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_volume_slider_thumb.png Binary files differdeleted file mode 100644 index a1bf0577905..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_volume_slider_thumb.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_volume_slider_thumb_down.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_volume_slider_thumb_down.png Binary files differdeleted file mode 100644 index a4560f0ffc2..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_volume_slider_thumb_down.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_volume_slider_thumb_hover.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_volume_slider_thumb_hover.png Binary files differdeleted file mode 100644 index 159e2e71f3e..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/media_volume_slider_thumb_hover.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/media/watch.png b/chromium/chrome/browser/resources/file_manager/foreground/images/media/watch.png Binary files differdeleted file mode 100644 index 92b628497fb..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/media/watch.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/archive.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/archive.png Binary files differdeleted file mode 100644 index b5821d4da5b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/archive.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_archive.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_archive.png Binary files differdeleted file mode 100644 index 6927bdd188e..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_archive.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_downloads.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_downloads.png Binary files differdeleted file mode 100644 index ab37f07104c..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_downloads.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_drive.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_drive.png Binary files differdeleted file mode 100644 index a17a0b19330..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_drive.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_hdd.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_hdd.png Binary files differdeleted file mode 100644 index e0ec6965c2a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_hdd.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_offline.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_offline.png Binary files differdeleted file mode 100644 index 87029a9355c..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_offline.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_optical.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_optical.png Binary files differdeleted file mode 100644 index 5077474e3b1..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_optical.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_phone.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_phone.png Binary files differdeleted file mode 100644 index c4521dec634..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_phone.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_recent.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_recent.png Binary files differdeleted file mode 100644 index e1b86212136..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_recent.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_sd.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_sd.png Binary files differdeleted file mode 100644 index 5679089adcf..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_sd.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_shared.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_shared.png Binary files differdeleted file mode 100644 index ec7c3e4779a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_shared.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_trash.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_trash.png Binary files differdeleted file mode 100644 index 67f261f460a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_trash.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_usb.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_usb.png Binary files differdeleted file mode 100644 index 2cceca66e9c..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/black_usb.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_hd.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_hd.png Binary files differdeleted file mode 100644 index e0ec6965c2a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_hd.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_optical.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_optical.png Binary files differdeleted file mode 100644 index 5077474e3b1..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_optical.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_sd.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_sd.png Binary files differdeleted file mode 100644 index 5679089adcf..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_sd.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_sd_large.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_sd_large.png Binary files differdeleted file mode 100644 index 6fa0c756dce..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_sd_large.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_usb.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_usb.png Binary files differdeleted file mode 100644 index 70e9686f3a2..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_usb.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_usb_large.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_usb_large.png Binary files differdeleted file mode 100644 index 17a8fee01f7..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/device_usb_large.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/downloads.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/downloads.png Binary files differdeleted file mode 100644 index 22e66179190..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/downloads.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/drive.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/drive.png Binary files differdeleted file mode 100644 index a17a0b19330..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/drive.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/drive_offline.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/drive_offline.png Binary files differdeleted file mode 100644 index 75981854cd6..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/drive_offline.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/drive_recent.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/drive_recent.png Binary files differdeleted file mode 100644 index 756e36a2e38..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/drive_recent.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/drive_shared.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/drive_shared.png Binary files differdeleted file mode 100644 index c2eb5dafb30..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/drive_shared.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/folder.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/folder.png Binary files differdeleted file mode 100644 index 01ac4929616..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/folder.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_archive.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_archive.png Binary files differdeleted file mode 100644 index 481c40b89f1..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_archive.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_downloads.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_downloads.png Binary files differdeleted file mode 100644 index 5262bb910a8..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_downloads.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_drive.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_drive.png Binary files differdeleted file mode 100644 index 5f43989d923..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_drive.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_hdd.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_hdd.png Binary files differdeleted file mode 100644 index bc5e8c417d9..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_hdd.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_offline.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_offline.png Binary files differdeleted file mode 100644 index 9d65b392094..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_offline.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_optical.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_optical.png Binary files differdeleted file mode 100644 index c67537714dd..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_optical.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_phone.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_phone.png Binary files differdeleted file mode 100644 index 2dfb8f27d61..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_phone.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_recent.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_recent.png Binary files differdeleted file mode 100644 index a80eae2c8b3..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_recent.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_sd.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_sd.png Binary files differdeleted file mode 100644 index 282de9aa9af..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_sd.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_shared.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_shared.png Binary files differdeleted file mode 100644 index 24ea1676b15..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_shared.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_trash.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_trash.png Binary files differdeleted file mode 100644 index f6c5ccb03f4..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_trash.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_usb.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_usb.png Binary files differdeleted file mode 100644 index f296f4e0245..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/2x/white_usb.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_archive.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_archive.png Binary files differdeleted file mode 100644 index e4514206fbd..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_archive.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_downloads.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_downloads.png Binary files differdeleted file mode 100644 index e25c8756b32..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_downloads.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_drive.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_drive.png Binary files differdeleted file mode 100644 index 891ec480c47..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_drive.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_folder.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_folder.png Binary files differdeleted file mode 100644 index 539f67759a5..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_folder.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_hdd.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_hdd.png Binary files differdeleted file mode 100644 index 53c02b4c48c..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_hdd.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_offline.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_offline.png Binary files differdeleted file mode 100644 index a07ef0cb483..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_offline.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_optical.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_optical.png Binary files differdeleted file mode 100644 index 30a905fbc9c..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_optical.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_phone.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_phone.png Binary files differdeleted file mode 100644 index aa3aa9deb7c..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_phone.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_recent.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_recent.png Binary files differdeleted file mode 100644 index 6e5d3636bff..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_recent.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_sd.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_sd.png Binary files differdeleted file mode 100644 index f24b4cefb74..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_sd.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_shared.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_shared.png Binary files differdeleted file mode 100644 index 10a1553b9b0..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_shared.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_trash.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_trash.png Binary files differdeleted file mode 100644 index 7708ae555a6..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_trash.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_usb.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_usb.png Binary files differdeleted file mode 100644 index ba7ef472471..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/black_usb.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/device_sd_large.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/device_sd_large.png Binary files differdeleted file mode 100644 index 39d2fe90a49..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/device_sd_large.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/device_usb_large.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/device_usb_large.png Binary files differdeleted file mode 100644 index 6b68508f7d8..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/device_usb_large.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_archive.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_archive.png Binary files differdeleted file mode 100644 index 3b542deac45..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_archive.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_downloads.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_downloads.png Binary files differdeleted file mode 100644 index 8b1cfdf7400..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_downloads.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_drive.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_drive.png Binary files differdeleted file mode 100644 index 0226fbd14ed..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_drive.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_folder.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_folder.png Binary files differdeleted file mode 100644 index 07b6aa21f7f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_folder.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_hdd.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_hdd.png Binary files differdeleted file mode 100644 index b7c4a485c94..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_hdd.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_offline.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_offline.png Binary files differdeleted file mode 100644 index 503ed67f82f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_offline.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_optical.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_optical.png Binary files differdeleted file mode 100644 index 3f13f723af4..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_optical.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_phone.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_phone.png Binary files differdeleted file mode 100644 index d187ef0951b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_phone.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_recent.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_recent.png Binary files differdeleted file mode 100644 index 23c526ad8b2..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_recent.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_sd.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_sd.png Binary files differdeleted file mode 100644 index f7f465c430b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_sd.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_shared.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_shared.png Binary files differdeleted file mode 100644 index 051191e6de1..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_shared.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_trash.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_trash.png Binary files differdeleted file mode 100644 index f95d0215ee4..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_trash.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_usb.png b/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_usb.png Binary files differdeleted file mode 100644 index 954a3c6dae3..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/images/volumes/white_usb.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/app_installer.js b/chromium/chrome/browser/resources/file_manager/foreground/js/app_installer.js deleted file mode 100644 index 7914d6e458f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/app_installer.js +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * Manage the installation of apps. - * - * @param {string} itemId Item id to be installed. - * @constructor - * @extends {cr.EventType} - */ -function AppInstaller(itemId) { - this.itemId_ = itemId; - this.callback_ = null; - - Object.seal(this); -} - -AppInstaller.prototype = { -}; - -/** - * Type of result. - * - * @enum {string} - * @const - */ -AppInstaller.Result = { - SUCCESS: 'AppInstaller.success', - CANCELLED: 'AppInstaller.cancelled', - ERROR: 'AppInstaller.error' -}; -Object.freeze(AppInstaller.Result); - -/** - * Error message for user cancellation. This must be match with the constant - * 'kUserCancelledError' in C/B/extensions/webstore_standalone_installer.cc. - * @type {string} - * @const - * @private - */ -AppInstaller.USER_CANCELLED_ERROR_STR_ = 'User cancelled install'; - -/** - * Start an installation. - * @param {function(boolean, string)} callback Called when the installation is - * finished. - */ -AppInstaller.prototype.install = function(callback) { - this.callback_ = callback; - chrome.fileBrowserPrivate.installWebstoreItem( - this.itemId_, - function() { - this.onInstallCompleted_(chrome.runtime.lastError); - }.bind(this)); -}; - -/** - * Called when the installation is completed. - * - * @param {{message: string}?} error Null if the installation is success, - * otherwise an object which contains error message. - * @private - */ -AppInstaller.prototype.onInstallCompleted_ = function(error) { - var installerResult = AppInstaller.Result.SUCCESS; - var errorMessage = ''; - if (error) { - installerResult = - error.message == AppInstaller.USER_CANCELLED_ERROR_STR_ ? - AppInstaller.Result.CANCELLED : - AppInstaller.Result.ERROR; - errorMessage = error.message; - } - this.callback_(installerResult, errorMessage); - this.callback_ = null; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/combobutton.js b/chromium/chrome/browser/resources/file_manager/foreground/js/combobutton.js deleted file mode 100644 index 59ae9f2b6ed..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/combobutton.js +++ /dev/null @@ -1,154 +0,0 @@ -// 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. - -'use strict'; - -/** - * @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(cr.ui.MenuButton); - - - ComboButton.prototype = { - __proto__: cr.ui.MenuButton.prototype, - - defaultItem_: null, - - /** - * Truncates drop-down list. - */ - clear: function() { - this.menu.clear(); - this.multiple = false; - }, - - addDropDownItem: function(item) { - this.multiple = true; - var menuitem = this.menu.addMenuItem(item); - menuitem.data = item; - if (item.iconType) { - menuitem.style.backgroundImage = ''; - menuitem.setAttribute('file-type-icon', item.iconType); - } - if (item.bold) { - menuitem.style.fontWeight = 'bold'; - } - return menuitem; - }, - - /** - * Adds separator to drop-down list. - */ - addSeparator: function() { - this.menu.addSeparator(); - }, - - /** - * Default item to fire on combobox click - */ - get defaultItem() { - return this.defaultItem_; - }, - set defaultItem(defaultItem) { - this.defaultItem_ = defaultItem; - - this.actionNode_.textContent = defaultItem.label || ''; - - if (defaultItem.iconType) { - this.actionNode_.style.backgroundImage = ''; - this.actionNode_.setAttribute('file-type-icon', defaultItem.iconType); - } else if (defaultItem.iconUrl) { - this.actionNode_.style.backgroundImage = - 'url(' + defaultItem.iconUrl + ')'; - } else { - this.actionNode_.style.backgroundImage = ''; - } - }, - - /** - * Initializes the element. - */ - decorate: function() { - cr.ui.MenuButton.prototype.decorate.call(this); - - this.classList.add('combobutton'); - - this.actionNode_ = this.ownerDocument.createElement('div'); - this.actionNode_.classList.add('action'); - this.appendChild(this.actionNode_); - - var triggerIcon = this.ownerDocument.createElement('span'); - triggerIcon.className = 'disclosureindicator'; - this.trigger_ = this.ownerDocument.createElement('div'); - this.trigger_.classList.add('trigger'); - this.trigger_.appendChild(triggerIcon); - - this.appendChild(this.trigger_); - - this.addEventListener('click', this.handleButtonClick_.bind(this)); - - this.trigger_.addEventListener('click', - this.handleTriggerClicked_.bind(this)); - - this.menu.addEventListener('activate', - this.handleMenuActivate_.bind(this)); - - // Remove mousedown event listener created by MenuButton::decorate, - // and move it down to trigger_. - this.removeEventListener('mousedown', this); - this.trigger_.addEventListener('mousedown', this); - }, - - /** - * Handles the keydown event for the menu button. - */ - handleKeyDown: function(e) { - switch (e.keyIdentifier) { - case 'Down': - case 'Up': - if (!this.isMenuShown()) - this.showMenu(); - e.preventDefault(); - break; - case 'Esc': - case 'U+001B': // Maybe this is remote desktop playing a prank? - this.hideMenu(); - break; - } - }, - - handleTriggerClicked_: function(event) { - event.stopPropagation(); - }, - - handleMenuActivate_: function(event) { - this.dispatchSelectEvent(event.target.data); - }, - - handleButtonClick_: function() { - this.dispatchSelectEvent(this.defaultItem_); - }, - - dispatchSelectEvent: function(item) { - var selectEvent = new Event('select'); - selectEvent.item = item; - this.dispatchEvent(selectEvent); - } - }; - - cr.defineProperty(ComboButton, 'disabled', cr.PropertyKind.BOOL_ATTR); - cr.defineProperty(ComboButton, 'multiple', cr.PropertyKind.BOOL_ATTR); - - return { - ComboButton: ComboButton - }; -}); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/commandbutton.js b/chromium/chrome/browser/resources/file_manager/foreground/js/commandbutton.js deleted file mode 100644 index b6f2b916cd3..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/commandbutton.js +++ /dev/null @@ -1,136 +0,0 @@ -// 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. - -'use strict'; - -/** - * @fileoverview This implements a common button control, bound to command. - */ - -/** - * Creates a new button element. - * @param {Object=} opt_propertyBag Optional properties. - * @constructor - * @extends {HTMLDivElement} - */ - var CommandButton = cr.ui.define('button'); - -/** @override */ -CommandButton.prototype.__proto__ = HTMLButtonElement.prototype; - -/** - * Associated command. - * @type {Command} - * @private - */ -CommandButton.prototype.command_ = null; - -/** - * Initializes the menu item. - */ -CommandButton.prototype.decorate = function() { - var commandId; - if ((commandId = this.getAttribute('command'))) - this.setCommand(commandId); - - this.addEventListener('click', this.handleClick_.bind(this)); -}; - -/** - * Returns associated command. - * @return {cr.ui.Command} associated command. - */ -CommandButton.prototype.getCommand = function() { - return this.command_; -}; - -/** - * Associates command with this button. - * @param {string|cr.ui.Command} command Command id, or command object to - * associate with this button. - */ -CommandButton.prototype.setCommand = function(command) { - if (this.command_) { - this.command_.removeEventListener('labelChange', this); - this.command_.removeEventListener('disabledChange', this); - this.command_.removeEventListener('hiddenChange', this); - } - - if (typeof command == 'string' && command[0] == '#') { - command = this.ownerDocument.getElementById(command.slice(1)); - cr.ui.decorate(command, cr.ui.Command); - } - - this.command_ = command; - if (command) { - if (command.id) - this.setAttribute('command', '#' + command.id); - - this.setLabel(command.label); - this.disabled = command.disabled; - this.hidden = command.hidden; - - this.command_.addEventListener('labelChange', this); - this.command_.addEventListener('disabledChange', this); - this.command_.addEventListener('hiddenChange', this); - } -}; - -/** - * Returns button label - * @return {string} Button label. - */ -CommandButton.prototype.getLabel = function() { - return this.textContent; -}; - -/** - * Sets button label. - * @param {string} label New button label. - */ -CommandButton.prototype.setLabel = function(label) { - this.textContent = label; -}; - -/** - * Handles click event and dispatches associated command. - * @param {Event} e The mouseup event object. - * @private - */ -CommandButton.prototype.handleClick_ = function(e) { - if (!this.disabled && this.command_) - this.command_.execute(this); -}; - -/** - * Handles changes to the associated command. - * @param {Event} e The event object. - */ -CommandButton.prototype.handleEvent = function(e) { - switch (e.type) { - case 'disabledChange': - this.disabled = this.command_.disabled; - break; - case 'hiddenChange': - this.hidden = this.command_.hidden; - break; - case 'labelChange': - this.setLabel(this.command_.label); - break; - } -}; - -/** - * Whether the button is disabled or not. - * @type {boolean} - */ -cr.defineProperty(CommandButton, 'disabled', - cr.PropertyKind.BOOL_ATTR); - -/** - * Whether the button is hidden or not. - * @type {boolean} - */ -cr.defineProperty(CommandButton, 'hidden', - cr.PropertyKind.BOOL_ATTR); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/cws_container_client.js b/chromium/chrome/browser/resources/file_manager/foreground/js/cws_container_client.js deleted file mode 100644 index fae6787a5ad..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/cws_container_client.js +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * @param {WebView} webView Web View tag. - * @param {?string} ext File extension. - * @param {?string} mime File mime type. - * @param {?string} searchQuery Search query. - * @param {number} width Width of the CWS widget. - * @param {number} height Height of the CWS widget. - * @param {string} url Share Url for an entry. - * @param {string} target Target (scheme + host + port) of the widget. - * @constructor - */ -function CWSContainerClient( - webView, ext, mime, searchQuery, width, height, url, target) { - this.webView_ = webView; - this.ext_ = (ext && ext[0] == '.') ? ext.substr(1) : ext; - this.mime_ = mime; - this.searchQuery_ = searchQuery; - this.width_ = width; - this.height_ = height; - this.url_ = url; - this.target_ = target; - - this.loaded_ = false; - this.loading_ = false; - - this.onMessageBound_ = this.onMessage_.bind(this); - this.onLoadStopBound_ = this.onLoadStop_.bind(this); - this.onLoadAbortBound_ = this.onLoadAbort_.bind(this); -} - -CWSContainerClient.prototype = { - __proto__: cr.EventTarget.prototype -}; - -/** - * Events CWSContainerClient fires - * - * @enum {string} - * @const - */ -CWSContainerClient.Events = { - LOADED: 'CWSContainerClient.Events.LOADED', - LOAD_FAILED: 'CWSContainerClient.Events.LOAD_FAILED', - REQUEST_INSTALL: 'CWSContainerClient.Events.REQUEST_INSTALL' -}; -Object.freeze(CWSContainerClient.Events); - -/** - * Handles messages from the widget - * @param {Event} event Message event. - * @private - */ -CWSContainerClient.prototype.onMessage_ = function(event) { - if (event.origin != this.target_) - return; - - var data = event.data; - switch (data['message']) { - case 'widget_loaded': - this.onWidgetLoaded_(); - break; - case 'widget_load_failed': - this.onWidgetLoadFailed_(); - break; - case 'before_install': - this.sendInstallRequest_(data['item_id']); - break; - default: - console.error('Unexpected message: ' + data['message'], data); - } -}; - -/** - * Called when receiving 'loadstop' event from the <wevview>. - * @param {Event} event Message event. - * @private - */ -CWSContainerClient.prototype.onLoadStop_ = function(event) { - if (this.url_ == this.webView_.src && !this.loaded_) { - this.loaded_ = true; - this.postInitializeMessage_(); - } -}; - -/** - * Called when the widget is loaded successfully. - * @private - */ -CWSContainerClient.prototype.onWidgetLoaded_ = function() { - cr.dispatchSimpleEvent(this, CWSContainerClient.Events.LOADED); -}; - -/** - * Called when the widget is failed to load. - * @private - */ -CWSContainerClient.prototype.onWidgetLoadFailed_ = function() { - this.sendWidgetLoadFailed_(); -}; - -/** - * Called when receiving the 'loadabort' event from <webview>. - * @param {Event} event Message event. - * @private - */ -CWSContainerClient.prototype.onLoadAbort_ = function(event) { - this.sendWidgetLoadFailed_(); -}; - -/** - * Called when the installation is completed from the suggest-app dialog. - * - * @param {boolean} result True if the installation is success, false if failed. - * @param {string} itemId Item id to be installed. - */ -CWSContainerClient.prototype.onInstallCompleted = function(result, itemId) { - if (result) - this.postInstallSuccessMessage_(itemId); - else - this.postInstallFailureMessage_(itemId); -}; - -/** - * Send the fail message to the suggest-app dialog. - * @private - */ -CWSContainerClient.prototype.sendWidgetLoadFailed_ = function() { - cr.dispatchSimpleEvent(this, CWSContainerClient.Events.LOAD_FAILED); -}; - -/** - * Send the install request to the suggest-app dialog. - * - * @param {string} itemId Item id to be installed. - * @private - */ -CWSContainerClient.prototype.sendInstallRequest_ = function(itemId) { - var event = new Event(CWSContainerClient.Events.REQUEST_INSTALL); - event.itemId = itemId; - this.dispatchEvent(event); -}; - -/** - * Send the 'install_failure' message to the widget. - * - * @param {string} itemId Item id to be installed. - * @private - */ -CWSContainerClient.prototype.postInstallFailureMessage_ = function(itemId) { - var message = { - message: 'install_failure', - item_id: itemId, - v: 1 - }; - - this.postMessage_(message); -}; - -/** - * Send the 'install_success' message to the widget. - * - * @param {string} itemId Item id to be installed. - * @private - */ -CWSContainerClient.prototype.postInstallSuccessMessage_ = function(itemId) { - var message = { - message: 'install_success', - item_id: itemId, - v: 1 - }; - - this.postMessage_(message); -}; - -/** - * Send the 'initialize' message to the widget. - * @private - */ -CWSContainerClient.prototype.postInitializeMessage_ = function() { - var message = { - message: 'initialize', - hl: util.getCurrentLocaleOrDefault(), - widgth: this.width_, - height: this.height_, - v: 1 - }; - - if (this.searchQuery_) { - message['search_query'] = this.searchQuery_; - } else { - message['file_extension'] = this.ext_; - message['mime_type'] = this.mime_; - } - - this.postMessage_(message); -}; - -/** - * Send a message to the widget. This method shouldn't be called directly, - * should from more specified posting function (eg. postXyzMessage_()). - * - * @param {object} message Message object to be posted. - * @private - */ -CWSContainerClient.prototype.postMessage_ = function(message) { - if (!this.webView_.contentWindow) - return; - - this.webView_.contentWindow.postMessage(message, this.target_); -}; - -/** - * Loads the page to <webview>. Can be called only once. - */ -CWSContainerClient.prototype.load = function() { - if (this.loading_ || this.loaded_) - throw new Error('Already loaded.'); - this.loading_ = true; - this.loaded_ = false; - - window.addEventListener('message', this.onMessageBound_); - this.webView_.addEventListener('loadstop', this.onLoadStopBound_); - this.webView_.addEventListener('loadabort', this.onLoadAbortBound_); - this.webView_.setAttribute('src', this.url_); -}; - -/** - * Aborts loading of the embedded dialog and performs cleanup. - */ -CWSContainerClient.prototype.abort = function() { - window.removeEventListener('message', this.onMessageBound_); - this.webView_.removeEventListener('loadstop', this.onLoadStopBound_); - this.webView_.removeEventListener( - 'loadabort', this.onLoadAbortBound_); - this.webView_.stop(); -}; - -/** - * Cleans the dialog by removing all handlers. - */ -CWSContainerClient.prototype.dispose = function() { - this.abort(); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/default_action_dialog.js b/chromium/chrome/browser/resources/file_manager/foreground/js/default_action_dialog.js deleted file mode 100644 index a5c8290a239..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/default_action_dialog.js +++ /dev/null @@ -1,157 +0,0 @@ -// 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. - -'use strict'; - - -/** - * DefaultActionDialog contains a message, a list box, an ok button, and a - * cancel button. - * This dialog should be used as action picker for file operations. - */ -cr.define('cr.filebrowser', function() { - - /** - * Creates dialog in DOM tree. - * - * @param {HTMLElement} parentNode Node to be parent for this dialog. - * @constructor - * @extends {FileManagerDialogBase} - */ - function DefaultActionDialog(parentNode) { - FileManagerDialogBase.call(this, parentNode); - - this.frame_.id = 'default-action-dialog'; - - this.list_ = new cr.ui.List(); - this.list_.id = 'default-actions-list'; - this.frame_.insertBefore(this.list_, this.text_.nextSibling); - - this.selectionModel_ = this.list_.selectionModel = - new cr.ui.ListSingleSelectionModel(); - this.dataModel_ = this.list_.dataModel = new cr.ui.ArrayDataModel([]); - - // List has max-height defined at css, so that list grows automatically, - // but doesn't exceed predefined size. - this.list_.autoExpands = true; - this.list_.activateItemAtIndex = this.activateItemAtIndex_.bind(this); - - this.initialFocusElement_ = this.list_; - - var self = this; - - // Binding stuff doesn't work with constructors, so we have to create - // closure here. - this.list_.itemConstructor = function(item) { - return self.renderItem(item); - }; - } - - DefaultActionDialog.prototype = { - __proto__: FileManagerDialogBase.prototype - }; - - /** - * @override - */ - DefaultActionDialog.prototype.onInputFocus = function() { - this.list_.select(); - }; - - /** - * Renders item for list. - * @param {Object} item Item to render. - */ - DefaultActionDialog.prototype.renderItem = function(item) { - var result = this.document_.createElement('li'); - - var div = this.document_.createElement('div'); - div.textContent = item.label; - - if (item.iconType) { - div.setAttribute('file-type-icon', item.iconType); - } else if (item.iconUrl) { - div.style.backgroundImage = 'url(' + item.iconUrl + ')'; - } - - if (item.class) - div.classList.add(item.class); - - result.appendChild(div); - - cr.defineProperty(result, 'lead', cr.PropertyKind.BOOL_ATTR); - cr.defineProperty(result, 'selected', cr.PropertyKind.BOOL_ATTR); - - return result; - }; - - /** - * Shows dialog. - * - * @param {string} title Title in dialog caption. - * @param {string} message Message in dialog caption. - * @param {Array.<Object>} items Items to render in the list. - * @param {number} defaultIndex Item to select by default. - * @param {function(Object=)} opt_onOk OK callback with the selected item. - * @param {function()=} opt_onCancel Cancel callback. - */ - DefaultActionDialog.prototype.show = function(title, message, items, - defaultIndex, opt_onOk, opt_onCancel) { - - var show = FileManagerDialogBase.prototype.showOkCancelDialog.call( - this, title, message, opt_onOk, opt_onCancel); - - if (!show) { - console.error('DefaultActionDialog can\'t be shown.'); - return; - } - - if (!message) { - this.text_.setAttribute('hidden', 'hidden'); - } else { - this.text_.removeAttribute('hidden'); - } - - this.list_.startBatchUpdates(); - this.dataModel_.splice(0, this.dataModel_.length); - for (var i = 0; i < items.length; i++) { - this.dataModel_.push(items[i]); - } - this.selectionModel_.selectedIndex = defaultIndex; - this.list_.endBatchUpdates(); - }; - - /** - * List activation handler. Closes dialog and calls 'ok' callback. - * @param {number} index Activated index. - */ - DefaultActionDialog.prototype.activateItemAtIndex_ = function(index) { - this.hide(); - this.onOk_(this.dataModel_.item(index)); - }; - - /** - * Closes dialog and invokes callback with currently-selected item. - * @override - */ - DefaultActionDialog.prototype.onOkClick_ = function() { - this.activateItemAtIndex_(this.selectionModel_.selectedIndex); - }; - - /** - * @override - */ - DefaultActionDialog.prototype.onContainerKeyDown_ = function(event) { - // Handle Escape. - if (event.keyCode == 27) { - this.onCancelClick_(event); - event.preventDefault(); - } else if (event.keyCode == 32 || event.keyCode == 13) { - this.onOkClick_(); - event.preventDefault(); - } - }; - - return {DefaultActionDialog: DefaultActionDialog}; -}); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/directory_contents.js b/chromium/chrome/browser/resources/file_manager/foreground/js/directory_contents.js deleted file mode 100644 index be69b66af90..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/directory_contents.js +++ /dev/null @@ -1,770 +0,0 @@ -// 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. - -'use strict'; - -/** - * Scanner of the entries. - * @constructor - */ -function ContentScanner() { - this.cancelled_ = false; -} - -/** - * Starts to scan the entries. For example, starts to read the entries in a - * directory, or starts to search with some query on a file system. - * Derived classes must override this method. - * - * @param {function(Array.<Entry>)} entriesCallback Called when some chunk of - * entries are read. This can be called a couple of times until the - * completion. - * @param {function()} successCallback Called when the scan is completed - * successfully. - * @param {function(FileError)} errorCallback Called an error occurs. - */ -ContentScanner.prototype.scan = function( - entriesCallback, successCallback, errorCallback) { -}; - -/** - * Request cancelling of the running scan. When the cancelling is done, - * an error will be reported from errorCallback passed to scan(). - */ -ContentScanner.prototype.cancel = function() { - this.cancelled_ = true; -}; - -/** - * Scanner of the entries in a directory. - * @param {DirectoryEntry} entry The directory to be read. - * @constructor - * @extends {ContentScanner} - */ -function DirectoryContentScanner(entry) { - ContentScanner.call(this); - this.entry_ = entry; -} - -/** - * Extends ContentScanner. - */ -DirectoryContentScanner.prototype.__proto__ = ContentScanner.prototype; - -/** - * Starts to read the entries in the directory. - * @override - */ -DirectoryContentScanner.prototype.scan = function( - entriesCallback, successCallback, errorCallback) { - if (!this.entry_ || this.entry_ === DirectoryModel.fakeDriveEntry_) { - // If entry is not specified or a fake, we cannot read it. - errorCallback(util.createFileError(FileError.INVALID_MODIFICATION_ERR)); - return; - } - - metrics.startInterval('DirectoryScan'); - var reader = this.entry_.createReader(); - var readEntries = function() { - reader.readEntries( - function(entries) { - if (this.cancelled_) { - errorCallback(util.createFileError(FileError.ABORT_ERR)); - return; - } - - if (entries.length === 0) { - // All entries are read. - metrics.recordInterval('DirectoryScan'); - successCallback(); - return; - } - - entriesCallback(entries); - readEntries(); - }.bind(this), - errorCallback); - }.bind(this); - readEntries(); -}; - -/** - * Scanner of the entries for the search results on Drive File System. - * @param {string} query The query string. - * @constructor - * @extends {ContentScanner} - */ -function DriveSearchContentScanner(query) { - ContentScanner.call(this); - this.query_ = query; -} - -/** - * Extends ContentScanner. - */ -DriveSearchContentScanner.prototype.__proto__ = ContentScanner.prototype; - -/** - * Delay in milliseconds to be used for drive search scan, in order to reduce - * the number of server requests while user is typing the query. - * @type {number} - * @private - * @const - */ -DriveSearchContentScanner.SCAN_DELAY_ = 200; - -/** - * Maximum number of results which is shown on the search. - * @type {number} - * @private - * @const - */ -DriveSearchContentScanner.MAX_RESULTS_ = 100; - -/** - * Starts to search on Drive File System. - * @override - */ -DriveSearchContentScanner.prototype.scan = function( - entriesCallback, successCallback, errorCallback) { - var numReadEntries = 0; - var readEntries = function(nextFeed) { - chrome.fileBrowserPrivate.searchDrive( - {query: this.query_, nextFeed: nextFeed}, - function(entries, nextFeed) { - if (this.cancelled_) { - errorCallback(util.createFileError(FileError.ABORT_ERR)); - return; - } - - // TODO(tbarzic): Improve error handling. - if (!entries) { - console.error('Drive search encountered an error.'); - errorCallback(util.createFileError( - FileError.INVALID_MODIFICATION_ERR)); - return; - } - - var numRemainingEntries = - DriveSearchContentScanner.MAX_RESULTS_ - numReadEntries; - if (entries.length >= numRemainingEntries) { - // The limit is hit, so quit the scan here. - entries = entries.slice(0, numRemainingEntries); - nextFeed = ''; - } - - numReadEntries += entries.length; - if (entries.length > 0) - entriesCallback(entries); - - if (nextFeed === '') - successCallback(); - else - readEntries(nextFeed); - }.bind(this)); - }.bind(this); - - // Let's give another search a chance to cancel us before we begin. - setTimeout( - function() { - // Check cancelled state before read the entries. - if (this.cancelled_) { - errorCallback(util.createFileError(FileError.ABORT_ERR)); - return; - } - readEntries(''); - }.bind(this), - DriveSearchContentScanner.SCAN_DELAY_); -}; - -/** - * Scanner of the entries of the file name search on the directory tree, whose - * root is entry. - * @param {DirectoryEntry} entry The root of the search target directory tree. - * @param {string} query The query of the search. - * @constructor - * @extends {ContentScanner} - */ -function LocalSearchContentScanner(entry, query) { - ContentScanner.call(this); - this.entry_ = entry; - this.query_ = query.toLowerCase(); -} - -/** - * Extedns ContentScanner. - */ -LocalSearchContentScanner.prototype.__proto__ = ContentScanner.prototype; - -/** - * Starts the file name search. - * @override - */ -LocalSearchContentScanner.prototype.scan = function( - entriesCallback, successCallback, errorCallback) { - var numRunningTasks = 0; - var error = null; - var maybeRunCallback = function() { - if (numRunningTasks === 0) { - if (this.cancelled_) - errorCallback(util.createFileError(FileError.ABORT_ERR)); - else if (error) - errorCallback(error); - else - successCallback(); - } - }.bind(this); - - var processEntry = function(entry) { - numRunningTasks++; - var onError = function(fileError) { - if (!error) - error = fileError; - numRunningTasks--; - maybeRunCallback(); - }; - - var onSuccess = function(entries) { - if (this.cancelled_ || error || entries.length === 0) { - numRunningTasks--; - maybeRunCallback(); - return; - } - - // Filters by the query, and if found, run entriesCallback. - var foundEntries = entries.filter(function(entry) { - return entry.name.toLowerCase().indexOf(this.query_) >= 0; - }.bind(this)); - if (foundEntries.length > 0) - entriesCallback(foundEntries); - - // Start to process sub directories. - for (var i = 0; i < entries.length; i++) { - if (entries[i].isDirectory) - processEntry(entries[i]); - } - - // Read remaining entries. - reader.readEntries(onSuccess, onError); - }.bind(this); - - var reader = entry.createReader(); - reader.readEntries(onSuccess, onError); - }.bind(this); - - processEntry(this.entry_); -}; - -/** - * Scanner of the entries for the metadata search on Drive File System. - * @param {string} query The query of the search. - * @param {DriveMetadataSearchContentScanner.SearchType} searchType The option - * of the search. - * @constructor - * @extends {ContentScanner} - */ -function DriveMetadataSearchContentScanner(query, searchType) { - ContentScanner.call(this); - this.query_ = query; - this.searchType_ = searchType; -} - -/** - * Extends ContentScanner. - */ -DriveMetadataSearchContentScanner.prototype.__proto__ = - ContentScanner.prototype; - -/** - * The search types on the Drive File System. - * @enum {string} - */ -DriveMetadataSearchContentScanner.SearchType = Object.freeze({ - SEARCH_ALL: 'ALL', - SEARCH_SHARED_WITH_ME: 'SHARED_WITH_ME', - SEARCH_RECENT_FILES: 'EXCLUDE_DIRECTORIES', - SEARCH_OFFLINE: 'OFFLINE' -}); - -/** - * Starts to metadata-search on Drive File System. - * @override - */ -DriveMetadataSearchContentScanner.prototype.scan = function( - entriesCallback, successCallback, errorCallback) { - chrome.fileBrowserPrivate.searchDriveMetadata( - {query: this.query_, types: this.searchType_, maxResults: 500}, - function(results) { - if (this.cancelled_) { - errorCallback(util.createFileError(FileError.ABORT_ERR)); - return; - } - - if (!results) { - console.error('Drive search encountered an error.'); - errorCallback(util.createFileError( - FileError.INVALID_MODIFICATION_ERR)); - return; - } - - var entries = results.map(function(result) { return result.entry; }); - if (entries.length > 0) - entriesCallback(entries); - successCallback(); - }.bind(this)); -}; - -/** - * This class manages filters and determines a file should be shown or not. - * When filters are changed, a 'changed' event is fired. - * - * @param {MetadataCache} metadataCache Metadata cache service. - * @param {boolean} showHidden If files starting with '.' are shown. - * @constructor - * @extends {cr.EventTarget} - */ -function FileFilter(metadataCache, showHidden) { - /** - * @type {MetadataCache} - * @private - */ - this.metadataCache_ = metadataCache; - - /** - * @type Object.<string, Function> - * @private - */ - this.filters_ = {}; - this.setFilterHidden(!showHidden); - - // Do not show entries marked as 'deleted'. - this.addFilter('deleted', function(entry) { - var internal = this.metadataCache_.getCached(entry, 'internal'); - return !(internal && internal.deleted); - }.bind(this)); -} - -/* - * FileFilter extends cr.EventTarget. - */ -FileFilter.prototype = {__proto__: cr.EventTarget.prototype}; - -/** - * @param {string} name Filter identifier. - * @param {function(Entry)} callback A filter — a function receiving an Entry, - * and returning bool. - */ -FileFilter.prototype.addFilter = function(name, callback) { - this.filters_[name] = callback; - cr.dispatchSimpleEvent(this, 'changed'); -}; - -/** - * @param {string} name Filter identifier. - */ -FileFilter.prototype.removeFilter = function(name) { - delete this.filters_[name]; - cr.dispatchSimpleEvent(this, 'changed'); -}; - -/** - * @param {boolean} value If do not show hidden files. - */ -FileFilter.prototype.setFilterHidden = function(value) { - if (value) { - this.addFilter( - 'hidden', - function(entry) { return entry.name.substr(0, 1) !== '.'; } - ); - } else { - this.removeFilter('hidden'); - } -}; - -/** - * @return {boolean} If the files with names starting with "." are not shown. - */ -FileFilter.prototype.isFilterHiddenOn = function() { - return 'hidden' in this.filters_; -}; - -/** - * @param {Entry} entry File entry. - * @return {boolean} True if the file should be shown, false otherwise. - */ -FileFilter.prototype.filter = function(entry) { - for (var name in this.filters_) { - if (!this.filters_[name](entry)) - return false; - } - return true; -}; - -/** - * A context of DirectoryContents. - * TODO(yoshiki): remove this. crbug.com/224869. - * - * @param {FileFilter} fileFilter The file-filter context. - * @param {MetadataCache} metadataCache Metadata cache service. - * @constructor - */ -function FileListContext(fileFilter, metadataCache) { - /** - * @type {cr.ui.ArrayDataModel} - */ - this.fileList = new cr.ui.ArrayDataModel([]); - - /** - * @type {MetadataCache} - */ - this.metadataCache = metadataCache; - - /** - * @type {FileFilter} - */ - this.fileFilter = fileFilter; -} - -/** - * This class is responsible for scanning directory (or search results), - * and filling the fileList. Different descendants handle various types of - * directory contents shown: basic directory, drive search results, local search - * results. - * TODO(hidehiko): Remove EventTarget from this. - * - * @param {FileListContext} context The file list context. - * @param {boolean} isSearch True for search directory contents, otherwise - * false. - * @param {DirectoryEntry} directoryEntry The entry of the current directory. - * @param {DirectoryEntry} lastNonSearchDirectoryEntry The entry of the last - * non-search directory. - * @param {function():ContentScanner} scannerFactory The factory to create - * ContentScanner instance. - * @constructor - * @extends {cr.EventTarget} - */ -function DirectoryContents(context, isSearch, directoryEntry, - lastNonSearchDirectoryEntry, - scannerFactory) { - this.context_ = context; - this.fileList_ = context.fileList; - - this.isSearch_ = isSearch; - this.directoryEntry_ = directoryEntry; - this.lastNonSearchDirectoryEntry_ = lastNonSearchDirectoryEntry; - - this.scannerFactory_ = scannerFactory; - this.scanner_ = null; - this.prefetchMetadataQueue_ = new AsyncUtil.Queue(); - this.scanCancelled_ = false; -} - -/** - * DirectoryContents extends cr.EventTarget. - */ -DirectoryContents.prototype.__proto__ = cr.EventTarget.prototype; - -/** - * Create the copy of the object, but without scan started. - * @return {DirectoryContents} Object copy. - */ -DirectoryContents.prototype.clone = function() { - return new DirectoryContents( - this.context_, this.isSearch_, this.directoryEntry_, - this.lastNonSearchDirectoryEntry_, this.scannerFactory_); -}; - -/** - * Use a given fileList instead of the fileList from the context. - * @param {Array|cr.ui.ArrayDataModel} fileList The new file list. - */ -DirectoryContents.prototype.setFileList = function(fileList) { - if (fileList instanceof cr.ui.ArrayDataModel) - this.fileList_ = fileList; - else - this.fileList_ = new cr.ui.ArrayDataModel(fileList); - this.context_.metadataCache.setCacheSize(this.fileList_.length); -}; - -/** - * Use the filelist from the context and replace its contents with the entries - * from the current fileList. - */ -DirectoryContents.prototype.replaceContextFileList = function() { - if (this.context_.fileList !== this.fileList_) { - var spliceArgs = this.fileList_.slice(); - var fileList = this.context_.fileList; - spliceArgs.unshift(0, fileList.length); - fileList.splice.apply(fileList, spliceArgs); - this.fileList_ = fileList; - this.context_.metadataCache.setCacheSize(this.fileList_.length); - } -}; - -/** - * @return {boolean} If the scan is active. - */ -DirectoryContents.prototype.isScanning = function() { - return this.scanner_ || this.prefetchMetadataQueue_.isRunning(); -}; - -/** - * @return {boolean} True if search results (drive or local). - */ -DirectoryContents.prototype.isSearch = function() { - return this.isSearch_; -}; - -/** - * @return {DirectoryEntry} A DirectoryEntry for current directory. In case of - * search -- the top directory from which search is run. - */ -DirectoryContents.prototype.getDirectoryEntry = function() { - return this.directoryEntry_; -}; - -/** - * @return {DirectoryEntry} A DirectoryEntry for the last non search contents. - */ -DirectoryContents.prototype.getLastNonSearchDirectoryEntry = function() { - return this.lastNonSearchDirectoryEntry_; -}; - -/** - * Start directory scan/search operation. Either 'scan-completed' or - * 'scan-failed' event will be fired upon completion. - */ -DirectoryContents.prototype.scan = function() { - // TODO(hidehiko,mtomasz): this scan method must be called at most once. - // Remove such a limitation. - this.scanner_ = this.scannerFactory_(); - this.scanner_.scan(this.onNewEntries_.bind(this), - this.onScanCompleted_.bind(this), - this.onScanError_.bind(this)); -}; - -/** - * Cancels the running scan. - */ -DirectoryContents.prototype.cancelScan = function() { - if (this.scanCancelled_) - return; - this.scanCancelled_ = true; - if (this.scanner_) - this.scanner_.cancel(); - - this.prefetchMetadataQueue_.cancel(); - cr.dispatchSimpleEvent(this, 'scan-cancelled'); -}; - -/** - * Called when the scanning by scanner_ is done. - * @private - */ -DirectoryContents.prototype.onScanCompleted_ = function() { - this.scanner_ = null; - if (this.scanCancelled_) - return; - - this.prefetchMetadataQueue_.run(function(callback) { - // Call callback first, so isScanning() returns false in the event handlers. - callback(); - cr.dispatchSimpleEvent(this, 'scan-completed'); - }.bind(this)); -}; - -/** - * Called in case scan has failed. Should send the event. - * @private - */ -DirectoryContents.prototype.onScanError_ = function() { - this.scanner_ = null; - if (this.scanCancelled_) - return; - - this.prefetchMetadataQueue_.run(function(callback) { - // Call callback first, so isScanning() returns false in the event handlers. - callback(); - cr.dispatchSimpleEvent(this, 'scan-failed'); - }.bind(this)); -}; - -/** - * Called when some chunk of entries are read by scanner. - * @param {Array.<Entry>} entries The list of the scanned entries. - * @private - */ -DirectoryContents.prototype.onNewEntries_ = function(entries) { - if (this.scanCancelled_) - return; - - var entriesFiltered = [].filter.call( - entries, this.context_.fileFilter.filter.bind(this.context_.fileFilter)); - - // Update the filelist without waiting the metadata. - this.fileList_.push.apply(this.fileList_, entriesFiltered); - cr.dispatchSimpleEvent(this, 'scan-updated'); - - this.context_.metadataCache.setCacheSize(this.fileList_.length); - - // Because the prefetchMetadata can be slow, throttling by splitting entries - // into smaller chunks to reduce UI latency. - // TODO(hidehiko,mtomasz): This should be handled in MetadataCache. - var MAX_CHUNK_SIZE = 50; - for (var i = 0; i < entriesFiltered.length; i += MAX_CHUNK_SIZE) { - var chunk = entriesFiltered.slice(i, i + MAX_CHUNK_SIZE); - this.prefetchMetadataQueue_.run(function(chunk, callback) { - this.prefetchMetadata(chunk, function() { - if (this.scanCancelled_) { - // Do nothing if the scanning is cancelled. - callback(); - return; - } - - // TODO(yoshiki): Here we should fire the update event of changed - // items. Currently we have a method this.fileList_.updateIndex() to - // fire an event, but this method takes only 1 argument and invokes sort - // one by one. It is obviously time wasting. Instead, we call sort - // directory. - // In future, we should implement a good method like updateIndexes and - // use it here. - var status = this.fileList_.sortStatus; - this.fileList_.sort(status.field, status.direction); - - cr.dispatchSimpleEvent(this, 'scan-updated'); - callback(); - }.bind(this)); - }.bind(this, chunk)); - } -}; - -/** - * @param {Array.<Entry>} entries Files. - * @param {function(Object)} callback Callback on done. - */ -DirectoryContents.prototype.prefetchMetadata = function(entries, callback) { - this.context_.metadataCache.get(entries, 'filesystem', callback); -}; - -/** - * @param {Array.<Entry>} entries Files. - * @param {function(Object)} callback Callback on done. - */ -DirectoryContents.prototype.reloadMetadata = function(entries, callback) { - this.context_.metadataCache.clear(entries, '*'); - this.context_.metadataCache.get(entries, 'filesystem', callback); -}; - -/** - * @param {string} name Directory name. - * @param {function(DirectoryEntry)} successCallback Called on success. - * @param {function(FileError)} errorCallback On error. - */ -DirectoryContents.prototype.createDirectory = function( - name, successCallback, errorCallback) { - // TODO(hidehiko): createDirectory should not be the part of - // DirectoryContent. - if (this.isSearch_ || !this.directoryEntry_) { - errorCallback(util.createFileError(FileError.INVALID_MODIFICATION_ERR)); - return; - } - - var onSuccess = function(newEntry) { - this.reloadMetadata([newEntry], function() { - successCallback(newEntry); - }); - }; - - this.directoryEntry_.getDirectory(name, {create: true, exclusive: true}, - onSuccess.bind(this), errorCallback); -}; - -/** - * Creates a DirectoryContents instance to show entries in a directory. - * - * @param {FileListContext} context File list context. - * @param {DirectoryEntry} directoryEntry The current directory entry. - * @return {DirectoryContents} Created DirectoryContents instance. - */ -DirectoryContents.createForDirectory = function(context, directoryEntry) { - return new DirectoryContents( - context, - false, // Non search. - directoryEntry, - directoryEntry, - function() { - return new DirectoryContentScanner(directoryEntry); - }); -}; - -/** - * Creates a DirectoryContents instance to show the result of the search on - * Drive File System. - * - * @param {FileListContext} context File list context. - * @param {DirectoryEntry} directoryEntry The current directory entry. - * @param {DirectoryEntry} previousDirectoryEntry The DirectoryEntry that was - * current before the search. - * @param {string} query Search query. - * @return {DirectoryContents} Created DirectoryContents instance. - */ -DirectoryContents.createForDriveSearch = function( - context, directoryEntry, previousDirectoryEntry, query) { - return new DirectoryContents( - context, - true, // Search. - directoryEntry, - previousDirectoryEntry, - function() { - return new DriveSearchContentScanner(query); - }); -}; - -/** - * Creates a DirectoryContents instance to show the result of the search on - * Local File System. - * - * @param {FileListContext} context File list context. - * @param {DirectoryEntry} directoryEntry The current directory entry. - * @param {string} query Search query. - * @return {DirectoryContents} Created DirectoryContents instance. - */ -DirectoryContents.createForLocalSearch = function( - context, directoryEntry, query) { - return new DirectoryContents( - context, - true, // Search. - directoryEntry, - directoryEntry, - function() { - return new LocalSearchContentScanner(directoryEntry, query); - }); -}; - -/** - * Creates a DirectoryContents instance to show the result of metadata search - * on Drive File System. - * - * @param {FileListContext} context File list context. - * @param {DirectoryEntry} fakeDirectoryEntry Fake directory entry representing - * the set of result entries. This serves as a top directory for the - * search. - * @param {DirectoryEntry} driveDirectoryEntry Directory for the actual drive. - * @param {string} query Search query. - * @param {DriveMetadataSearchContentScanner.SearchType} searchType The type of - * the search. The scanner will restricts the entries based on the given - * type. - * @return {DirectoryContents} Created DirectoryContents instance. - */ -DirectoryContents.createForDriveMetadataSearch = function( - context, fakeDirectoryEntry, driveDirectoryEntry, query, searchType) { - return new DirectoryContents( - context, - true, // Search - fakeDirectoryEntry, - driveDirectoryEntry, - function() { - return new DriveMetadataSearchContentScanner(query, searchType); - }); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/directory_model.js b/chromium/chrome/browser/resources/file_manager/foreground/js/directory_model.js deleted file mode 100644 index fde41e8c321..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/directory_model.js +++ /dev/null @@ -1,1186 +0,0 @@ -// 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. - -'use strict'; - -// If directory files changes too often, don't rescan directory more than once -// per specified interval -var SIMULTANEOUS_RESCAN_INTERVAL = 1000; -// Used for operations that require almost instant rescan. -var SHORT_RESCAN_INTERVAL = 100; - -/** - * Data model of the file manager. - * - * @param {boolean} singleSelection True if only one file could be selected - * at the time. - * @param {FileFilter} fileFilter Instance of FileFilter. - * @param {FileWatcher} fileWatcher Instance of FileWatcher. - * @param {MetadataCache} metadataCache The metadata cache service. - * @param {VolumeManagerWrapper} volumeManager The volume manager. - * @constructor - */ -function DirectoryModel(singleSelection, fileFilter, fileWatcher, - metadataCache, volumeManager) { - this.fileListSelection_ = singleSelection ? - new cr.ui.ListSingleSelectionModel() : new cr.ui.ListSelectionModel(); - - this.runningScan_ = null; - this.pendingScan_ = null; - this.rescanTime_ = null; - this.scanFailures_ = 0; - this.changeDirectorySequence_ = 0; - - this.fileFilter_ = fileFilter; - this.fileFilter_.addEventListener('changed', - this.onFilterChanged_.bind(this)); - - this.currentFileListContext_ = new FileListContext( - fileFilter, metadataCache); - this.currentDirContents_ = - DirectoryContents.createForDirectory(this.currentFileListContext_, null); - - this.volumeManager_ = volumeManager; - this.volumeManager_.volumeInfoList.addEventListener( - 'splice', this.onVolumeInfoListUpdated_.bind(this)); - - this.fileWatcher_ = fileWatcher; - this.fileWatcher_.addEventListener( - 'watcher-directory-changed', - this.onWatcherDirectoryChanged_.bind(this)); -} - -/** - * Fake entry to be used in currentDirEntry_ when current directory is - * unmounted DRIVE. TODO(haruki): Support "drive/root" and "drive/other". - * @type {Object} - * @const - * @private - */ -DirectoryModel.fakeDriveEntry_ = { - fullPath: RootDirectory.DRIVE + '/' + DriveSubRootDirectory.ROOT, - isDirectory: true, - rootType: RootType.DRIVE -}; - -/** - * Fake entry representing a psuedo directory, which contains Drive files - * available offline. This entry works as a trigger to start a search for - * offline files. - * @type {Object} - * @const - * @private - */ -DirectoryModel.fakeDriveOfflineEntry_ = { - fullPath: RootDirectory.DRIVE_OFFLINE, - isDirectory: true, - rootType: RootType.DRIVE_OFFLINE -}; - -/** - * Fake entry representing a pseudo directory, which contains shared-with-me - * Drive files. This entry works as a trigger to start a search for - * shared-with-me files. - * @type {Object} - * @const - * @private - */ -DirectoryModel.fakeDriveSharedWithMeEntry_ = { - fullPath: RootDirectory.DRIVE_SHARED_WITH_ME, - isDirectory: true, - rootType: RootType.DRIVE_SHARED_WITH_ME -}; - -/** - * Fake entry representing a pseudo directory, which contains Drive files - * accessed recently. This entry works as a trigger to start a metadata search - * implemented as DirectoryContentsDriveRecent. - * DirectoryModel is responsible to start the search when the UI tries to open - * this fake entry (e.g. changeDirectory()). - * @type {Object} - * @const - * @private - */ -DirectoryModel.fakeDriveRecentEntry_ = { - fullPath: RootDirectory.DRIVE_RECENT, - isDirectory: true, - rootType: RootType.DRIVE_RECENT -}; - -/** - * List of fake entries for special searches. - * - * @type {Array.<Object>} - * @const - */ -DirectoryModel.FAKE_DRIVE_SPECIAL_SEARCH_ENTRIES = [ - DirectoryModel.fakeDriveSharedWithMeEntry_, - DirectoryModel.fakeDriveRecentEntry_, - DirectoryModel.fakeDriveOfflineEntry_ -]; - -/** - * DirectoryModel extends cr.EventTarget. - */ -DirectoryModel.prototype.__proto__ = cr.EventTarget.prototype; - -/** - * Disposes the directory model by removing file watchers. - */ -DirectoryModel.prototype.dispose = function() { - this.fileWatcher_.dispose(); -}; - -/** - * @return {cr.ui.ArrayDataModel} Files in the current directory. - */ -DirectoryModel.prototype.getFileList = function() { - return this.currentFileListContext_.fileList; -}; - -/** - * Sort the file list. - * @param {string} sortField Sort field. - * @param {string} sortDirection "asc" or "desc". - */ -DirectoryModel.prototype.sortFileList = function(sortField, sortDirection) { - this.getFileList().sort(sortField, sortDirection); -}; - -/** - * @return {cr.ui.ListSelectionModel|cr.ui.ListSingleSelectionModel} Selection - * in the fileList. - */ -DirectoryModel.prototype.getFileListSelection = function() { - return this.fileListSelection_; -}; - -/** - * @return {RootType} Root type of current root. - */ -DirectoryModel.prototype.getCurrentRootType = function() { - var entry = this.currentDirContents_.getDirectoryEntry(); - return PathUtil.getRootType(entry ? entry.fullPath : ''); -}; - -/** - * @return {string} Root path. - */ -DirectoryModel.prototype.getCurrentRootPath = function() { - var entry = this.currentDirContents_.getDirectoryEntry(); - return entry ? PathUtil.getRootPath(entry.fullPath) : ''; -}; - -/** - * @return {string} Filesystem URL representing the mountpoint for the current - * contents. - */ -DirectoryModel.prototype.getCurrentMountPointUrl = function() { - var rootPath = this.getCurrentRootPath(); - // Special search roots are just showing a search results from DRIVE. - if (PathUtil.getRootType(rootPath) == RootType.DRIVE || - PathUtil.isSpecialSearchRoot(rootPath)) - return util.makeFilesystemUrl(RootDirectory.DRIVE); - - return util.makeFilesystemUrl(rootPath); -}; - -/** - * @return {boolean} on True if offline. - */ -DirectoryModel.prototype.isDriveOffline = function() { - var connection = this.volumeManager_.getDriveConnectionState(); - return connection.type == util.DriveConnectionType.OFFLINE; -}; - -/** - * TODO(haruki): This actually checks the current root. Fix the method name and - * related code. - * @return {boolean} True if the root for the current directory is read only. - */ -DirectoryModel.prototype.isReadOnly = function() { - return this.isPathReadOnly(this.getCurrentRootPath()); -}; - -/** - * @return {boolean} True if the a scan is active. - */ -DirectoryModel.prototype.isScanning = function() { - return this.currentDirContents_.isScanning(); -}; - -/** - * @return {boolean} True if search is in progress. - */ -DirectoryModel.prototype.isSearching = function() { - return this.currentDirContents_.isSearch(); -}; - -/** - * @param {string} path Path to check. - * @return {boolean} True if the |path| is read only. - */ -DirectoryModel.prototype.isPathReadOnly = function(path) { - // TODO(hidehiko): Migrate this into VolumeInfo. - switch (PathUtil.getRootType(path)) { - case RootType.REMOVABLE: - var volumeInfo = this.volumeManager_.getVolumeInfo(path); - // Returns true if the volume is actually read only, or if an error - // is found during the mounting. - // TODO(hidehiko): Remove "error" check here, by removing error'ed volume - // info from VolumeManager. - return volumeInfo && (volumeInfo.isReadOnly || !!volumeInfo.error); - case RootType.ARCHIVE: - return true; - case RootType.DOWNLOADS: - return false; - case RootType.DRIVE: - // TODO(haruki): Maybe add DRIVE_OFFLINE as well to allow renaming in the - // offline tab. - return this.isDriveOffline(); - default: - return true; - } -}; - -/** - * Updates the selection by using the updateFunc and publish the change event. - * If updateFunc returns true, it force to dispatch the change event even if the - * selection index is not changed. - * - * @param {cr.ui.ListSelectionModel|cr.ui.ListSingleSelectionModel} selection - * Selection to be updated. - * @param {function(): boolean} updateFunc Function updating the selection. - * @private - */ -DirectoryModel.prototype.updateSelectionAndPublishEvent_ = - function(selection, updateFunc) { - // Begin change. - selection.beginChange(); - - // If dispatchNeeded is true, we should ensure the change event is - // dispatched. - var dispatchNeeded = updateFunc(); - - // Check if the change event is dispatched in the endChange function - // or not. - var eventDispatched = function() { dispatchNeeded = false; }; - selection.addEventListener('change', eventDispatched); - selection.endChange(); - selection.removeEventListener('change', eventDispatched); - - // If the change event have been already dispatched, dispatchNeeded is false. - if (dispatchNeeded) { - var event = new Event('change'); - // The selection status (selected or not) is not changed because - // this event is caused by the change of selected item. - event.changes = []; - selection.dispatchEvent(event); - } -}; - -/** - * Invoked when a change in the directory is detected by the watcher. - * @private - */ -DirectoryModel.prototype.onWatcherDirectoryChanged_ = function() { - this.rescanSoon(); -}; - -/** - * Invoked when filters are changed. - * @private - */ -DirectoryModel.prototype.onFilterChanged_ = function() { - this.rescanSoon(); -}; - -/** - * Returns the filter. - * @return {FileFilter} The file filter. - */ -DirectoryModel.prototype.getFileFilter = function() { - return this.fileFilter_; -}; - -/** - * @return {DirectoryEntry} Current directory. - */ -DirectoryModel.prototype.getCurrentDirEntry = function() { - return this.currentDirContents_.getDirectoryEntry(); -}; - -/** - * @return {string} URL of the current directory. or null if unavailable. - */ -DirectoryModel.prototype.getCurrentDirectoryURL = function() { - var entry = this.currentDirContents_.getDirectoryEntry(); - if (!entry) - return null; - if (entry === DirectoryModel.fakeDriveOfflineEntry_) - return util.makeFilesystemUrl(entry.fullPath); - return entry.toURL(); -}; - -/** - * @return {string} Path for the current directory, or empty string if the - * current directory is not yet set. - */ -DirectoryModel.prototype.getCurrentDirPath = function() { - var entry = this.currentDirContents_.getDirectoryEntry(); - return entry ? entry.fullPath : ''; -}; - -/** - * @return {Array.<string>} File paths of selected files. - * @private - */ -DirectoryModel.prototype.getSelectedPaths_ = function() { - var indexes = this.fileListSelection_.selectedIndexes; - var fileList = this.getFileList(); - if (fileList) { - return indexes.map(function(i) { - return fileList.item(i).fullPath; - }); - } - return []; -}; - -/** - * @param {Array.<string>} value List of file paths of selected files. - * @private - */ -DirectoryModel.prototype.setSelectedPaths_ = function(value) { - var indexes = []; - var fileList = this.getFileList(); - - var safeKey = function(key) { - // The transformation must: - // 1. Never generate a reserved name ('__proto__') - // 2. Keep different keys different. - return '#' + key; - }; - - var hash = {}; - - for (var i = 0; i < value.length; i++) - hash[safeKey(value[i])] = 1; - - for (var i = 0; i < fileList.length; i++) { - if (hash.hasOwnProperty(safeKey(fileList.item(i).fullPath))) - indexes.push(i); - } - this.fileListSelection_.selectedIndexes = indexes; -}; - -/** - * @return {string} Lead item file path. - * @private - */ -DirectoryModel.prototype.getLeadPath_ = function() { - var index = this.fileListSelection_.leadIndex; - return index >= 0 && this.getFileList().item(index).fullPath; -}; - -/** - * @param {string} value The name of new lead index. - * @private - */ -DirectoryModel.prototype.setLeadPath_ = function(value) { - var fileList = this.getFileList(); - for (var i = 0; i < fileList.length; i++) { - if (fileList.item(i).fullPath === value) { - this.fileListSelection_.leadIndex = i; - return; - } - } -}; - -/** - * Schedule rescan with short delay. - */ -DirectoryModel.prototype.rescanSoon = function() { - this.scheduleRescan(SHORT_RESCAN_INTERVAL); -}; - -/** - * Schedule rescan with delay. Designed to handle directory change - * notification. - */ -DirectoryModel.prototype.rescanLater = function() { - this.scheduleRescan(SIMULTANEOUS_RESCAN_INTERVAL); -}; - -/** - * Schedule rescan with delay. If another rescan has been scheduled does - * nothing. File operation may cause a few notifications what should cause - * a single refresh. - * @param {number} delay Delay in ms after which the rescan will be performed. - */ -DirectoryModel.prototype.scheduleRescan = function(delay) { - if (this.rescanTime_) { - if (this.rescanTime_ <= Date.now() + delay) - return; - clearTimeout(this.rescanTimeoutId_); - } - - this.rescanTime_ = Date.now() + delay; - this.rescanTimeoutId_ = setTimeout(this.rescan.bind(this), delay); -}; - -/** - * Cancel a rescan on timeout if it is scheduled. - * @private - */ -DirectoryModel.prototype.clearRescanTimeout_ = function() { - this.rescanTime_ = null; - if (this.rescanTimeoutId_) { - clearTimeout(this.rescanTimeoutId_); - this.rescanTimeoutId_ = null; - } -}; - -/** - * Rescan current directory. May be called indirectly through rescanLater or - * directly in order to reflect user action. Will first cache all the directory - * contents in an array, then seamlessly substitute the fileList contents, - * preserving the select element etc. - * - * This should be to scan the contents of current directory (or search). - */ -DirectoryModel.prototype.rescan = function() { - this.clearRescanTimeout_(); - if (this.runningScan_) { - this.pendingRescan_ = true; - return; - } - - var dirContents = this.currentDirContents_.clone(); - dirContents.setFileList([]); - - var successCallback = (function() { - this.replaceDirectoryContents_(dirContents); - cr.dispatchSimpleEvent(this, 'rescan-completed'); - }).bind(this); - - this.scan_(dirContents, - successCallback, function() {}, function() {}, function() {}); -}; - -/** - * Run scan on the current DirectoryContents. The active fileList is cleared and - * the entries are added directly. - * - * This should be used when changing directory or initiating a new search. - * - * @param {DirectoryContentes} newDirContents New DirectoryContents instance to - * replace currentDirContents_. - * @param {function()=} opt_callback Called on success. - * @private - */ -DirectoryModel.prototype.clearAndScan_ = function(newDirContents, - opt_callback) { - if (this.currentDirContents_.isScanning()) - this.currentDirContents_.cancelScan(); - this.currentDirContents_ = newDirContents; - this.clearRescanTimeout_(); - - if (this.pendingScan_) - this.pendingScan_ = false; - - if (this.runningScan_) { - if (this.runningScan_.isScanning()) - this.runningScan_.cancelScan(); - this.runningScan_ = null; - } - - var onDone = function() { - cr.dispatchSimpleEvent(this, 'scan-completed'); - if (opt_callback) - opt_callback(); - }.bind(this); - - var onFailed = function() { - cr.dispatchSimpleEvent(this, 'scan-failed'); - }.bind(this); - - var onUpdated = function() { - cr.dispatchSimpleEvent(this, 'scan-updated'); - }.bind(this); - - var onCancelled = function() { - cr.dispatchSimpleEvent(this, 'scan-cancelled'); - }.bind(this); - - // Clear the table, and start scanning. - cr.dispatchSimpleEvent(this, 'scan-started'); - var fileList = this.getFileList(); - fileList.splice(0, fileList.length); - this.scan_(this.currentDirContents_, - onDone, onFailed, onUpdated, onCancelled); -}; - -/** - * Perform a directory contents scan. Should be called only from rescan() and - * clearAndScan_(). - * - * @param {DirectoryContents} dirContents DirectoryContents instance on which - * the scan will be run. - * @param {function()} successCallback Callback on success. - * @param {function()} failureCallback Callback on failure. - * @param {function()} updatedCallback Callback on update. Only on the last - * update, {@code successCallback} is called instead of this. - * @param {function()} cancelledCallback Callback on cancel. - * @private - */ -DirectoryModel.prototype.scan_ = function( - dirContents, - successCallback, failureCallback, updatedCallback, cancelledCallback) { - var self = this; - - /** - * Runs pending scan if there is one. - * - * @return {boolean} Did pending scan exist. - */ - var maybeRunPendingRescan = function() { - if (this.pendingRescan_) { - this.rescanSoon(); - this.pendingRescan_ = false; - return true; - } - return false; - }.bind(this); - - var onSuccess = function() { - // Record metric for Downloads directory. - if (!dirContents.isSearch()) { - var locationInfo = - this.volumeManager_.getLocationInfo(dirContents.getDirectoryEntry()); - if (locationInfo.volumeInfo.volumeType === util.VolumeType.DOWNLOADS && - locationInfo.isRootEntry) { - metrics.recordMediumCount('DownloadsCount', - dirContents.fileList_.length); - } - } - - this.runningScan_ = null; - successCallback(); - this.scanFailures_ = 0; - maybeRunPendingRescan(); - }.bind(this); - - var onFailure = function() { - this.runningScan_ = null; - this.scanFailures_++; - failureCallback(); - - if (maybeRunPendingRescan()) - return; - - if (this.scanFailures_ <= 1) - this.rescanLater(); - }.bind(this); - - this.runningScan_ = dirContents; - - dirContents.addEventListener('scan-completed', onSuccess); - dirContents.addEventListener('scan-updated', updatedCallback); - dirContents.addEventListener('scan-failed', onFailure); - dirContents.addEventListener('scan-cancelled', cancelledCallback); - dirContents.scan(); -}; - -/** - * @param {DirectoryContents} dirContents DirectoryContents instance. - * @private - */ -DirectoryModel.prototype.replaceDirectoryContents_ = function(dirContents) { - cr.dispatchSimpleEvent(this, 'begin-update-files'); - this.updateSelectionAndPublishEvent_(this.fileListSelection_, function() { - var selectedPaths = this.getSelectedPaths_(); - var selectedIndices = this.fileListSelection_.selectedIndexes; - - // Restore leadIndex in case leadName no longer exists. - var leadIndex = this.fileListSelection_.leadIndex; - var leadPath = this.getLeadPath_(); - - this.currentDirContents_ = dirContents; - dirContents.replaceContextFileList(); - - this.setSelectedPaths_(selectedPaths); - this.fileListSelection_.leadIndex = leadIndex; - this.setLeadPath_(leadPath); - - // If nothing is selected after update, then select file next to the - // latest selection - var forceChangeEvent = false; - if (this.fileListSelection_.selectedIndexes.length == 0 && - selectedIndices.length != 0) { - var maxIdx = Math.max.apply(null, selectedIndices); - this.selectIndex(Math.min(maxIdx - selectedIndices.length + 2, - this.getFileList().length) - 1); - forceChangeEvent = true; - } - return forceChangeEvent; - }.bind(this)); - - cr.dispatchSimpleEvent(this, 'end-update-files'); -}; - -/** - * Callback when an entry is changed. - * @param {util.EntryChangedKind} kind How the entry is changed. - * @param {Entry} entry The changed entry. - */ -DirectoryModel.prototype.onEntryChanged = function(kind, entry) { - // TODO(hidehiko): We should update directory model even the search result - // is shown. - var rootType = this.getCurrentRootType(); - if ((rootType === RootType.DRIVE || - rootType === RootType.DRIVE_SHARED_WITH_ME || - rootType === RootType.DRIVE_RECENT || - rootType === RootType.DRIVE_OFFLINE) && - this.isSearching()) - return; - - if (kind == util.EntryChangedKind.CREATED) { - entry.getParent(function(parentEntry) { - if (this.getCurrentDirEntry().fullPath != parentEntry.fullPath) { - // Do nothing if current directory changed during async operations. - return; - } - this.currentDirContents_.prefetchMetadata([entry], function() { - if (this.getCurrentDirEntry().fullPath != parentEntry.fullPath) { - // Do nothing if current directory changed during async operations. - return; - } - - var index = this.findIndexByEntry_(entry); - if (index >= 0) - this.getFileList().splice(index, 1, entry); - else - this.getFileList().push(entry); - }.bind(this)); - }.bind(this)); - } else { - // This is the delete event. - var index = this.findIndexByEntry_(entry); - if (index >= 0) - this.getFileList().splice(index, 1); - } -}; - -/** - * @param {Entry} entry The entry to be searched. - * @return {number} The index in the fileList, or -1 if not found. - * @private - */ -DirectoryModel.prototype.findIndexByEntry_ = function(entry) { - var fileList = this.getFileList(); - for (var i = 0; i < fileList.length; i++) { - if (util.isSameEntry(fileList.item(i), entry)) - return i; - } - return -1; -}; - -/** - * Called when rename is done successfully. - * Note: conceptually, DirectoryModel should work without this, because entries - * can be renamed by other systems anytime and Files.app should reflect it - * correctly. - * TODO(hidehiko): investigate more background, and remove this if possible. - * - * @param {Entry} oldEntry The old entry. - * @param {Entry} newEntry The new entry. - * @param {function()} opt_callback Called on completion. - */ -DirectoryModel.prototype.onRenameEntry = function( - oldEntry, newEntry, opt_callback) { - this.currentDirContents_.prefetchMetadata([newEntry], function() { - // If the current directory is the old entry, then quietly change to the - // new one. - if (util.isSameEntry(oldEntry, this.getCurrentDirEntry())) - this.changeDirectory(newEntry.fullPath); - - // Look for the old entry. - // If the entry doesn't exist in the list, it has been updated from - // outside (probably by directory rescan). - var index = this.findIndexByEntry_(oldEntry); - if (index >= 0) { - // Update the content list and selection status. - var wasSelected = this.fileListSelection_.getIndexSelected(index); - this.updateSelectionAndPublishEvent_(this.fileListSelection_, function() { - this.fileListSelection_.setIndexSelected(index, false); - this.getFileList().splice(index, 1, newEntry); - if (wasSelected) { - // We re-search the index, because splice may trigger sorting so that - // index may be stale. - this.fileListSelection_.setIndexSelected( - this.findIndexByEntry_(newEntry), true); - } - return true; - }.bind(this)); - } - - // Run callback, finally. - if (opt_callback) - opt_callback(); - }.bind(this)); -}; - -/** - * Creates directory and updates the file list. - * - * @param {string} name Directory name. - * @param {function(DirectoryEntry)} successCallback Callback on success. - * @param {function(FileError)} errorCallback Callback on failure. - */ -DirectoryModel.prototype.createDirectory = function(name, successCallback, - errorCallback) { - var entry = this.getCurrentDirEntry(); - if (!entry) { - errorCallback(util.createFileError(FileError.INVALID_MODIFICATION_ERR)); - return; - } - - var tracker = this.createDirectoryChangeTracker(); - tracker.start(); - - var onSuccess = function(newEntry) { - // Do not change anything or call the callback if current - // directory changed. - tracker.stop(); - if (tracker.hasChanged) - return; - - var existing = this.getFileList().slice().filter( - function(e) {return e.name == name;}); - - if (existing.length) { - this.selectEntry(newEntry); - successCallback(existing[0]); - } else { - this.fileListSelection_.beginChange(); - this.getFileList().splice(0, 0, newEntry); - this.selectEntry(newEntry); - this.fileListSelection_.endChange(); - successCallback(newEntry); - } - }; - - this.currentDirContents_.createDirectory(name, onSuccess.bind(this), - errorCallback); -}; - -/** - * Changes directory. Causes 'directory-change' event. - * - * The directory will not be changed, if another request is started before it is - * finished. The error callback will not be called, and the event for the first - * request will not be invoked. - * - * @param {string} path New current directory path. - * @param {function(FileError)=} opt_errorCallback Executed if the change - * directory failed. - */ -DirectoryModel.prototype.changeDirectory = function(path, opt_errorCallback) { - this.changeDirectorySequence_++; - - if (PathUtil.isSpecialSearchRoot(path)) { - this.specialSearch(path, ''); - return; - } - - this.resolveDirectory( - path, - function(sequence, directoryEntry) { - if (this.changeDirectorySequence_ === sequence) - this.changeDirectoryEntry(directoryEntry); - }.bind(this, this.changeDirectorySequence_), - function(error) { - console.error('Error changing directory to ' + path + ': ', error); - if (opt_errorCallback) - opt_errorCallback(error); - }); -}; - -/** - * Resolves absolute directory path. Handles Drive stub. If the drive is - * mounting, callbacks will be called after the mount is completed. - * - * @param {string} path Path to the directory. - * @param {function(DirectoryEntry)} successCallback Success callback. - * @param {function(FileError)} errorCallback Error callback. - */ -DirectoryModel.prototype.resolveDirectory = function( - path, successCallback, errorCallback) { - if (PathUtil.getRootType(path) == RootType.DRIVE) { - if (!this.volumeManager_.getVolumeInfo(RootDirectory.DRIVE)) { - errorCallback(util.createFileError(FileError.NOT_FOUND_ERR)); - return; - } - } - - var onError = function(error) { - // Handle the special case, when in offline mode, and there are no cached - // contents on the C++ side. In such case, let's display the stub. - // The INVALID_STATE_ERR error code is returned from the drive filesystem - // in such situation. - // - // TODO(mtomasz, hashimoto): Consider rewriting this logic. - // crbug.com/253464. - if (PathUtil.getRootType(path) == RootType.DRIVE && - error.code == FileError.INVALID_STATE_ERR) { - successCallback(DirectoryModel.fakeDriveEntry_); - return; - } - errorCallback(error); - }.bind(this); - - // TODO(mtomasz): Use Entry instead of a path. - this.volumeManager_.resolveAbsolutePath( - path, - function(entry) { - if (entry.isFile) { - onError(util.createFileError(FileError.TYPE_MISMATCH_ERR)); - return; - } - successCallback(entry); - }, - onError); -}; - -/** - * @param {DirectoryEntry} dirEntry The absolute path to the new directory. - * @param {function()=} opt_callback Executed if the directory loads - * successfully. - * @private - */ -DirectoryModel.prototype.changeDirectoryEntrySilent_ = function(dirEntry, - opt_callback) { - var onScanComplete = function() { - if (opt_callback) - opt_callback(); - // For tests that open the dialog to empty directories, everything - // is loaded at this point. - chrome.test.sendMessage('directory-change-complete'); - }; - this.clearAndScan_( - DirectoryContents.createForDirectory(this.currentFileListContext_, - dirEntry), - onScanComplete.bind(this)); -}; - -/** - * Change the current directory to the directory represented by a - * DirectoryEntry. - * - * Dispatches the 'directory-changed' event when the directory is successfully - * changed. - * - * @param {DirectoryEntry} dirEntry The absolute path to the new directory. - * @param {function()=} opt_callback Executed if the directory loads - * successfully. - */ -DirectoryModel.prototype.changeDirectoryEntry = function( - dirEntry, opt_callback) { - this.fileWatcher_.changeWatchedDirectory(dirEntry, function(sequence) { - if (this.changeDirectorySequence_ !== sequence) - return; - var previous = this.currentDirContents_.getDirectoryEntry(); - this.clearSearch_(); - this.changeDirectoryEntrySilent_(dirEntry, opt_callback); - - var e = new Event('directory-changed'); - e.previousDirEntry = previous; - e.newDirEntry = dirEntry; - this.dispatchEvent(e); - }.bind(this, this.changeDirectorySequence_)); -}; - -/** - * Creates an object which could say whether directory has changed while it has - * been active or not. Designed for long operations that should be cancelled - * if the used change current directory. - * @return {Object} Created object. - */ -DirectoryModel.prototype.createDirectoryChangeTracker = function() { - var tracker = { - dm_: this, - active_: false, - hasChanged: false, - - start: function() { - if (!this.active_) { - this.dm_.addEventListener('directory-changed', - this.onDirectoryChange_); - this.active_ = true; - this.hasChanged = false; - } - }, - - stop: function() { - if (this.active_) { - this.dm_.removeEventListener('directory-changed', - this.onDirectoryChange_); - this.active_ = false; - } - }, - - onDirectoryChange_: function(event) { - tracker.stop(); - tracker.hasChanged = true; - } - }; - return tracker; -}; - -/** - * @param {Entry} entry Entry to be selected. - */ -DirectoryModel.prototype.selectEntry = function(entry) { - var fileList = this.getFileList(); - for (var i = 0; i < fileList.length; i++) { - if (fileList.item(i).toURL() === entry.toURL()) { - this.selectIndex(i); - return; - } - } -}; - -/** - * @param {Array.<string>} entries Array of entries. - */ -DirectoryModel.prototype.selectEntries = function(entries) { - // URLs are needed here, since we are comparing Entries by URLs. - var urls = util.entriesToURLs(entries); - var fileList = this.getFileList(); - this.fileListSelection_.beginChange(); - this.fileListSelection_.unselectAll(); - for (var i = 0; i < fileList.length; i++) { - if (urls.indexOf(fileList.item(i).toURL()) >= 0) - this.fileListSelection_.setIndexSelected(i, true); - } - this.fileListSelection_.endChange(); -}; - -/** - * @param {number} index Index of file. - */ -DirectoryModel.prototype.selectIndex = function(index) { - // this.focusCurrentList_(); - if (index >= this.getFileList().length) - return; - - // If a list bound with the model it will do scrollIndexIntoView(index). - this.fileListSelection_.selectedIndex = index; -}; - -/** - * Called when VolumeInfoList is updated. - * - * @param {Event} event Event of VolumeInfoList's 'splice'. - * @private - */ -DirectoryModel.prototype.onVolumeInfoListUpdated_ = function(event) { - var driveVolume = this.volumeManager_.getVolumeInfo(RootDirectory.DRIVE); - if (driveVolume && !driveVolume.error) { - var currentDirEntry = this.getCurrentDirEntry(); - if (currentDirEntry) { - if (currentDirEntry === DirectoryModel.fakeDriveEntry_) { - // Replace the fake entry by real DirectoryEntry silently. - this.volumeManager_.resolveAbsolutePath( - DirectoryModel.fakeDriveEntry_.fullPath, - function(entry) { - // If the current entry is still fake drive entry, replace it. - if (this.getCurrentDirEntry() === DirectoryModel.fakeDriveEntry_) - this.changeDirectoryEntrySilent_(entry); - }, - function(error) {}); - } else if (PathUtil.isSpecialSearchRoot(currentDirEntry.fullPath)) { - for (var i = 0; i < event.added.length; i++) { - if (event.added[i].volumeType == util.VolumeType.DRIVE) { - // If the Drive volume is newly mounted, rescan it. - this.rescan(); - break; - } - } - } - } - } - - // When the volume where we are is unmounted, fallback to - // DEFAULT_MOUNT_POINT. If current directory path is empty, stop the fallback - // since the current directory is initializing now. - // TODO(mtomasz): DEFAULT_MOUNT_POINT is deprecated. Use VolumeManager:: - // getDefaultVolume() after it is implemented. - if (this.getCurrentDirPath() && - !this.volumeManager_.getVolumeInfo(this.getCurrentDirPath())) - this.changeDirectory(PathUtil.DEFAULT_MOUNT_POINT); -}; - -/** - * Check if the root of the given path is mountable or not. - * - * @param {string} path Path. - * @return {boolean} Return true, if the given path is under mountable root. - * Otherwise, return false. - */ -DirectoryModel.isMountableRoot = function(path) { - var rootType = PathUtil.getRootType(path); - switch (rootType) { - case RootType.DOWNLOADS: - return false; - case RootType.ARCHIVE: - case RootType.REMOVABLE: - case RootType.DRIVE: - return true; - default: - throw new Error('Unknown root type!'); - } -}; - -/** - * Performs search and displays results. The search type is dependent on the - * current directory. If we are currently on drive, server side content search - * over drive mount point. If the current directory is not on the drive, file - * name search over current directory will be performed. - * - * @param {string} query Query that will be searched for. - * @param {function(Event)} onSearchRescan Function that will be called when the - * search directory is rescanned (i.e. search results are displayed). - * @param {function()} onClearSearch Function to be called when search state - * gets cleared. - * TODO(olege): Change callbacks to events. - */ -DirectoryModel.prototype.search = function(query, - onSearchRescan, - onClearSearch) { - query = query.trimLeft(); - - this.clearSearch_(); - - var currentDirEntry = this.getCurrentDirEntry(); - if (!currentDirEntry) { - // Not yet initialized. Do nothing. - return; - } - - if (!query) { - if (this.isSearching()) { - var newDirContents = DirectoryContents.createForDirectory( - this.currentFileListContext_, - this.currentDirContents_.getLastNonSearchDirectoryEntry()); - this.clearAndScan_(newDirContents); - } - return; - } - - this.onSearchCompleted_ = onSearchRescan; - this.onClearSearch_ = onClearSearch; - - this.addEventListener('scan-completed', this.onSearchCompleted_); - - // If we are offline, let's fallback to file name search inside dir. - // A search initiated from directories in Drive or special search results - // should trigger Drive search. - var newDirContents; - if (!this.isDriveOffline() && - PathUtil.isDriveBasedPath(currentDirEntry.fullPath)) { - // Drive search is performed over the whole drive, so pass drive root as - // |directoryEntry|. - newDirContents = DirectoryContents.createForDriveSearch( - this.currentFileListContext_, - currentDirEntry, - this.currentDirContents_.getLastNonSearchDirectoryEntry(), - query); - } else { - newDirContents = DirectoryContents.createForLocalSearch( - this.currentFileListContext_, currentDirEntry, query); - } - this.clearAndScan_(newDirContents); -}; - -/** - * Performs special search and displays results. e.g. Drive files available - * offline, shared-with-me files, recently modified files. - * @param {string} path Path string representing special search. See fake - * entries in PathUtil.RootDirectory. - * @param {string=} opt_query Query string used for the search. - */ -DirectoryModel.prototype.specialSearch = function(path, opt_query) { - var query = opt_query || ''; - - this.clearSearch_(); - - this.onSearchCompleted_ = null; - this.onClearSearch_ = null; - - var onDriveDirectoryResolved = function(sequence, driveRoot) { - if (this.changeDirectorySequence_ !== sequence) - return; - if (!driveRoot || driveRoot == DirectoryModel.fakeDriveEntry_) { - // Drive root not available or not ready. onVolumeInfoListUpdated_() - // handles the rescan if necessary. - driveRoot = null; - } - - var specialSearchType = PathUtil.getRootType(path); - var searchOption; - var dirEntry; - if (specialSearchType == RootType.DRIVE_OFFLINE) { - dirEntry = DirectoryModel.fakeDriveOfflineEntry_; - searchOption = - DriveMetadataSearchContentScanner.SearchType.SEARCH_OFFLINE; - } else if (specialSearchType == RootType.DRIVE_SHARED_WITH_ME) { - dirEntry = DirectoryModel.fakeDriveSharedWithMeEntry_; - searchOption = - DriveMetadataSearchContentScanner.SearchType.SEARCH_SHARED_WITH_ME; - } else if (specialSearchType == RootType.DRIVE_RECENT) { - dirEntry = DirectoryModel.fakeDriveRecentEntry_; - searchOption = - DriveMetadataSearchContentScanner.SearchType.SEARCH_RECENT_FILES; - } else { - // Unknown path. - throw new Error('Unknown path for special search.'); - } - - var newDirContents = DirectoryContents.createForDriveMetadataSearch( - this.currentFileListContext_, - dirEntry, driveRoot, query, searchOption); - var previous = this.currentDirContents_.getDirectoryEntry(); - this.clearAndScan_(newDirContents); - - var e = new Event('directory-changed'); - e.previousDirEntry = previous; - e.newDirEntry = dirEntry; - this.dispatchEvent(e); - }.bind(this, this.changeDirectorySequence_); - - this.resolveDirectory(DirectoryModel.fakeDriveEntry_.fullPath, - onDriveDirectoryResolved /* success */, - function() {} /* failed */); -}; - -/** - * In case the search was active, remove listeners and send notifications on - * its canceling. - * @private - */ -DirectoryModel.prototype.clearSearch_ = function() { - if (!this.isSearching()) - return; - - if (this.onSearchCompleted_) { - this.removeEventListener('scan-completed', this.onSearchCompleted_); - this.onSearchCompleted_ = null; - } - - if (this.onClearSearch_) { - this.onClearSearch_(); - this.onClearSearch_ = null; - } -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/directory_tree.js b/chromium/chrome/browser/resources/file_manager/foreground/js/directory_tree.js deleted file mode 100644 index 5c9de7aa0fe..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/directory_tree.js +++ /dev/null @@ -1,676 +0,0 @@ -// Copyright (c) 2013 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. - -'use strict'; - -//////////////////////////////////////////////////////////////////////////////// -// DirectoryTreeUtil - -/** - * Utility methods. They are intended for use only in this file. - */ -var DirectoryTreeUtil = {}; - -/** - * Generate a list of the directory entries for the top level on the tree. - * @return {Array.<DirectoryEntry>} Entries for the top level on the tree. - */ -DirectoryTreeUtil.generateTopLevelEntries = function() { - var entries = [ - DirectoryModel.fakeDriveEntry_, - DirectoryModel.fakeDriveOfflineEntry_, - DirectoryModel.fakeDriveSharedWithMeEntry_, - DirectoryModel.fakeDriveRecentEntry_, - ]; - - for (var i = 0; i < entries.length; i++) { - entries[i]['label'] = PathUtil.getRootLabel(entries[i].fullPath); - } - - return entries; -}; - -/** - * Checks if the given directory can be on the tree or not. - * - * @param {string} path Path to be checked. - * @return {boolean} True if the path is eligible for the directory tree. - * Otherwise, false. - */ -DirectoryTreeUtil.isEligiblePathForDirectoryTree = function(path) { - return PathUtil.isDriveBasedPath(path); -}; - -Object.freeze(DirectoryTreeUtil); - -//////////////////////////////////////////////////////////////////////////////// -// DirectoryTreeBase - -/** - * Implementation of methods for DirectoryTree and DirectoryItem. These classes - * inherits cr.ui.Tree/TreeItem so we can't make them inherit this class. - * Instead, we separate their implementations to this separate object and call - * it with setting 'this' from DirectoryTree/Item. - */ -var DirectoryItemTreeBaseMethods = {}; - -/** - * Updates sub-elements of {@code this} reading {@code DirectoryEntry}. - * The list of {@code DirectoryEntry} are not updated by this method. - * - * @param {boolean} recursive True if the all visible sub-directories are - * updated recursively including left arrows. If false, the update walks - * only immediate child directories without arrows. - */ -DirectoryItemTreeBaseMethods.updateSubElementsFromList = function(recursive) { - var index = 0; - var tree = this.parentTree_ || this; // If no parent, 'this' itself is tree. - while (this.entries_[index]) { - var currentEntry = this.entries_[index]; - var currentElement = this.items[index]; - - if (index >= this.items.length) { - var item = new DirectoryItem(currentEntry, this, tree); - this.add(item); - index++; - } else if (currentEntry.fullPath == currentElement.fullPath) { - if (recursive && this.expanded) - currentElement.updateSubDirectories(true /* recursive */); - - index++; - } else if (currentEntry.fullPath < currentElement.fullPath) { - var item = new DirectoryItem(currentEntry, this, tree); - this.addAt(item, index); - index++; - } else if (currentEntry.fullPath > currentElement.fullPath) { - this.remove(currentElement); - } - } - - var removedChild; - while (removedChild = this.items[index]) { - this.remove(removedChild); - } - - if (index == 0) { - this.hasChildren = false; - this.expanded = false; - } else { - this.hasChildren = true; - } -}; - -/** - * Finds a parent directory of the {@code entry} in {@code this}, and - * invokes the DirectoryItem.selectByEntry() of the found directory. - * - * @param {DirectoryEntry|Object} entry The entry to be searched for. Can be - * a fake. - * @return {boolean} True if the parent item is found. - */ -DirectoryItemTreeBaseMethods.searchAndSelectByEntry = function(entry) { - for (var i = 0; i < this.items.length; i++) { - var item = this.items[i]; - if (util.isParentEntry(item.entry, entry)) { - item.selectByEntry(entry); - return true; - } - } - return false; -}; - -Object.freeze(DirectoryItemTreeBaseMethods); - -//////////////////////////////////////////////////////////////////////////////// -// DirectoryItem - -/** - * A directory in the tree. Each element represents one directory. - * - * @param {DirectoryEntry} dirEntry DirectoryEntry of this item. - * @param {DirectoryItem|DirectoryTree} parentDirItem Parent of this item. - * @param {DirectoryTree} tree Current tree, which contains this item. - * @extends {cr.ui.TreeItem} - * @constructor - */ -function DirectoryItem(dirEntry, parentDirItem, tree) { - var item = cr.doc.createElement('div'); - DirectoryItem.decorate(item, dirEntry, parentDirItem, tree); - return item; -} - -/** - * @param {HTMLElement} el Element to be DirectoryItem. - * @param {DirectoryEntry} dirEntry DirectoryEntry of this item. - * @param {DirectoryItem|DirectoryTree} parentDirItem Parent of this item. - * @param {DirectoryTree} tree Current tree, which contains this item. - */ -DirectoryItem.decorate = - function(el, dirEntry, parentDirItem, tree) { - el.__proto__ = DirectoryItem.prototype; - (/** @type {DirectoryItem} */ el).decorate( - dirEntry, parentDirItem, tree); -}; - -DirectoryItem.prototype = { - __proto__: cr.ui.TreeItem.prototype, - - /** - * The DirectoryEntry corresponding to this DirectoryItem. This may be - * a dummy DirectoryEntry. - * @type {DirectoryEntry|Object} - */ - get entry() { - return this.dirEntry_; - }, - - /** - * The element containing the label text and the icon. - * @type {!HTMLElement} - * @override - */ - get labelElement() { - return this.firstElementChild.querySelector('.label'); - } -}; - -/** - * Calls DirectoryItemTreeBaseMethods.updateSubElementsFromList(). - * - * @param {boolean} recursive True if the all visible sub-directories are - * updated recursively including left arrows. If false, the update walks - * only immediate child directories without arrows. - */ -DirectoryItem.prototype.updateSubElementsFromList = function(recursive) { - DirectoryItemTreeBaseMethods.updateSubElementsFromList.call(this, recursive); -}; - -/** - * Calls DirectoryItemTreeBaseMethods.updateSubElementsFromList(). - * @param {DirectoryEntry|Object} entry The entry to be searched for. Can be - * a fake. - * @return {boolean} True if the parent item is found. - */ -DirectoryItem.prototype.searchAndSelectByEntry = function(entry) { - return DirectoryItemTreeBaseMethods.searchAndSelectByEntry.call(this, entry); -}; - -/** - * @param {DirectoryEntry} dirEntry DirectoryEntry of this item. - * @param {DirectoryItem|DirectoryTree} parentDirItem Parent of this item. - * @param {DirectoryTree} tree Current tree, which contains this item. - */ -DirectoryItem.prototype.decorate = function( - dirEntry, parentDirItem, tree) { - var path = dirEntry.fullPath; - var label; - label = dirEntry.label ? dirEntry.label : dirEntry.name; - - this.className = 'tree-item'; - this.innerHTML = - '<div class="tree-row">' + - ' <span class="expand-icon"></span>' + - ' <span class="icon"></span>' + - ' <span class="label"></span>' + - '</div>' + - '<div class="tree-children"></div>'; - this.setAttribute('role', 'treeitem'); - - this.parentTree_ = tree; - this.directoryModel_ = tree.directoryModel; - this.parent_ = parentDirItem; - this.label = label; - this.fullPath = path; - this.dirEntry_ = dirEntry; - this.fileFilter_ = this.directoryModel_.getFileFilter(); - - // Sets hasChildren=false tentatively. This will be overridden after - // scanning sub-directories in DirectoryTreeUtil.updateSubElementsFromList. - this.hasChildren = false; - - this.addEventListener('expand', this.onExpand_.bind(this), false); - var icon = this.querySelector('.icon'); - icon.classList.add('volume-icon'); - var iconType = PathUtil.getRootType(path); - if (iconType && PathUtil.isRootPath(path)) - icon.setAttribute('volume-type-icon', iconType); - else - icon.setAttribute('file-type-icon', 'folder'); - - if (this.parentTree_.contextMenuForSubitems) - this.setContextMenu(this.parentTree_.contextMenuForSubitems); - // Adds handler for future change. - this.parentTree_.addEventListener( - 'contextMenuForSubitemsChange', - function(e) { this.setContextMenu(e.newValue); }.bind(this)); - - if (parentDirItem.expanded) - this.updateSubDirectories(false /* recursive */); -}; - -/** - * Overrides WebKit's scrollIntoViewIfNeeded, which doesn't work well with - * a complex layout. This call is not necessary, so we are ignoring it. - * - * @param {boolean} unused Unused. - * @override - */ -DirectoryItem.prototype.scrollIntoViewIfNeeded = function(unused) { -}; - -/** - * Removes the child node, but without selecting the parent item, to avoid - * unintended changing of directories. Removing is done externally, and other - * code will navigate to another directory. - * - * @param {!cr.ui.TreeItem} child The tree item child to remove. - * @override - */ -DirectoryItem.prototype.remove = function(child) { - this.lastElementChild.removeChild(child); - if (this.items.length == 0) - this.hasChildren = false; -}; - -/** - * Invoked when the item is being expanded. - * @param {!UIEvent} e Event. - * @private - **/ -DirectoryItem.prototype.onExpand_ = function(e) { - this.updateSubDirectories( - true /* recursive */, - function() {}, - function() { - this.expanded = false; - }.bind(this)); - - e.stopPropagation(); -}; - -/** - * Retrieves the latest subdirectories and update them on the tree. - * @param {boolean} recursive True if the update is recursively. - * @param {function()=} opt_successCallback Callback called on success. - * @param {function()=} opt_errorCallback Callback called on error. - */ -DirectoryItem.prototype.updateSubDirectories = function( - recursive, opt_successCallback, opt_errorCallback) { - if (util.isFakeEntry(this.entry)) { - if (opt_errorCallback) - opt_errorCallback(); - return; - } - - var sortEntries = function(fileFilter, entries) { - entries.sort(function(a, b) { - return (a.name.toLowerCase() > b.name.toLowerCase()) ? 1 : -1; - }); - return entries.filter(fileFilter.filter.bind(fileFilter)); - }; - - var onSuccess = function(entries) { - this.entries_ = entries; - this.redrawSubDirectoryList_(recursive); - opt_successCallback && opt_successCallback(); - }.bind(this); - - var reader = this.entry.createReader(); - var entries = []; - var readEntry = function() { - reader.readEntries(function(results) { - if (!results.length) { - onSuccess(sortEntries(this.fileFilter_, entries)); - return; - } - - for (var i = 0; i < results.length; i++) { - var entry = results[i]; - if (entry.isDirectory) - entries.push(entry); - } - readEntry(); - }.bind(this)); - }.bind(this); - readEntry(); -}; - -/** - * Updates sub-elements of {@code parentElement} reading {@code DirectoryEntry} - * with calling {@code iterator}. - * - * @param {string} changedDirectryPath The path of the changed directory. - */ -DirectoryItem.prototype.updateItemByPath = function(changedDirectryPath) { - if (changedDirectryPath === this.entry.fullPath) { - this.updateSubDirectories(false /* recursive */); - return; - } - - for (var i = 0; i < this.items.length; i++) { - var item = this.items[i]; - if (PathUtil.isParentPath(item.entry.fullPath, changedDirectryPath)) { - item.updateItemByPath(changedDirectryPath); - break; - } - } -}; - -/** - * Redraw subitems with the latest information. The items are sorted in - * alphabetical order, case insensitive. - * @param {boolean} recursive True if the update is recursively. - * @private - */ -DirectoryItem.prototype.redrawSubDirectoryList_ = function(recursive) { - this.updateSubElementsFromList(recursive); -}; - -/** - * Select the item corresponding to the given {@code entry}. - * @param {DirectoryEntry|Object} entry The entry to be selected. Can be a fake. - */ -DirectoryItem.prototype.selectByEntry = function(entry) { - if (util.isSameEntry(entry, this.entry)) { - this.selected = true; - return; - } - - if (this.searchAndSelectByEntry(entry)) - return; - - // If the path doesn't exist, updates sub directories and tryes again. - this.updateSubDirectories( - false /* recursive */, - this.searchAndSelectByEntry.bind(this, entry)); -}; - -/** - * Executes the assigned action as a drop target. - */ -DirectoryItem.prototype.doDropTargetAction = function() { - this.expanded = true; -}; - -/** - * Executes the assigned action. DirectoryItem performs changeDirectory. - */ -DirectoryItem.prototype.doAction = function() { - if (this.fullPath != this.directoryModel_.getCurrentDirPath()) - this.directoryModel_.changeDirectory(this.fullPath); -}; - -/** - * Sets the context menu for directory tree. - * @param {cr.ui.Menu} menu Menu to be set. - */ -DirectoryItem.prototype.setContextMenu = function(menu) { - if (this.entry && PathUtil.isEligibleForFolderShortcut(this.entry.fullPath)) - cr.ui.contextMenuHandler.setContextMenu(this, menu); -}; - -//////////////////////////////////////////////////////////////////////////////// -// DirectoryTree - -/** - * Tree of directories on the middle bar. This element is also the root of - * items, in other words, this is the parent of the top-level items. - * - * @constructor - * @extends {cr.ui.Tree} - */ -function DirectoryTree() {} - -/** - * Decorates an element. - * @param {HTMLElement} el Element to be DirectoryTree. - * @param {DirectoryModel} directoryModel Current DirectoryModel. - * @param {VolumeManagerWrapper} volumeManager VolumeManager of the system. - */ -DirectoryTree.decorate = function(el, directoryModel, volumeManager) { - el.__proto__ = DirectoryTree.prototype; - (/** @type {DirectoryTree} */ el).decorate(directoryModel, volumeManager); -}; - -DirectoryTree.prototype = { - __proto__: cr.ui.Tree.prototype, - - // DirectoryTree is always expanded. - get expanded() { return true; }, - /** - * @param {boolean} value Not used. - */ - set expanded(value) {}, - - /** - * The DirectoryEntry corresponding to this DirectoryItem. This may be - * a dummy DirectoryEntry. - * @type {DirectoryEntry|Object} - * @override - **/ - get entry() { - return this.dirEntry_; - }, - - /** - * The DirectoryModel this tree corresponds to. - * @type {DirectoryModel} - */ - get directoryModel() { - return this.directoryModel_; - }, - - /** - * The VolumeManager instance of the system. - * @type {VolumeManager} - */ - get volumeManager() { - return this.volumeManager_; - }, -}; - -cr.defineProperty(DirectoryTree, 'contextMenuForSubitems', cr.PropertyKind.JS); - -/** - * Calls DirectoryItemTreeBaseMethods.updateSubElementsFromList(). - * - * @param {boolean} recursive True if the all visible sub-directories are - * updated recursively including left arrows. If false, the update walks - * only immediate child directories without arrows. - */ -DirectoryTree.prototype.updateSubElementsFromList = function(recursive) { - DirectoryItemTreeBaseMethods.updateSubElementsFromList.call(this, recursive); -}; - -/** - * Calls DirectoryItemTreeBaseMethods.updateSubElementsFromList(). - * @param {DirectoryEntry|Object} entry The entry to be searched for. Can be - * a fake. - * @return {boolean} True if the parent item is found. - */ -DirectoryTree.prototype.searchAndSelectByEntry = function(entry) { - return DirectoryItemTreeBaseMethods.searchAndSelectByEntry.call(this, entry); -}; - -/** - * Decorates an element. - * @param {DirectoryModel} directoryModel Current DirectoryModel. - * @param {VolumeManagerWrapper} volumeManager VolumeManager of the system. - */ -DirectoryTree.prototype.decorate = function(directoryModel, volumeManager) { - cr.ui.Tree.prototype.decorate.call(this); - - this.directoryModel_ = directoryModel; - this.volumeManager_ = volumeManager; - this.entries_ = DirectoryTreeUtil.generateTopLevelEntries(); - - this.fileFilter_ = this.directoryModel_.getFileFilter(); - this.fileFilter_.addEventListener('changed', - this.onFilterChanged_.bind(this)); - - this.directoryModel_.addEventListener('directory-changed', - this.onCurrentDirectoryChanged_.bind(this)); - - // Add a handler for directory change. - this.addEventListener('change', function() { - if (this.selectedItem && - (!this.currentEntry_ || - !util.isSameEntry(this.currentEntry_, this.selectedItem.entry))) { - this.currentEntry_ = this.selectedItem.entry; - this.selectedItem.doAction(); - return; - } - }.bind(this)); - - this.privateOnDirectoryChangedBound_ = - this.onDirectoryContentChanged_.bind(this); - chrome.fileBrowserPrivate.onDirectoryChanged.addListener( - this.privateOnDirectoryChangedBound_); - - this.scrollBar_ = MainPanelScrollBar(); - this.scrollBar_.initialize(this.parentNode, this); - - // Once, draws the list with the fake '/drive/' entry. - this.redraw(false /* recursive */); - // Resolves 'My Drive' entry and replaces the fake with the true one. - this.maybeResolveMyDriveRoot_(function() { - // After the true entry is resolved, draws the list again. - this.redraw(true /* recursive */); - }.bind(this)); -}; - -/** - * Select the item corresponding to the given entry. - * @param {DirectoryEntry|Object} entry The directory entry to be selected. Can - * be a fake. - */ -DirectoryTree.prototype.selectByEntry = function(entry) { - // If the target directory is not in the tree, do nothing. - if (!DirectoryTreeUtil.isEligiblePathForDirectoryTree(entry.fullPath)) - return; - - this.maybeResolveMyDriveRoot_(function() { - if (this.selectedItem && util.isSameEntry(entry, this.selectedItem.entry)) - return; - - if (this.searchAndSelectByEntry(entry)) - return; - - this.selectedItem = null; - this.updateSubDirectories( - false /* recursive */, - // Success callback, failure is not handled. - function() { - if (!this.searchAndSelectByEntry(entry)) - this.selectedItem = null; - }.bind(this)); - }.bind(this)); -}; - -/** - * Resolves the My Drive root's entry, if it is a fake. If the entry is already - * resolved to a DirectoryEntry, completionCallback() will be called - * immediately. - * @param {function()} completionCallback Called when the resolving is - * done (or the entry is already resolved), regardless if it is - * successfully done or not. - * @private - */ -DirectoryTree.prototype.maybeResolveMyDriveRoot_ = function( - completionCallback) { - var myDriveItem = this.items[0]; - if (!util.isFakeEntry(myDriveItem.entry)) { - // The entry is already resolved. Don't need to try again. - completionCallback(); - return; - } - - // The entry is a fake. - this.directoryModel_.resolveDirectory( - myDriveItem.fullPath, - function(entry) { - if (!util.isFakeEntry(entry)) - myDriveItem.dirEntry_ = entry; - - completionCallback(); - }, - completionCallback); -}; - -/** - * Retrieves the latest subdirectories and update them on the tree. - * @param {boolean} recursive True if the update is recursively. - * @param {function()=} opt_successCallback Callback called on success. - * @param {function()=} opt_errorCallback Callback called on error. - */ -DirectoryTree.prototype.updateSubDirectories = function( - recursive, opt_successCallback, opt_errorCallback) { - this.entries_ = DirectoryTreeUtil.generateTopLevelEntries(); - this.redraw(recursive); - if (opt_successCallback) - opt_successCallback(); -}; - -/** - * Redraw the list. - * @param {boolean} recursive True if the update is recursively. False if the - * only root items are updated. - */ -DirectoryTree.prototype.redraw = function(recursive) { - this.updateSubElementsFromList(recursive); -}; - -/** - * Invoked when the filter is changed. - * @private - */ -DirectoryTree.prototype.onFilterChanged_ = function() { - // Returns immediately, if the tree is hidden. - if (this.hidden) - return; - - this.redraw(true /* recursive */); -}; - -/** - * Invoked when a directory is changed. - * @param {!UIEvent} event Event. - * @private - */ -DirectoryTree.prototype.onDirectoryContentChanged_ = function(event) { - if (event.eventType == 'changed') { - // TODO: Use Entry instead of urls. This will stop working once migrating - // to separate file systems. See: crbug.com/325052. - if (!DirectoryTreeUtil.isEligiblePathForDirectoryTree(event.entry.fullPath)) - return; - - var myDriveItem = this.items[0]; - myDriveItem.updateItemByPath(event.entry.fullPath); - } -}; - -/** - * Invoked when the current directory is changed. - * @param {!UIEvent} event Event. - * @private - */ -DirectoryTree.prototype.onCurrentDirectoryChanged_ = function(event) { - this.selectByEntry(event.newDirEntry); -}; - -/** - * Sets the margin height for the transparent preview panel at the bottom. - * @param {number} margin Margin to be set in px. - */ -DirectoryTree.prototype.setBottomMarginForPanel = function(margin) { - this.style.paddingBottom = margin + 'px'; - this.scrollBar_.setBottomMarginForPanel(margin); -}; - -/** - * Updates the UI after the layout has changed. - */ -DirectoryTree.prototype.relayout = function() { - cr.dispatchSimpleEvent(this, 'relayout'); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/drag_selector.js b/chromium/chrome/browser/resources/file_manager/foreground/js/drag_selector.js deleted file mode 100644 index edc55165dfb..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/drag_selector.js +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * Drag selector used on the file list or the grid table. - * TODO(hirono): Support drag selection for grid view. crbug.com/224832 - * @constructor - */ -function DragSelector() { - /** - * Target list of drag selection. - * @type {cr.ui.List} - * @private - */ - this.target_ = null; - - /** - * Border element of drag handle. - * @type {HtmlElement} - * @private - */ - this.border_ = null; - - /** - * Start point of dragging. - * @type {number?} - * @private - */ - this.startX_ = null; - - /** - * Start point of dragging. - * @type {number?} - * @private - */ - this.startY_ = null; - - /** - * Indexes of selected items by dragging at the last update. - * @type {Array.<number>!} - * @private - */ - this.lastSelection_ = []; - - /** - * Indexes of selected items at the start of dragging. - * @type {Array.<number>!} - * @private - */ - this.originalSelection_ = []; - - // Bind handlers to make them removable. - this.onMouseMoveBound_ = this.onMouseMove_.bind(this); - this.onMouseUpBound_ = this.onMouseUp_.bind(this); - - Object.seal(this); -} - -/** - * Flag that shows whether the item is included in the selection or not. - * @enum {number} - * @private - */ -DragSelector.SelectionFlag_ = { - IN_LAST_SELECTION: 1 << 0, - IN_CURRENT_SELECTION: 1 << 1 -}; - -/** - * Obtains the scrolled position in the element of mouse pointer from the mouse - * event. - * - * @param {HTMLElement} element Element that has the scroll bars. - * @param {Event} event The mouse event. - * @return {object} Scrolled position. - */ -DragSelector.getScrolledPosition = function(element, event) { - if (!element.cachedBounds) { - element.cachedBounds = element.getBoundingClientRect(); - if (!element.cachedBounds) - return null; - } - var rect = element.cachedBounds; - return { - x: event.clientX - rect.left + element.scrollLeft, - y: event.clientY - rect.top + element.scrollTop - }; -}; - -/** - * Starts drag selection by reacting dragstart event. - * This function must be called from handlers of dragstart event. - * - * @this {DragSelector} - * @param {cr.ui.List} list List where the drag selection starts. - * @param {Event} event The dragstart event. - */ -DragSelector.prototype.startDragSelection = function(list, event) { - // Precondition check - if (!list.selectionModel_.multiple || this.target_) - return; - - // Set the target of the drag selection - this.target_ = list; - - // Prevent the default action. - event.preventDefault(); - - // Save the start state. - var startPos = DragSelector.getScrolledPosition(list, event); - if (!startPos) - return; - this.startX_ = startPos.x; - this.startY_ = startPos.y; - this.lastSelection_ = []; - this.originalSelection_ = this.target_.selectionModel_.selectedIndexes; - - // Create and add the border element - if (!this.border_) { - this.border_ = this.target_.ownerDocument.createElement('div'); - this.border_.className = 'drag-selection-border'; - } - this.border_.style.left = this.startX_ + 'px'; - this.border_.style.top = this.startY_ + 'px'; - this.border_.style.width = '0'; - this.border_.style.height = '0'; - list.appendChild(this.border_); - - // If no modifier key is pressed, clear the original selection. - if (!event.shiftKey && !event.ctrlKey) - this.target_.selectionModel_.unselectAll(); - - // Register event handlers. - // The handlers are bounded at the constructor. - this.target_.ownerDocument.addEventListener( - 'mousemove', this.onMouseMoveBound_, true); - this.target_.ownerDocument.addEventListener( - 'mouseup', this.onMouseUpBound_, true); -}; - -/** - * Handles the mousemove event. - * @private - * @param {MouseEvent} event The mousemove event. - */ -DragSelector.prototype.onMouseMove_ = function(event) { - // Get the selection bounds. - var pos = DragSelector.getScrolledPosition(this.target_, event); - var borderBounds = { - left: Math.max(Math.min(this.startX_, pos.x), 0), - top: Math.max(Math.min(this.startY_, pos.y), 0), - right: Math.min(Math.max(this.startX_, pos.x), this.target_.scrollWidth), - bottom: Math.min(Math.max(this.startY_, pos.y), this.target_.scrollHeight) - }; - borderBounds.width = borderBounds.right - borderBounds.left; - borderBounds.height = borderBounds.bottom - borderBounds.top; - - // Collect items within the selection rect. - var currentSelection = this.target_.getHitElements( - borderBounds.left, - borderBounds.top, - borderBounds.width, - borderBounds.height); - var pointedElements = this.target_.getHitElements(pos.x, pos.y); - var leadIndex = pointedElements.length ? pointedElements[0] : -1; - - // Diff the selection between currentSelection and this.lastSelection_. - var selectionFlag = []; - for (var i = 0; i < this.lastSelection_.length; i++) { - var index = this.lastSelection_[i]; - // Bit operator can be used for undefined value. - selectionFlag[index] = - selectionFlag[index] | DragSelector.SelectionFlag_.IN_LAST_SELECTION; - } - for (var i = 0; i < currentSelection.length; i++) { - var index = currentSelection[i]; - // Bit operator can be used for undefined value. - selectionFlag[index] = - selectionFlag[index] | DragSelector.SelectionFlag_.IN_CURRENT_SELECTION; - } - - // Update the selection - this.target_.selectionModel_.beginChange(); - for (var name in selectionFlag) { - var index = parseInt(name); - var flag = selectionFlag[name]; - // The flag may be one of followings: - // - IN_LAST_SELECTION | IN_CURRENT_SELECTION - // - IN_LAST_SELECTION - // - IN_CURRENT_SELECTION - // - undefined - - // If the flag equals to (IN_LAST_SELECTION | IN_CURRENT_SELECTION), - // this is included in both the last selection and the current selection. - // We have nothing to do for this item. - - if (flag == DragSelector.SelectionFlag_.IN_LAST_SELECTION) { - // If the flag equals to IN_LAST_SELECTION, - // then the item is included in lastSelection but not in currentSelection. - // Revert the selection state to this.originalSelection_. - this.target_.selectionModel_.setIndexSelected( - index, this.originalSelection_.indexOf(index) != -1); - } else if (flag == DragSelector.SelectionFlag_.IN_CURRENT_SELECTION) { - // If the flag equals to IN_CURRENT_SELECTION, - // this is included in currentSelection but not in lastSelection. - this.target_.selectionModel_.setIndexSelected(index, true); - } - } - if (leadIndex != -1) { - this.target_.selectionModel_.leadIndex = leadIndex; - this.target_.selectionModel_.anchorIndex = leadIndex; - } - this.target_.selectionModel_.endChange(); - this.lastSelection_ = currentSelection; - - // Update the size of border - this.border_.style.left = borderBounds.left + 'px'; - this.border_.style.top = borderBounds.top + 'px'; - this.border_.style.width = borderBounds.width + 'px'; - this.border_.style.height = borderBounds.height + 'px'; -}; - -/** - * Handle the mouseup event. - * @private - * @param {MouseEvent} event The mouseup event. - */ -DragSelector.prototype.onMouseUp_ = function(event) { - this.onMouseMove_(event); - this.target_.removeChild(this.border_); - this.target_.ownerDocument.removeEventListener( - 'mousemove', this.onMouseMoveBound_, true); - this.target_.ownerDocument.removeEventListener( - 'mouseup', this.onMouseUpBound_, true); - cr.dispatchSimpleEvent(this.target_, 'dragselectionend'); - this.target_.cachedBounds = null; - this.target_ = null; - // The target may select an item by reacting to the mouseup event. - // This suppress to the selecting behavior. - event.stopPropagation(); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/drive_banners.js b/chromium/chrome/browser/resources/file_manager/foreground/js/drive_banners.js deleted file mode 100644 index dc1cd924d7a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/drive_banners.js +++ /dev/null @@ -1,660 +0,0 @@ -// 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. - -'use strict'; - -/** - * Responsible for showing following banners in the file list. - * - WelcomeBanner - * - AuthFailBanner - * @param {DirectoryModel} directoryModel The model. - * @param {VolumeManagerWrapper} volumeManager The manager. - * @param {DOMDocument} document HTML document. - * @param {boolean} showOffers True if we should show offer banners. - * @constructor - */ -function FileListBannerController( - directoryModel, volumeManager, document, showOffers) { - this.directoryModel_ = directoryModel; - this.volumeManager_ = volumeManager; - this.document_ = document; - this.showOffers_ = showOffers; - this.driveEnabled_ = false; - - this.initializeWelcomeBanner_(); - this.privateOnDirectoryChangedBound_ = - this.privateOnDirectoryChanged_.bind(this); - - var handler = this.checkSpaceAndMaybeShowWelcomeBanner_.bind(this); - this.directoryModel_.addEventListener('scan-completed', handler); - this.directoryModel_.addEventListener('rescan-completed', handler); - this.directoryModel_.addEventListener('directory-changed', - this.onDirectoryChanged_.bind(this)); - - this.unmountedPanel_ = this.document_.querySelector('#unmounted-panel'); - this.volumeManager_.volumeInfoList.addEventListener( - 'splice', this.onVolumeInfoListSplice_.bind(this)); - this.volumeManager_.addEventListener('drive-connection-changed', - this.onDriveConnectionChanged_.bind(this)); - - chrome.storage.onChanged.addListener(this.onStorageChange_.bind(this)); - this.welcomeHeaderCounter_ = WELCOME_HEADER_COUNTER_LIMIT; - this.warningDismissedCounter_ = 0; - chrome.storage.local.get([WELCOME_HEADER_COUNTER_KEY, WARNING_DISMISSED_KEY], - function(values) { - this.welcomeHeaderCounter_ = - parseInt(values[WELCOME_HEADER_COUNTER_KEY]) || 0; - this.warningDismissedCounter_ = - parseInt(values[WARNING_DISMISSED_KEY]) || 0; - }.bind(this)); - - this.authFailedBanner_ = - this.document_.querySelector('#drive-auth-failed-warning'); - var authFailedText = this.authFailedBanner_.querySelector('.drive-text'); - authFailedText.innerHTML = util.htmlUnescape(str('DRIVE_NOT_REACHED')); - authFailedText.querySelector('a').addEventListener('click', function(e) { - chrome.fileBrowserPrivate.logoutUserForReauthentication(); - e.preventDefault(); - }); - this.maybeShowAuthFailBanner_(); -} - -/** - * FileListBannerController extends cr.EventTarget. - */ -FileListBannerController.prototype.__proto__ = cr.EventTarget.prototype; - -/** - * Key in localStorage to keep number of times the Drive Welcome - * banner has shown. - */ -var WELCOME_HEADER_COUNTER_KEY = 'driveWelcomeHeaderCounter'; - -// If the warning was dismissed before, this key stores the quota value -// (as of the moment of dismissal). -// If the warning was never dismissed or was reset this key stores 0. -var WARNING_DISMISSED_KEY = 'driveSpaceWarningDismissed'; - -/** - * Maximum times Drive Welcome banner could have shown. - */ -var WELCOME_HEADER_COUNTER_LIMIT = 25; - -/** - * Initializes the banner to promote DRIVE. - * This method must be called before any of showing banner functions, and - * also before registering them as callbacks. - * @private - */ -FileListBannerController.prototype.initializeWelcomeBanner_ = function() { - this.usePromoWelcomeBanner_ = !util.boardIs('x86-mario') && - !util.boardIs('x86-zgb') && - !util.boardIs('x86-alex'); -}; - -/** - * @param {number} value How many times the Drive Welcome header banner - * has shown. - * @private - */ -FileListBannerController.prototype.setWelcomeHeaderCounter_ = function(value) { - var values = {}; - values[WELCOME_HEADER_COUNTER_KEY] = value; - chrome.storage.local.set(values); -}; - -/** - * @param {number} value How many times the low space warning has dismissed. - * @private - */ -FileListBannerController.prototype.setWarningDismissedCounter_ = - function(value) { - var values = {}; - values[WARNING_DISMISSED_KEY] = value; - chrome.storage.local.set(values); -}; - -/** - * chrome.storage.onChanged event handler. - * @param {Object.<string, Object>} changes Changes values. - * @param {string} areaName "local" or "sync". - * @private - */ -FileListBannerController.prototype.onStorageChange_ = function(changes, - areaName) { - if (areaName == 'local' && WELCOME_HEADER_COUNTER_KEY in changes) { - this.welcomeHeaderCounter_ = changes[WELCOME_HEADER_COUNTER_KEY].newValue; - } - if (areaName == 'local' && WARNING_DISMISSED_KEY in changes) { - this.warningDismissedCounter_ = changes[WARNING_DISMISSED_KEY].newValue; - } -}; - -/** - * Invoked when the drive connection status is change in the volume manager. - * @private - */ -FileListBannerController.prototype.onDriveConnectionChanged_ = function() { - this.maybeShowAuthFailBanner_(); -}; - -/** - * @param {string} type 'none'|'page'|'header'. - * @param {string} messageId Resource ID of the message. - * @private - */ -FileListBannerController.prototype.prepareAndShowWelcomeBanner_ = - function(type, messageId) { - this.showWelcomeBanner_(type); - - var container = this.document_.querySelector('.drive-welcome.' + type); - if (container.firstElementChild) - return; // Do not re-create. - - if (!this.document_.querySelector('link[drive-welcome-style]')) { - var style = this.document_.createElement('link'); - style.rel = 'stylesheet'; - style.href = 'foreground/css/drive_welcome.css'; - style.setAttribute('drive-welcome-style', ''); - this.document_.head.appendChild(style); - } - - var wrapper = util.createChild(container, 'drive-welcome-wrapper'); - util.createChild(wrapper, 'drive-welcome-icon'); - - var close = util.createChild(wrapper, 'cr-dialog-close'); - close.addEventListener('click', this.closeWelcomeBanner_.bind(this)); - - var message = util.createChild(wrapper, 'drive-welcome-message'); - - var title = util.createChild(message, 'drive-welcome-title'); - - var text = util.createChild(message, 'drive-welcome-text'); - text.innerHTML = str(messageId); - - var links = util.createChild(message, 'drive-welcome-links'); - - var more; - if (this.usePromoWelcomeBanner_) { - var welcomeTitle = str('DRIVE_WELCOME_TITLE_ALTERNATIVE'); - if (util.boardIs('link')) - welcomeTitle = str('DRIVE_WELCOME_TITLE_ALTERNATIVE_1TB'); - title.textContent = welcomeTitle; - more = util.createChild(links, - 'drive-welcome-button drive-welcome-start', 'a'); - more.textContent = str('DRIVE_WELCOME_CHECK_ELIGIBILITY'); - more.href = str('GOOGLE_DRIVE_REDEEM_URL'); - } else { - title.textContent = str('DRIVE_WELCOME_TITLE'); - more = util.createChild(links, 'plain-link', 'a'); - more.textContent = str('DRIVE_LEARN_MORE'); - more.href = str('GOOGLE_DRIVE_OVERVIEW_URL'); - } - more.tabIndex = '13'; // See: go/filesapp-tabindex. - more.target = '_blank'; - - var dismiss; - if (this.usePromoWelcomeBanner_) - dismiss = util.createChild(links, 'drive-welcome-button'); - else - dismiss = util.createChild(links, 'plain-link'); - - dismiss.classList.add('drive-welcome-dismiss'); - dismiss.textContent = str('DRIVE_WELCOME_DISMISS'); - dismiss.addEventListener('click', this.closeWelcomeBanner_.bind(this)); - - this.previousDirWasOnDrive_ = false; -}; - -/** - * Show or hide the "Low Google Drive space" warning. - * @param {boolean} show True if the box need to be shown. - * @param {Object} sizeStats Size statistics. Should be defined when showing the - * warning. - * @private - */ -FileListBannerController.prototype.showLowDriveSpaceWarning_ = - function(show, sizeStats) { - var box = this.document_.querySelector('#volume-space-warning'); - - // Avoid showing two banners. - // TODO(kaznacheev): Unify the low space warning and the promo header. - if (show) - this.cleanupWelcomeBanner_(); - - if (box.hidden == !show) - return; - - if (this.warningDismissedCounter_) { - if (this.warningDismissedCounter_ == - sizeStats.totalSize && // Quota had not changed - sizeStats.remainingSize / sizeStats.totalSize < 0.15) { - // Since the last dismissal decision the quota has not changed AND - // the user did not free up significant space. Obey the dismissal. - show = false; - } else { - // Forget the dismissal. Warning will be shown again. - this.setWarningDismissedCounter_(0); - } - } - - box.textContent = ''; - if (show) { - var icon = this.document_.createElement('div'); - icon.className = 'drive-icon'; - box.appendChild(icon); - - var text = this.document_.createElement('div'); - text.className = 'drive-text'; - text.textContent = strf('DRIVE_SPACE_AVAILABLE_LONG', - util.bytesToString(sizeStats.remainingSize)); - box.appendChild(text); - - var link = this.document_.createElement('a'); - link.className = 'plain-link'; - link.textContent = str('DRIVE_BUY_MORE_SPACE_LINK'); - link.href = str('GOOGLE_DRIVE_BUY_STORAGE_URL'); - link.target = '_blank'; - box.appendChild(link); - - var close = this.document_.createElement('div'); - close.className = 'cr-dialog-close'; - box.appendChild(close); - close.addEventListener('click', function(total) { - window.localStorage[WARNING_DISMISSED_KEY] = total; - box.hidden = true; - this.requestRelayout_(100); - }.bind(this, sizeStats.totalSize)); - } - - if (box.hidden != !show) { - box.hidden = !show; - this.requestRelayout_(100); - } -}; -/** - * Closes the Drive Welcome banner. - * @private - */ -FileListBannerController.prototype.closeWelcomeBanner_ = function() { - this.cleanupWelcomeBanner_(); - // Stop showing the welcome banner. - this.setWelcomeHeaderCounter_(WELCOME_HEADER_COUNTER_LIMIT); -}; - -/** - * Shows or hides the welcome banner for drive. - * @private - */ -FileListBannerController.prototype.checkSpaceAndMaybeShowWelcomeBanner_ = - function() { - if (!this.isOnCurrentProfileDrive()) { - // We are not on the drive file system. Do not show (close) the welcome - // banner. - this.cleanupWelcomeBanner_(); - this.previousDirWasOnDrive_ = false; - return; - } - - var driveVolume = this.volumeManager_.getCurrentProfileVolumeInfo( - util.VolumeType.DRIVE); - if (this.welcomeHeaderCounter_ >= WELCOME_HEADER_COUNTER_LIMIT || - !driveVolume || driveVolume.error) { - // The banner is already shown enough times or the drive FS is not mounted. - // So, do nothing here. - return; - } - - if (!this.showOffers_) { - // Because it is not necessary to show the offer, set - // |usePromoWelcomeBanner_| false here. Note that it probably should be able - // to do this in the constructor, but there remains non-trivial path, - // which may be causes |usePromoWelcomeBanner_| == true's behavior even - // if |showOffers_| is false. - // TODO(hidehiko): Make sure if it is expected or not, and simplify - // |showOffers_| if possible. - this.usePromoWelcomeBanner_ = false; - } - - // Perform asynchronous tasks in parallel. - var group = new AsyncUtil.Group(); - - // Choose the offer basing on the board name. The default one is 100 GB. - var offerSize = 100; // In GB. - var offerServiceId = 'drive.cros.echo.1'; - - if (util.boardIs('link')) { - offerSize = 1024; // 1 TB. - offerServiceId = 'drive.cros.echo.2'; - } - - // If the offer has been checked, then do not show the promo anymore. - group.add(function(onCompleted) { - chrome.echoPrivate.getOfferInfo(offerServiceId, function(offerInfo) { - // If the offer has not been checked, then an error is raised. - if (!chrome.runtime.lastError) - this.usePromoWelcomeBanner_ = false; - onCompleted(); - }.bind(this)); - }.bind(this)); - - if (this.usePromoWelcomeBanner_) { - // getSizeStats for Drive file system accesses to the server, so we should - // minimize the invocation. - group.add(function(onCompleted) { - chrome.fileBrowserPrivate.getSizeStats( - util.makeFilesystemUrl(this.directoryModel_.getCurrentRootPath()), - function(result) { - if (result && result.totalSize >= offerSize * 1024 * 1024 * 1024) - this.usePromoWelcomeBanner_ = false; - onCompleted(); - }.bind(this)); - }.bind(this)); - } - - group.run(this.maybeShowWelcomeBanner_.bind(this)); -}; - -/** - * Decides which banner should be shown, and show it. This method is designed - * to be called only from checkSpaceAndMaybeShowWelcomeBanner_. - * @private - */ -FileListBannerController.prototype.maybeShowWelcomeBanner_ = function() { - if (this.directoryModel_.getFileList().length == 0 && - this.welcomeHeaderCounter_ == 0) { - // Only show the full page banner if the header banner was never shown. - // Do not increment the counter. - // The timeout below is required because sometimes another - // 'rescan-completed' event arrives shortly with non-empty file list. - setTimeout(function() { - if (this.isOnCurrentProfileDrive() && this.welcomeHeaderCounter_ == 0) { - this.prepareAndShowWelcomeBanner_('page', 'DRIVE_WELCOME_TEXT_LONG'); - } - }.bind(this), 2000); - } else { - // We do not want to increment the counter when the user navigates - // between different directories on Drive, but we increment the counter - // once anyway to prevent the full page banner from showing. - if (!this.previousDirWasOnDrive_ || this.welcomeHeaderCounter_ == 0) { - this.setWelcomeHeaderCounter_(this.welcomeHeaderCounter_ + 1); - this.prepareAndShowWelcomeBanner_('header', 'DRIVE_WELCOME_TEXT_SHORT'); - } - } - this.previousDirWasOnDrive_ = true; -}; - -/** - * @return {boolean} True if current directory is on Drive root of current - * profile. - */ -FileListBannerController.prototype.isOnCurrentProfileDrive = function() { - var entry = this.directoryModel_.getCurrentDirEntry(); - if (!entry || util.isFakeEntry(entry)) - return false; - var locationInfo = this.volumeManager_.getLocationInfo(entry); - return locationInfo && - locationInfo.rootType === RootType.DRIVE && - locationInfo.volumeInfo.profile.isCurrentProfile; -}; - -/** - * Shows the Drive Welcome banner. - * @param {string} type 'page'|'head'|'none'. - * @private - */ -FileListBannerController.prototype.showWelcomeBanner_ = function(type) { - var container = this.document_.querySelector('.dialog-container'); - if (container.getAttribute('drive-welcome') != type) { - container.setAttribute('drive-welcome', type); - this.requestRelayout_(200); // Resize only after the animation is done. - } -}; - -/** - * Update the UI when the current directory changes. - * - * @param {Event} event The directory-changed event. - * @private - */ -FileListBannerController.prototype.onDirectoryChanged_ = function(event) { - var rootVolume = this.volumeManager_.getVolumeInfo(event.newDirEntry); - var previousRootVolume = event.previousDirEntry ? - this.volumeManager_.getVolumeInfo(event.previousDirEntry) : null; - - // Show (or hide) the low space warning. - this.maybeShowLowSpaceWarning_(rootVolume); - - // Add or remove listener to show low space warning, if necessary. - var isLowSpaceWarningTarget = this.isLowSpaceWarningTarget_(rootVolume); - if (isLowSpaceWarningTarget !== - this.isLowSpaceWarningTarget_(previousRootVolume)) { - if (isLowSpaceWarningTarget) { - chrome.fileBrowserPrivate.onDirectoryChanged.addListener( - this.privateOnDirectoryChangedBound_); - } else { - chrome.fileBrowserPrivate.onDirectoryChanged.removeListener( - this.privateOnDirectoryChangedBound_); - } - } - - if (!this.isOnCurrentProfileDrive()) { - this.cleanupWelcomeBanner_(); - this.authFailedBanner_.hidden = true; - } - - this.updateDriveUnmountedPanel_(); - if (this.isOnCurrentProfileDrive()) { - this.unmountedPanel_.classList.remove('retry-enabled'); - this.maybeShowAuthFailBanner_(); - } -}; - -/** - * @param {VolumeInfo} volumeInfo Volume info to be checked. - * @return {boolean} true if the file system specified by |root| is a target - * to show low space warning. Otherwise false. - * @private - */ -FileListBannerController.prototype.isLowSpaceWarningTarget_ = - function(volumeInfo) { - return volumeInfo && - volumeInfo.profile.isCurrentProfile && - (volumeInfo.volumeType === util.VolumeType.DOWNLOADS || - volumeInfo.volumeType === util.VolumeType.DRIVE); -}; - -/** - * Callback which is invoked when the file system has been changed. - * @param {Object} event chrome.fileBrowserPrivate.onDirectoryChanged event. - * @private - */ -FileListBannerController.prototype.privateOnDirectoryChanged_ = function( - event) { - if (!this.directoryModel_.getCurrentDirEntry()) - return; - - var currentDirEntry = this.directoryModel_.getCurrentDirEntry(); - var currentVolume = currentDirEntry && - this.volumeManager_.getVolumeInfo(currentDirEntry); - var eventVolume = this.volumeManager_.getVolumeInfo(event.entry); - if (currentVolume === eventVolume) { - // The file system we are currently on is changed. - // So, check the free space. - this.maybeShowLowSpaceWarning_(currentVolume); - } -}; - -/** - * Shows or hides the low space warning. - * @param {VolumeInfo} volume Type of volume, which we are interested in. - * @private - */ -FileListBannerController.prototype.maybeShowLowSpaceWarning_ = function( - volume) { - // TODO(kaznacheev): Unify the two low space warning. - var threshold = 0; - switch (volume.volumeType) { - case util.VolumeType.DOWNLOADS: - this.showLowDriveSpaceWarning_(false); - threshold = 0.2; - break; - case util.VolumeType.DRIVE: - this.showLowDownloadsSpaceWarning_(false); - threshold = 0.1; - break; - default: - // If the current file system is neither the DOWNLOAD nor the DRIVE, - // just hide the warning. - this.showLowDownloadsSpaceWarning_(false); - this.showLowDriveSpaceWarning_(false); - return; - } - - chrome.fileBrowserPrivate.getSizeStats( - volume.getDisplayRootDirectoryURL(), - function(sizeStats) { - var currentVolume = this.volumeManager_.getVolumeInfo( - this.directoryModel_.getCurrentDirEntry()); - if (volume !== currentVolume) { - // This happens when the current directory is moved during requesting - // the file system size. Just ignore it. - return; - } - // sizeStats is undefined, if some error occurs. - if (!sizeStats || sizeStats.totalSize == 0) - return; - - var remainingRatio = sizeStats.remainingSize / sizeStats.totalSize; - var isLowDiskSpace = remainingRatio < threshold; - if (volume.volumeType === util.VolumeType.DOWNLOADS) - this.showLowDownloadsSpaceWarning_(isLowDiskSpace); - else - this.showLowDriveSpaceWarning_(isLowDiskSpace, sizeStats); - }.bind(this)); -}; - -/** - * removes the Drive Welcome banner. - * @private - */ -FileListBannerController.prototype.cleanupWelcomeBanner_ = function() { - this.showWelcomeBanner_('none'); -}; - -/** - * Notifies the file manager what layout must be recalculated. - * @param {number} delay In milliseconds. - * @private - */ -FileListBannerController.prototype.requestRelayout_ = function(delay) { - var self = this; - setTimeout(function() { - cr.dispatchSimpleEvent(self, 'relayout'); - }, delay); -}; - -/** - * Show or hide the "Low disk space" warning. - * @param {boolean} show True if the box need to be shown. - * @private - */ -FileListBannerController.prototype.showLowDownloadsSpaceWarning_ = - function(show) { - var box = this.document_.querySelector('.downloads-warning'); - - if (box.hidden == !show) return; - - if (show) { - var html = util.htmlUnescape(str('DOWNLOADS_DIRECTORY_WARNING')); - box.innerHTML = html; - var link = box.querySelector('a'); - link.href = str('DOWNLOADS_LOW_SPACE_WARNING_HELP_URL'); - link.target = '_blank'; - } else { - box.innerHTML = ''; - } - - box.hidden = !show; - this.requestRelayout_(100); -}; - -/** - * Creates contents for the DRIVE unmounted panel. - * @private - */ -FileListBannerController.prototype.ensureDriveUnmountedPanelInitialized_ = - function() { - var panel = this.unmountedPanel_; - if (panel.firstElementChild) - return; - - var create = function(parent, tag, className, opt_textContent) { - var div = panel.ownerDocument.createElement(tag); - div.className = className; - div.textContent = opt_textContent || ''; - parent.appendChild(div); - return div; - }; - - var loading = create(panel, 'div', 'loading', str('DRIVE_LOADING')); - var spinnerBox = create(loading, 'div', 'spinner-box'); - create(spinnerBox, 'div', 'spinner'); - create(panel, 'div', 'error', str('DRIVE_CANNOT_REACH')); - - var learnMore = create(panel, 'a', 'learn-more plain-link', - str('DRIVE_LEARN_MORE')); - learnMore.href = str('GOOGLE_DRIVE_ERROR_HELP_URL'); - learnMore.target = '_blank'; -}; - -/** - * Called when volume info list is updated. - * @param {Event} event Splice event data on volume info list. - * @private - */ -FileListBannerController.prototype.onVolumeInfoListSplice_ = function(event) { - var isDriveVolume = function(volumeInfo) { - return volumeInfo.volumeType === util.VolumeType.DRIVE; - }; - if (event.removed.some(isDriveVolume) || event.added.some(isDriveVolume)) - this.updateDriveUnmountedPanel_(); -}; - -/** - * Shows the panel when current directory is DRIVE and it's unmounted. - * Hides it otherwise. The panel shows spinner if DRIVE is mounting or - * an error message if it failed. - * @private - */ -FileListBannerController.prototype.updateDriveUnmountedPanel_ = function() { - var node = this.document_.body; - if (this.isOnCurrentProfileDrive()) { - var driveVolume = this.volumeManager_.getCurrentProfileVolumeInfo( - util.VolumeType.DRIVE); - if (driveVolume && driveVolume.error) { - this.ensureDriveUnmountedPanelInitialized_(); - this.unmountedPanel_.classList.add('retry-enabled'); - } else { - this.unmountedPanel_.classList.remove('retry-enabled'); - } - node.setAttribute('drive', status); - } else { - node.removeAttribute('drive'); - } -}; - -/** - * Updates the visibility of Drive Connection Warning banner, retrieving the - * current connection information. - * @private - */ -FileListBannerController.prototype.maybeShowAuthFailBanner_ = function() { - var connection = this.volumeManager_.getDriveConnectionState(); - var showDriveNotReachedMessage = - this.isOnCurrentProfileDrive() && - connection.type == util.DriveConnectionType.OFFLINE && - connection.reason == util.DriveConnectionReason.NOT_READY; - this.authFailedBanner_.hidden = !showDriveNotReachedMessage; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/error_counter.js b/chromium/chrome/browser/resources/file_manager/foreground/js/error_counter.js deleted file mode 100644 index 8cec3bba03f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/error_counter.js +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * This variable is checked in SelectFileDialogExtensionBrowserTest. - * @type {number} - */ -window.JSErrorCount = 0; - -/** - * Count uncaught exceptions. - */ -window.onerror = function() { window.JSErrorCount++; }; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/error_dialog.js b/chromium/chrome/browser/resources/file_manager/foreground/js/error_dialog.js deleted file mode 100644 index 5dd3545d3c7..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/error_dialog.js +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * @param {HTMLElement} parentNode Node to be parent for this dialog. - * @constructor - */ -function ErrorDialog(parentNode) { - cr.ui.dialogs.BaseDialog.call(this, parentNode); -} - -ErrorDialog.prototype = { - __proto__: cr.ui.dialogs.BaseDialog.prototype -}; - -/** - * One-time initialization of DOM. - * @private - */ -ErrorDialog.prototype.initDom_ = function() { - cr.ui.dialogs.BaseDialog.prototype.initDom_.call(this); - this.frame_.classList.add('error-dialog-frame'); - var img = this.document_.createElement('div'); - img.className = 'error-dialog-img'; - this.frame_.insertBefore(img, this.text_); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/file_grid.js b/chromium/chrome/browser/resources/file_manager/foreground/js/file_grid.js deleted file mode 100644 index b275cd0e9f5..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/file_grid.js +++ /dev/null @@ -1,302 +0,0 @@ -// 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. - -'use strict'; - -/** - * FileGrid constructor. - * - * Represents grid for the Grid Vew in the File Manager. - * @constructor - * @extends {cr.ui.Grid} - */ - -function FileGrid() { - throw new Error('Use FileGrid.decorate'); -} - -/** - * Thumbnail quality. - * @enum {number} - */ -FileGrid.ThumbnailQuality = { - LOW: 0, - HIGH: 1 -}; - -/** - * Inherits from cr.ui.Grid. - */ -FileGrid.prototype.__proto__ = cr.ui.Grid.prototype; - -/** - * Decorates an HTML element to be a FileGrid. - * @param {HTMLElement} self The grid to decorate. - * @param {MetadataCache} metadataCache Metadata cache to find entries - * metadata. - */ -FileGrid.decorate = function(self, metadataCache) { - cr.ui.Grid.decorate(self); - self.__proto__ = FileGrid.prototype; - self.metadataCache_ = metadataCache; - - self.scrollBar_ = new MainPanelScrollBar(); - self.scrollBar_.initialize(self.parentNode, self); - self.setBottomMarginForPanel(0); - - self.itemConstructor = function(entry) { - var item = self.ownerDocument.createElement('LI'); - FileGrid.Item.decorate(item, entry, self); - return item; - }; - - self.relayoutAggregation_ = - new AsyncUtil.Aggregation(self.relayoutImmediately_.bind(self)); -}; - -/** - * Updates items to reflect metadata changes. - * @param {string} type Type of metadata changed. - * @param {Object.<string, Object>} props Map from entry URLs to metadata props. - */ -FileGrid.prototype.updateListItemsMetadata = function(type, props) { - var boxes = this.querySelectorAll('.img-container'); - for (var i = 0; i < boxes.length; i++) { - var box = boxes[i]; - var entry = this.dataModel.item(this.getListItemAncestor(box)); - if (!entry || !(entry.toURL() in props)) - continue; - - FileGrid.decorateThumbnailBox(box, - entry, - this.metadataCache_, - ThumbnailLoader.FillMode.FIT, - FileGrid.ThumbnailQuality.HIGH); - } -}; - -/** - * Redraws the UI. Skips multiple consecutive calls. - */ -FileGrid.prototype.relayout = function() { - this.relayoutAggregation_.run(); -}; - -/** - * Redraws the UI immediately. - * @private - */ -FileGrid.prototype.relayoutImmediately_ = function() { - this.startBatchUpdates(); - this.columns = 0; - this.redraw(); - this.endBatchUpdates(); - cr.dispatchSimpleEvent(this, 'relayout'); -}; - -/** - * Decorates thumbnail. - * @param {HTMLElement} li List item. - * @param {Entry} entry Entry to render a thumbnail for. - * @param {MetadataCache} metadataCache To retrieve metadata. - */ -FileGrid.decorateThumbnail = function(li, entry, metadataCache) { - li.className = 'thumbnail-item'; - if (entry) - filelist.decorateListItem(li, entry, metadataCache); - - var frame = li.ownerDocument.createElement('div'); - frame.className = 'thumbnail-frame'; - li.appendChild(frame); - - var box = li.ownerDocument.createElement('div'); - if (entry) { - FileGrid.decorateThumbnailBox(box, - entry, - metadataCache, - ThumbnailLoader.FillMode.AUTO, - FileGrid.ThumbnailQuality.HIGH); - } - frame.appendChild(box); - - var bottom = li.ownerDocument.createElement('div'); - bottom.className = 'thumbnail-bottom'; - bottom.appendChild(filelist.renderFileNameLabel(li.ownerDocument, entry)); - frame.appendChild(bottom); -}; - -/** - * Decorates the box containing a centered thumbnail image. - * - * @param {HTMLDivElement} box Box to decorate. - * @param {Entry} entry Entry which thumbnail is generating for. - * @param {MetadataCache} metadataCache To retrieve metadata. - * @param {ThumbnailLoader.FillMode} fillMode Fill mode. - * @param {FileGrid.ThumbnailQuality} quality Thumbnail quality. - * @param {function(HTMLElement)=} opt_imageLoadCallback Callback called when - * the image has been loaded before inserting it into the DOM. - */ -FileGrid.decorateThumbnailBox = function( - box, entry, metadataCache, fillMode, quality, opt_imageLoadCallback) { - box.className = 'img-container'; - if (entry.isDirectory) { - box.setAttribute('generic-thumbnail', 'folder'); - if (opt_imageLoadCallback) - setTimeout(opt_imageLoadCallback, 0, null /* callback parameter */); - return; - } - - var metadataTypes = 'thumbnail|filesystem'; - - if (FileType.isOnDrive(entry)) { - metadataTypes += '|drive'; - } else { - // TODO(dgozman): If we ask for 'media' for a Drive file we fall into an - // infinite loop. - metadataTypes += '|media'; - } - - // Drive provides high quality thumbnails via USE_EMBEDDED, however local - // images usually provide very tiny thumbnails, therefore USE_EMBEDDE can't - // be used to obtain high quality output. - var useEmbedded; - switch (quality) { - case FileGrid.ThumbnailQuality.LOW: - useEmbedded = ThumbnailLoader.UseEmbedded.USE_EMBEDDED; - break; - case FileGrid.ThumbnailQuality.HIGH: - useEmbedded = FileType.isOnDrive(entry) ? - ThumbnailLoader.UseEmbedded.USE_EMBEDDED : - ThumbnailLoader.UseEmbedded.NO_EMBEDDED; - break; - } - - metadataCache.get(entry, metadataTypes, - function(metadata) { - new ThumbnailLoader(entry.toURL(), - ThumbnailLoader.LoaderType.IMAGE, - metadata, - undefined, // opt_mediaType - useEmbedded). - load(box, - fillMode, - ThumbnailLoader.OptimizationMode.DISCARD_DETACHED, - opt_imageLoadCallback); - }); -}; - -/** - * Item for the Grid View. - * @constructor - */ -FileGrid.Item = function() { - throw new Error(); -}; - -/** - * Inherits from cr.ui.ListItem. - */ -FileGrid.Item.prototype.__proto__ = cr.ui.ListItem.prototype; - -Object.defineProperty(FileGrid.Item.prototype, 'label', { - /** - * @this {FileGrid.Item} - * @return {string} Label of the item. - */ - get: function() { - return this.querySelector('filename-label').textContent; - } -}); - -/** - * @param {Element} li List item element. - * @param {Entry} entry File entry. - * @param {FileGrid} grid Owner. - */ -FileGrid.Item.decorate = function(li, entry, grid) { - li.__proto__ = FileGrid.Item.prototype; - FileGrid.decorateThumbnail(li, entry, grid.metadataCache_, true); - - // Override the default role 'listitem' to 'option' to match the parent's - // role (listbox). - li.setAttribute('role', 'option'); -}; - -/** - * Sets the margin height for the transparent preview panel at the bottom. - * @param {number} margin Margin to be set in px. - */ -FileGrid.prototype.setBottomMarginForPanel = function(margin) { - // +20 bottom margin is needed to match the bottom margin size with the - // margin between its items. - this.style.paddingBottom = (margin + 20) + 'px'; - this.scrollBar_.setBottomMarginForPanel(margin); -}; - -/** - * Obtains if the drag selection should be start or not by referring the mouse - * event. - * @param {MouseEvent} event Drag start event. - * @return {boolean} True if the mouse is hit to the background of the list. - */ -FileGrid.prototype.shouldStartDragSelection = function(event) { - var pos = DragSelector.getScrolledPosition(this, event); - return this.getHitElements(pos.x, pos.y).length == 0; -}; - -/** - * Obtains the column/row index that the coordinate points. - * @param {number} coordinate Vertical/horizontal coodinate value that points - * column/row. - * @param {number} step Length from a column/row to the next one. - * @param {number} threshold Threshold that determinds whether 1 offset is added - * to the return value or not. This is used in order to handle the margin of - * column/row. - * @return {number} Index of hit column/row. - * @private - */ -FileGrid.prototype.getHitIndex_ = function(coordinate, step, threshold) { - var index = ~~(coordinate / step); - return (coordinate % step >= threshold) ? index + 1 : index; -}; - -/** - * Obtains the index list of elements that are hit by the point or the - * rectangle. - * - * We should match its argument interface with FileList.getHitElements. - * - * @param {number} x X coordinate value. - * @param {number} y Y coordinate value. - * @param {=number} opt_width Width of the coordinate. - * @param {=number} opt_height Height of the coordinate. - * @return {Array.<number>} Index list of hit elements. - */ -FileGrid.prototype.getHitElements = function(x, y, opt_width, opt_height) { - var currentSelection = []; - var right = x + (opt_width || 0); - var bottom = y + (opt_height || 0); - var itemMetrics = this.measureItem(); - var horizontalStartIndex = this.getHitIndex_( - x, itemMetrics.width, itemMetrics.width - itemMetrics.marginRight); - var horizontalEndIndex = Math.min(this.columns, this.getHitIndex_( - right, itemMetrics.width, itemMetrics.marginLeft)); - var verticalStartIndex = this.getHitIndex_( - y, itemMetrics.height, itemMetrics.height - itemMetrics.bottom); - var verticalEndIndex = this.getHitIndex_( - bottom, itemMetrics.height, itemMetrics.marginTop); - for (var verticalIndex = verticalStartIndex; - verticalIndex < verticalEndIndex; - verticalIndex++) { - var indexBase = this.getFirstItemInRow(verticalIndex); - for (var horizontalIndex = horizontalStartIndex; - horizontalIndex < horizontalEndIndex; - horizontalIndex++) { - var index = indexBase + horizontalIndex; - if (0 <= index && index < this.dataModel.length) - currentSelection.push(index); - } - } - return currentSelection; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/file_manager.js b/chromium/chrome/browser/resources/file_manager/foreground/js/file_manager.js deleted file mode 100644 index 201a4f6ad2d..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/file_manager.js +++ /dev/null @@ -1,3688 +0,0 @@ -// 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. - -'use strict'; - -/** - * FileManager constructor. - * - * FileManager objects encapsulate the functionality of the file selector - * dialogs, as well as the full screen file manager application (though the - * latter is not yet implemented). - * - * @constructor - */ -function FileManager() { - this.initializeQueue_ = new AsyncUtil.Group(); - - /** - * Current list type. - * @type {ListType} - * @private - */ - this.listType_ = null; - - /** - * Whether to suppress the focus moving or not. - * This is used to filter out focusing by mouse. - * @type {boolean} - * @private - */ - this.suppressFocus_ = false; - - /** - * SelectionHandler. - * @type {SelectionHandler} - * @private - */ - this.selectionHandler_ = null; -} - -/** - * Maximum delay in milliseconds for updating thumbnails in the bottom panel - * to mitigate flickering. If images load faster then the delay they replace - * old images smoothly. On the other hand we don't want to keep old images - * too long. - * - * @type {number} - * @const - */ -FileManager.THUMBNAIL_SHOW_DELAY = 100; - -FileManager.prototype = { - __proto__: cr.EventTarget.prototype, - get directoryModel() { - return this.directoryModel_; - }, - get navigationList() { - return this.navigationList_; - }, - get document() { - return this.document_; - }, - get fileTransferController() { - return this.fileTransferController_; - }, - get backgroundPage() { - return this.backgroundPage_; - }, - get volumeManager() { - return this.volumeManager_; - } -}; - -/** - * Unload the file manager. - * Used by background.js (when running in the packaged mode). - */ -function unload() { - fileManager.onBeforeUnload_(); - fileManager.onUnload_(); -} - -/** - * List of dialog types. - * - * Keep this in sync with FileManagerDialog::GetDialogTypeAsString, except - * FULL_PAGE which is specific to this code. - * - * @enum {string} - */ -var DialogType = { - SELECT_FOLDER: 'folder', - SELECT_UPLOAD_FOLDER: 'upload-folder', - SELECT_SAVEAS_FILE: 'saveas-file', - SELECT_OPEN_FILE: 'open-file', - SELECT_OPEN_MULTI_FILE: 'open-multi-file', - FULL_PAGE: 'full-page' -}; - -/** - * @param {string} type Dialog type. - * @return {boolean} Whether the type is modal. - */ -DialogType.isModal = function(type) { - return type == DialogType.SELECT_FOLDER || - type == DialogType.SELECT_UPLOAD_FOLDER || - type == DialogType.SELECT_SAVEAS_FILE || - type == DialogType.SELECT_OPEN_FILE || - type == DialogType.SELECT_OPEN_MULTI_FILE; -}; - -/** - * @param {string} type Dialog type. - * @return {boolean} Whether the type is open dialog. - */ -DialogType.isOpenDialog = function(type) { - return type == DialogType.SELECT_OPEN_FILE || - type == DialogType.SELECT_OPEN_MULTI_FILE; -}; - -/** - * @param {string} type Dialog type. - * @return {boolean} Whether the type is folder selection dialog. - */ -DialogType.isFolderDialog = function(type) { - return type == DialogType.SELECT_FOLDER || - type == DialogType.SELECT_UPLOAD_FOLDER; -}; - -/** - * Bottom margin of the list and tree for transparent preview panel. - * @const - */ -var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52; - -// Anonymous "namespace". -(function() { - - // Private variables and helper functions. - - /** - * Number of milliseconds in a day. - */ - var MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000; - - /** - * Some UI elements react on a single click and standard double click handling - * leads to confusing results. We ignore a second click if it comes soon - * after the first. - */ - var DOUBLE_CLICK_TIMEOUT = 200; - - /** - * Update the element to display the information about remaining space for - * the storage. - * @param {!Element} spaceInnerBar Block element for a percentage bar - * representing the remaining space. - * @param {!Element} spaceInfoLabel Inline element to contain the message. - * @param {!Element} spaceOuterBar Block element around the percentage bar. - */ - var updateSpaceInfo = function( - sizeStatsResult, spaceInnerBar, spaceInfoLabel, spaceOuterBar) { - spaceInnerBar.removeAttribute('pending'); - if (sizeStatsResult) { - var sizeStr = util.bytesToString(sizeStatsResult.remainingSize); - spaceInfoLabel.textContent = strf('SPACE_AVAILABLE', sizeStr); - - var usedSpace = - sizeStatsResult.totalSize - sizeStatsResult.remainingSize; - spaceInnerBar.style.width = - (100 * usedSpace / sizeStatsResult.totalSize) + '%'; - - spaceOuterBar.hidden = false; - } else { - spaceOuterBar.hidden = true; - spaceInfoLabel.textContent = str('FAILED_SPACE_INFO'); - } - }; - - // Public statics. - - FileManager.ListType = { - DETAIL: 'detail', - THUMBNAIL: 'thumb' - }; - - FileManager.prototype.initPreferences_ = function(callback) { - var group = new AsyncUtil.Group(); - - // DRIVE preferences should be initialized before creating DirectoryModel - // to rebuild the roots list. - group.add(this.getPreferences_.bind(this)); - - // Get startup preferences. - this.viewOptions_ = {}; - group.add(function(done) { - util.platform.getPreference(this.startupPrefName_, function(value) { - // Load the global default options. - try { - this.viewOptions_ = JSON.parse(value); - } catch (ignore) {} - // Override with window-specific options. - if (window.appState && window.appState.viewOptions) { - for (var key in window.appState.viewOptions) { - if (window.appState.viewOptions.hasOwnProperty(key)) - this.viewOptions_[key] = window.appState.viewOptions[key]; - } - } - done(); - }.bind(this)); - }.bind(this)); - - // Get the command line option. - group.add(function(done) { - chrome.commandLinePrivate.hasSwitch( - 'file-manager-show-checkboxes', function(flag) { - this.showCheckboxes_ = flag; - done(); - }.bind(this)); - }.bind(this)); - - // TODO(yoshiki): Remove the flag when the feature is launched. - this.enableExperimentalWebstoreIntegration_ = true; - - group.run(callback); - }; - - /** - * One time initialization for the file system and related things. - * - * @param {function()} callback Completion callback. - * @private - */ - FileManager.prototype.initFileSystemUI_ = function(callback) { - this.table_.startBatchUpdates(); - this.grid_.startBatchUpdates(); - - this.initFileList_(); - this.setupCurrentDirectory_(); - - // PyAuto tests monitor this state by polling this variable - this.__defineGetter__('workerInitialized_', function() { - return this.metadataCache_.isInitialized(); - }.bind(this)); - - this.initDateTimeFormatters_(); - - var self = this; - - // Get the 'allowRedeemOffers' preference before launching - // FileListBannerController. - this.getPreferences_(function(pref) { - /** @type {boolean} */ - var showOffers = pref['allowRedeemOffers']; - self.bannersController_ = new FileListBannerController( - self.directoryModel_, self.volumeManager_, self.document_, - showOffers); - self.bannersController_.addEventListener('relayout', - self.onResize_.bind(self)); - }); - - var dm = this.directoryModel_; - dm.addEventListener('directory-changed', - this.onDirectoryChanged_.bind(this)); - dm.addEventListener('begin-update-files', function() { - self.currentList_.startBatchUpdates(); - }); - dm.addEventListener('end-update-files', function() { - self.restoreItemBeingRenamed_(); - self.currentList_.endBatchUpdates(); - }); - dm.addEventListener('scan-started', this.onScanStarted_.bind(this)); - dm.addEventListener('scan-completed', this.onScanCompleted_.bind(this)); - dm.addEventListener('scan-failed', this.onScanCancelled_.bind(this)); - dm.addEventListener('scan-cancelled', this.onScanCancelled_.bind(this)); - dm.addEventListener('scan-updated', this.onScanUpdated_.bind(this)); - dm.addEventListener('rescan-completed', - this.onRescanCompleted_.bind(this)); - - this.directoryTree_.addEventListener('change', function() { - this.ensureDirectoryTreeItemNotBehindPreviewPanel_(); - }.bind(this)); - - var stateChangeHandler = - this.onPreferencesChanged_.bind(this); - chrome.fileBrowserPrivate.onPreferencesChanged.addListener( - stateChangeHandler); - stateChangeHandler(); - - var driveConnectionChangedHandler = - this.onDriveConnectionChanged_.bind(this); - this.volumeManager_.addEventListener('drive-connection-changed', - driveConnectionChangedHandler); - driveConnectionChangedHandler(); - - // Set the initial focus. - this.refocus(); - // Set it as a fallback when there is no focus. - this.document_.addEventListener('focusout', function(e) { - setTimeout(function() { - // When there is no focus, the active element is the <body>. - if (this.document_.activeElement == this.document_.body) - this.refocus(); - }.bind(this), 0); - }.bind(this)); - - this.initDataTransferOperations_(); - - this.initContextMenus_(); - this.initCommands_(); - - this.updateFileTypeFilter_(); - - this.selectionHandler_.onFileSelectionChanged(); - - this.table_.endBatchUpdates(); - this.grid_.endBatchUpdates(); - - callback(); - }; - - /** - * If |item| in the directory tree is behind the preview panel, scrolls up the - * parent view and make the item visible. This should be called when: - * - the selected item is changed in the directory tree. - * - the visibility of the the preview panel is changed. - * - * @private - */ - FileManager.prototype.ensureDirectoryTreeItemNotBehindPreviewPanel_ = - function() { - var selectedSubTree = this.directoryTree_.selectedItem; - if (!selectedSubTree) - return; - var item = selectedSubTree.rowElement; - var parentView = this.directoryTree_; - - var itemRect = item.getBoundingClientRect(); - if (!itemRect) - return; - - var listRect = parentView.getBoundingClientRect(); - if (!listRect) - return; - - var previewPanel = this.dialogDom_.querySelector('.preview-panel'); - var previewPanelRect = previewPanel.getBoundingClientRect(); - var panelHeight = previewPanelRect ? previewPanelRect.height : 0; - - var itemBottom = itemRect.bottom; - var listBottom = listRect.bottom - panelHeight; - - if (itemBottom > listBottom) { - var scrollOffset = itemBottom - listBottom; - parentView.scrollTop += scrollOffset; - } - }; - - /** - * @private - */ - FileManager.prototype.initDateTimeFormatters_ = function() { - var use12hourClock = !this.preferences_['use24hourClock']; - this.table_.setDateTimeFormat(use12hourClock); - }; - - /** - * @private - */ - FileManager.prototype.initDataTransferOperations_ = function() { - this.fileOperationManager_ = FileOperationManagerWrapper.getInstance( - this.backgroundPage_); - - // CopyManager are required for 'Delete' operation in - // Open and Save dialogs. But drag-n-drop and copy-paste are not needed. - if (this.dialogType != DialogType.FULL_PAGE) return; - - // TODO(hidehiko): Extract FileOperationManager related code from - // FileManager to simplify it. - this.onCopyProgressBound_ = this.onCopyProgress_.bind(this); - this.fileOperationManager_.addEventListener( - 'copy-progress', this.onCopyProgressBound_); - - this.onEntryChangedBound_ = this.onEntryChanged_.bind(this); - this.fileOperationManager_.addEventListener( - 'entry-changed', this.onEntryChangedBound_); - - var controller = this.fileTransferController_ = - new FileTransferController(this.document_, - this.fileOperationManager_, - this.metadataCache_, - this.directoryModel_); - controller.attachDragSource(this.table_.list); - controller.attachFileListDropTarget(this.table_.list); - controller.attachDragSource(this.grid_); - controller.attachFileListDropTarget(this.grid_); - controller.attachTreeDropTarget(this.directoryTree_); - controller.attachNavigationListDropTarget(this.navigationList_, true); - controller.attachCopyPasteHandlers(); - controller.addEventListener('selection-copied', - this.blinkSelection.bind(this)); - controller.addEventListener('selection-cut', - this.blinkSelection.bind(this)); - }; - - /** - * One-time initialization of context menus. - * @private - */ - FileManager.prototype.initContextMenus_ = function() { - this.fileContextMenu_ = this.dialogDom_.querySelector('#file-context-menu'); - cr.ui.Menu.decorate(this.fileContextMenu_); - - cr.ui.contextMenuHandler.setContextMenu(this.grid_, this.fileContextMenu_); - cr.ui.contextMenuHandler.setContextMenu(this.table_.querySelector('.list'), - this.fileContextMenu_); - cr.ui.contextMenuHandler.setContextMenu( - this.document_.querySelector('.drive-welcome.page'), - this.fileContextMenu_); - - this.rootsContextMenu_ = - this.dialogDom_.querySelector('#roots-context-menu'); - cr.ui.Menu.decorate(this.rootsContextMenu_); - this.navigationList_.setContextMenu(this.rootsContextMenu_); - - this.directoryTreeContextMenu_ = - this.dialogDom_.querySelector('#directory-tree-context-menu'); - cr.ui.Menu.decorate(this.directoryTreeContextMenu_); - this.directoryTree_.contextMenuForSubitems = this.directoryTreeContextMenu_; - - this.textContextMenu_ = - this.dialogDom_.querySelector('#text-context-menu'); - cr.ui.Menu.decorate(this.textContextMenu_); - - this.gearButton_ = this.dialogDom_.querySelector('#gear-button'); - this.gearButton_.addEventListener('menushow', - this.refreshRemainingSpace_.bind(this, - false /* Without loading caption. */)); - this.dialogDom_.querySelector('#gear-menu').menuItemSelector = - 'menuitem, hr'; - cr.ui.decorate(this.gearButton_, cr.ui.MenuButton); - - if (this.dialogType == DialogType.FULL_PAGE) { - // This is to prevent the buttons from stealing focus on mouse down. - var preventFocus = function(event) { - event.preventDefault(); - }; - - var maximizeButton = this.dialogDom_.querySelector('#maximize-button'); - maximizeButton.addEventListener('click', this.onMaximize.bind(this)); - maximizeButton.addEventListener('mousedown', preventFocus); - - var closeButton = this.dialogDom_.querySelector('#close-button'); - closeButton.addEventListener('click', this.onClose.bind(this)); - closeButton.addEventListener('mousedown', preventFocus); - } - - this.syncButton.checkable = true; - this.hostedButton.checkable = true; - this.detailViewButton_.checkable = true; - this.thumbnailViewButton_.checkable = true; - - if (util.platform.runningInBrowser()) { - // Suppresses the default context menu. - this.dialogDom_.addEventListener('contextmenu', function(e) { - e.preventDefault(); - e.stopPropagation(); - }); - } - }; - - FileManager.prototype.onMaximize = function() { - var appWindow = chrome.app.window.current(); - if (appWindow.isMaximized()) - appWindow.restore(); - else - appWindow.maximize(); - }; - - FileManager.prototype.onClose = function() { - window.close(); - }; - - /** - * One-time initialization of commands. - * @private - */ - FileManager.prototype.initCommands_ = function() { - this.commandHandler = new CommandHandler(this); - - // TODO(hirono): Move the following block to the UI part. - var commandButtons = this.dialogDom_.querySelectorAll('button[command]'); - for (var j = 0; j < commandButtons.length; j++) - CommandButton.decorate(commandButtons[j]); - - var inputs = this.dialogDom_.querySelectorAll( - 'input[type=text], input[type=search], textarea'); - for (var i = 0; i < inputs.length; i++) { - cr.ui.contextMenuHandler.setContextMenu(inputs[i], this.textContextMenu_); - this.registerInputCommands_(inputs[i]); - } - - cr.ui.contextMenuHandler.setContextMenu(this.renameInput_, - this.textContextMenu_); - this.registerInputCommands_(this.renameInput_); - this.document_.addEventListener('command', - this.setNoHover_.bind(this, true)); - }; - - /** - * Registers cut, copy, paste and delete commands on input element. - * - * @param {Node} node Text input element to register on. - * @private - */ - FileManager.prototype.registerInputCommands_ = function(node) { - CommandUtil.forceDefaultHandler(node, 'cut'); - CommandUtil.forceDefaultHandler(node, 'copy'); - CommandUtil.forceDefaultHandler(node, 'paste'); - CommandUtil.forceDefaultHandler(node, 'delete'); - node.addEventListener('keydown', function(e) { - var key = util.getKeyModifiers(e) + e.keyCode; - if (key === '190' /* '/' */ || key === '191' /* '.' */) { - // If this key event is propagated, this is handled search command, - // which calls 'preventDefault' method. - e.stopPropagation(); - } - }); - }; - - /** - * Entry point of the initialization. - * This method is called from main.js. - */ - FileManager.prototype.initializeCore = function() { - this.initializeQueue_.add(this.initGeneral_.bind(this), [], 'initGeneral'); - this.initializeQueue_.add(this.initBackgroundPage_.bind(this), - [], 'initBackgroundPage'); - this.initializeQueue_.add(this.initPreferences_.bind(this), - ['initGeneral'], 'initPreferences'); - this.initializeQueue_.add(this.initVolumeManager_.bind(this), - ['initGeneral', 'initBackgroundPage'], - 'initVolumeManager'); - - this.initializeQueue_.run(); - }; - - FileManager.prototype.initializeUI = function(dialogDom, callback) { - this.dialogDom_ = dialogDom; - this.document_ = this.dialogDom_.ownerDocument; - - this.initializeQueue_.add( - this.initEssentialUI_.bind(this), - ['initGeneral', 'initBackgroundPage'], - 'initEssentialUI'); - this.initializeQueue_.add(this.initAdditionalUI_.bind(this), - ['initEssentialUI'], 'initAdditionalUI'); - this.initializeQueue_.add( - this.initFileSystemUI_.bind(this), - ['initAdditionalUI', 'initPreferences'], 'initFileSystemUI'); - - // Run again just in case if all pending closures have completed and the - // queue has stopped and monitor the completion. - this.initializeQueue_.run(callback); - }; - - /** - * Initializes general purpose basic things, which are used by other - * initializing methods. - * - * @param {function()} callback Completion callback. - * @private - */ - FileManager.prototype.initGeneral_ = function(callback) { - // Initialize the application state. - if (window.appState) { - this.params_ = window.appState.params || {}; - this.defaultPath = window.appState.defaultPath; - } else { - this.params_ = location.search ? - JSON.parse(decodeURIComponent(location.search.substr(1))) : - {}; - this.defaultPath = this.params_.defaultPath; - } - - // Initialize the member variables that depend this.params_. - this.dialogType = this.params_.type || DialogType.FULL_PAGE; - this.startupPrefName_ = 'file-manager-' + this.dialogType; - this.fileTypes_ = this.params_.typeList || []; - - callback(); - }; - - /** - * Initialize the background page. - * @param {function()} callback Completion callback. - * @private - */ - FileManager.prototype.initBackgroundPage_ = function(callback) { - chrome.runtime.getBackgroundPage(function(backgroundPage) { - this.backgroundPage_ = backgroundPage; - this.backgroundPage_.background.ready(function() { - loadTimeData.data = this.backgroundPage_.background.stringData; - callback(); - }.bind(this)); - }.bind(this)); - }; - - /** - * Initializes the VolumeManager instance. - * @param {function()} callback Completion callback. - * @private - */ - FileManager.prototype.initVolumeManager_ = function(callback) { - // Auto resolving to local path does not work for folders (e.g., dialog for - // loading unpacked extensions). - var noLocalPathResolution = DialogType.isFolderDialog(this.params_.type); - - // If this condition is false, VolumeManagerWrapper hides all drive - // related event and data, even if Drive is enabled on preference. - // In other words, even if Drive is disabled on preference but Files.app - // should show Drive when it is re-enabled, then the value should be set to - // true. - // Note that the Drive enabling preference change is listened by - // DriveIntegrationService, so here we don't need to take care about it. - var driveEnabled = - !noLocalPathResolution || !this.params_.shouldReturnLocalPath; - this.volumeManager_ = new VolumeManagerWrapper( - driveEnabled, this.backgroundPage_); - callback(); - }; - - /** - * One time initialization of the Files.app's essential UI elements. These - * elements will be shown to the user. Only visible elements should be - * initialized here. Any heavy operation should be avoided. Files.app's - * window is shown at the end of this routine. - * - * @param {function()} callback Completion callback. - * @private - */ - FileManager.prototype.initEssentialUI_ = function(callback) { - // Optional list of file types. - metrics.recordEnum('Create', this.dialogType, - [DialogType.SELECT_FOLDER, - DialogType.SELECT_UPLOAD_FOLDER, - DialogType.SELECT_SAVEAS_FILE, - DialogType.SELECT_OPEN_FILE, - DialogType.SELECT_OPEN_MULTI_FILE, - DialogType.FULL_PAGE]); - - // Create the metadata cache. - this.metadataCache_ = MetadataCache.createFull(); - - // Create the root view of FileManager. - this.ui_ = new FileManagerUI(this.dialogDom_, this.dialogType); - this.fileTypeSelector_ = this.ui_.fileTypeSelector; - this.okButton_ = this.ui_.okButton; - this.cancelButton_ = this.ui_.cancelButton; - - // Show the window as soon as the UI pre-initialization is done. - if (this.dialogType == DialogType.FULL_PAGE && - !util.platform.runningInBrowser()) { - chrome.app.window.current().show(); - setTimeout(callback, 100); // Wait until the animation is finished. - } else { - callback(); - } - }; - - /** - * One-time initialization of dialogs. - * @private - */ - FileManager.prototype.initDialogs_ = function() { - // Initialize the dialog. - this.ui_.initDialogs(); - FileManagerDialogBase.setFileManager(this); - - // Obtains the dialog instances from FileManagerUI. - // TODO(hirono): Remove the properties from the FileManager class. - this.error = this.ui_.errorDialog; - this.alert = this.ui_.alertDialog; - this.confirm = this.ui_.confirmDialog; - this.prompt = this.ui_.promptDialog; - this.shareDialog_ = this.ui_.shareDialog; - this.defaultTaskPicker = this.ui_.defaultTaskPicker; - this.suggestAppsDialog = this.ui_.suggestAppsDialog; - }; - - /** - * One-time initialization of various DOM nodes. Loads the additional DOM - * elements visible to the user. Initialize here elements, which are expensive - * or hidden in the beginning. - * - * @param {function()} callback Completion callback. - * @private - */ - FileManager.prototype.initAdditionalUI_ = function(callback) { - this.initDialogs_(); - this.ui_.initAdditionalUI(); - - this.dialogDom_.addEventListener('drop', function(e) { - // Prevent opening an URL by dropping it onto the page. - e.preventDefault(); - }); - - this.dialogDom_.addEventListener('click', - this.onExternalLinkClick_.bind(this)); - // Cache nodes we'll be manipulating. - var dom = this.dialogDom_; - - this.filenameInput_ = dom.querySelector('#filename-input-box input'); - this.taskItems_ = dom.querySelector('#tasks'); - - this.table_ = dom.querySelector('.detail-table'); - this.grid_ = dom.querySelector('.thumbnail-grid'); - this.spinner_ = dom.querySelector('#list-container > .spinner-layer'); - this.showSpinner_(true); - - // Check the option to hide the selecting checkboxes. - this.table_.showCheckboxes = this.showCheckboxes_; - - var fullPage = this.dialogType == DialogType.FULL_PAGE; - FileTable.decorate(this.table_, this.metadataCache_, fullPage); - FileGrid.decorate(this.grid_, this.metadataCache_); - - this.previewPanel_ = new PreviewPanel( - dom.querySelector('.preview-panel'), - DialogType.isOpenDialog(this.dialogType) ? - PreviewPanel.VisibilityType.ALWAYS_VISIBLE : - PreviewPanel.VisibilityType.AUTO, - this.metadataCache_, - this.volumeManager_); - this.previewPanel_.addEventListener( - PreviewPanel.Event.VISIBILITY_CHANGE, - this.onPreviewPanelVisibilityChange_.bind(this)); - this.previewPanel_.initialize(); - - this.previewPanel_.breadcrumbs.addEventListener( - 'pathclick', this.onBreadcrumbClick_.bind(this)); - - // Initialize progress center panel. - this.progressCenterPanel_ = new ProgressCenterPanel( - dom.querySelector('#progress-center')); - this.backgroundPage_.background.progressCenter.addPanel( - this.progressCenterPanel_); - - this.document_.addEventListener('keydown', this.onKeyDown_.bind(this)); - - // This capturing event is only used to distinguish focusing using - // keyboard from focusing using mouse. - this.document_.addEventListener('mousedown', function() { - this.suppressFocus_ = true; - }.bind(this), true); - - this.renameInput_ = this.document_.createElement('input'); - this.renameInput_.className = 'rename'; - - this.renameInput_.addEventListener( - 'keydown', this.onRenameInputKeyDown_.bind(this)); - this.renameInput_.addEventListener( - 'blur', this.onRenameInputBlur_.bind(this)); - - // TODO(hirono): Rename the handler after creating the DialogFooter class. - this.filenameInput_.addEventListener( - 'input', this.onFilenameInputInput_.bind(this)); - this.filenameInput_.addEventListener( - 'keydown', this.onFilenameInputKeyDown_.bind(this)); - this.filenameInput_.addEventListener( - 'focus', this.onFilenameInputFocus_.bind(this)); - - this.listContainer_ = this.dialogDom_.querySelector('#list-container'); - this.listContainer_.addEventListener( - 'keydown', this.onListKeyDown_.bind(this)); - this.listContainer_.addEventListener( - 'keypress', this.onListKeyPress_.bind(this)); - this.listContainer_.addEventListener( - 'mousemove', this.onListMouseMove_.bind(this)); - - this.okButton_.addEventListener('click', this.onOk_.bind(this)); - this.onCancelBound_ = this.onCancel_.bind(this); - this.cancelButton_.addEventListener('click', this.onCancelBound_); - - this.decorateSplitter( - this.dialogDom_.querySelector('#navigation-list-splitter')); - this.decorateSplitter( - this.dialogDom_.querySelector('#middlebar-splitter')); - - this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container'); - - this.syncButton = this.dialogDom_.querySelector('#drive-sync-settings'); - this.syncButton.addEventListener('click', this.onDrivePrefClick_.bind( - this, 'cellularDisabled', false /* not inverted */)); - - this.hostedButton = this.dialogDom_.querySelector('#drive-hosted-settings'); - this.hostedButton.addEventListener('click', this.onDrivePrefClick_.bind( - this, 'hostedFilesDisabled', true /* inverted */)); - - this.detailViewButton_ = - this.dialogDom_.querySelector('#detail-view'); - this.detailViewButton_.addEventListener('activate', - this.onDetailViewButtonClick_.bind(this)); - - this.thumbnailViewButton_ = - this.dialogDom_.querySelector('#thumbnail-view'); - this.thumbnailViewButton_.addEventListener('activate', - this.onThumbnailViewButtonClick_.bind(this)); - - cr.ui.ComboButton.decorate(this.taskItems_); - this.taskItems_.showMenu = function(shouldSetFocus) { - // Prevent the empty menu from opening. - if (!this.menu.length) - return; - cr.ui.ComboButton.prototype.showMenu.call(this, shouldSetFocus); - }; - this.taskItems_.addEventListener('select', - this.onTaskItemClicked_.bind(this)); - - this.dialogDom_.ownerDocument.defaultView.addEventListener( - 'resize', this.onResize_.bind(this)); - - this.filePopup_ = null; - - this.searchBoxWrapper_ = this.ui_.searchBox.element; - this.searchBox_ = this.ui_.searchBox.inputElement; - this.searchBox_.addEventListener( - 'input', this.onSearchBoxUpdate_.bind(this)); - this.ui_.searchBox.clearButton.addEventListener( - 'click', this.onSearchClearButtonClick_.bind(this)); - - this.lastSearchQuery_ = ''; - - this.autocompleteList_ = this.ui_.searchBox.autocompleteList; - this.autocompleteList_.requestSuggestions = - this.requestAutocompleteSuggestions_.bind(this); - - // Instead, open the suggested item when Enter key is pressed or - // mouse-clicked. - this.autocompleteList_.handleEnterKeydown = function(event) { - this.openAutocompleteSuggestion_(); - this.lastAutocompleteQuery_ = ''; - this.autocompleteList_.suggestions = []; - }.bind(this); - this.autocompleteList_.addEventListener('mousedown', function(event) { - this.openAutocompleteSuggestion_(); - this.lastAutocompleteQuery_ = ''; - this.autocompleteList_.suggestions = []; - }.bind(this)); - - this.defaultActionMenuItem_ = - this.dialogDom_.querySelector('#default-action'); - - this.openWithCommand_ = - this.dialogDom_.querySelector('#open-with'); - - this.driveBuyMoreStorageCommand_ = - this.dialogDom_.querySelector('#drive-buy-more-space'); - - this.defaultActionMenuItem_.addEventListener('click', - this.dispatchSelectionAction_.bind(this)); - - this.initFileTypeFilter_(); - - util.addIsFocusedMethod(); - - // Populate the static localized strings. - i18nTemplate.process(this.document_, loadTimeData); - - // Arrange the file list. - this.table_.normalizeColumns(); - this.table_.redraw(); - - callback(); - }; - - /** - * @private - */ - FileManager.prototype.onBreadcrumbClick_ = function(event) { - // TODO(hirono): Use directoryModel#changeDirectoryEntry after implementing - // it. - if (event.entry === RootType.DRIVE_SHARED_WITH_ME) - this.directoryModel_.changeDirectory(RootDirectory.DRIVE_SHARED_WITH_ME); - else - this.directoryModel_.changeDirectory(event.entry.fullPath); - }; - - /** - * Constructs table and grid (heavy operation). - * @private - **/ - FileManager.prototype.initFileList_ = function() { - // Always sharing the data model between the detail/thumb views confuses - // them. Instead we maintain this bogus data model, and hook it up to the - // view that is not in use. - this.emptyDataModel_ = new cr.ui.ArrayDataModel([]); - this.emptySelectionModel_ = new cr.ui.ListSelectionModel(); - - var singleSelection = - this.dialogType == DialogType.SELECT_OPEN_FILE || - this.dialogType == DialogType.SELECT_FOLDER || - this.dialogType == DialogType.SELECT_UPLOAD_FOLDER || - this.dialogType == DialogType.SELECT_SAVEAS_FILE; - - this.fileFilter_ = new FileFilter( - this.metadataCache_, - false /* Don't show dot files by default. */); - - this.fileWatcher_ = new FileWatcher(this.metadataCache_); - this.fileWatcher_.addEventListener( - 'watcher-metadata-changed', - this.onWatcherMetadataChanged_.bind(this)); - - this.directoryModel_ = new DirectoryModel( - singleSelection, - this.fileFilter_, - this.fileWatcher_, - this.metadataCache_, - this.volumeManager_); - - this.folderShortcutsModel_ = new FolderShortcutsDataModel(); - - this.selectionHandler_ = new FileSelectionHandler(this); - - var dataModel = this.directoryModel_.getFileList(); - - this.table_.setupCompareFunctions(dataModel); - - dataModel.addEventListener('permuted', - this.updateStartupPrefs_.bind(this)); - - this.directoryModel_.getFileListSelection().addEventListener('change', - this.selectionHandler_.onFileSelectionChanged.bind( - this.selectionHandler_)); - - this.initList_(this.grid_); - this.initList_(this.table_.list); - - var fileListFocusBound = this.onFileListFocus_.bind(this); - var fileListBlurBound = this.onFileListBlur_.bind(this); - - this.table_.list.addEventListener('focus', fileListFocusBound); - this.grid_.addEventListener('focus', fileListFocusBound); - - this.table_.list.addEventListener('blur', fileListBlurBound); - this.grid_.addEventListener('blur', fileListBlurBound); - - var dragStartBound = this.onDragStart_.bind(this); - this.table_.list.addEventListener('dragstart', dragStartBound); - this.grid_.addEventListener('dragstart', dragStartBound); - - var dragEndBound = this.onDragEnd_.bind(this); - this.table_.list.addEventListener('dragend', dragEndBound); - this.grid_.addEventListener('dragend', dragEndBound); - // This event is published by DragSelector because drag end event is not - // published at the end of drag selection. - this.table_.list.addEventListener('dragselectionend', dragEndBound); - this.grid_.addEventListener('dragselectionend', dragEndBound); - - // TODO(mtomasz, yoshiki): Create navigation list earlier, and here just - // attach the directory model. - this.initNavigationList_(); - - this.table_.addEventListener('column-resize-end', - this.updateStartupPrefs_.bind(this)); - - // Restore preferences. - this.directoryModel_.sortFileList( - this.viewOptions_.sortField || 'modificationTime', - this.viewOptions_.sortDirection || 'desc'); - if (this.viewOptions_.columns) { - var cm = this.table_.columnModel; - for (var i = 0; i < cm.totalSize; i++) { - if (this.viewOptions_.columns[i] > 0) - cm.setWidth(i, this.viewOptions_.columns[i]); - } - } - this.setListType(this.viewOptions_.listType || FileManager.ListType.DETAIL); - - this.textSearchState_ = {text: '', date: new Date()}; - this.closeOnUnmount_ = (this.params_.action == 'auto-open'); - - if (this.closeOnUnmount_) { - this.volumeManager_.addEventListener('externally-unmounted', - this.onExternallyUnmounted_.bind(this)); - } - - // Update metadata to change 'Today' and 'Yesterday' dates. - var today = new Date(); - today.setHours(0); - today.setMinutes(0); - today.setSeconds(0); - today.setMilliseconds(0); - setTimeout(this.dailyUpdateModificationTime_.bind(this), - today.getTime() + MILLISECONDS_IN_DAY - Date.now() + 1000); - }; - - /** - * @private - */ - FileManager.prototype.initNavigationList_ = function() { - this.directoryTree_ = this.dialogDom_.querySelector('#directory-tree'); - DirectoryTree.decorate(this.directoryTree_, this.directoryModel_); - - this.navigationList_ = this.dialogDom_.querySelector('#navigation-list'); - NavigationList.decorate(this.navigationList_, - this.volumeManager_, - this.directoryModel_); - this.navigationList_.fileManager = this; - this.navigationList_.dataModel = new NavigationListModel( - this.volumeManager_, this.folderShortcutsModel_); - }; - - /** - * @private - */ - FileManager.prototype.updateMiddleBarVisibility_ = function() { - var entry = this.directoryModel_.getCurrentDirEntry(); - if (!entry) - return; - - var driveVolume = this.volumeManager_.getVolumeInfo(entry); - var visible = - DirectoryTreeUtil.isEligiblePathForDirectoryTree(entry.fullPath) && - driveVolume && !driveVolume.error; - this.dialogDom_. - querySelector('.dialog-middlebar-contents').hidden = !visible; - this.dialogDom_.querySelector('#middlebar-splitter').hidden = !visible; - this.onResize_(); - }; - - /** - * @private - */ - FileManager.prototype.updateStartupPrefs_ = function() { - var sortStatus = this.directoryModel_.getFileList().sortStatus; - var prefs = { - sortField: sortStatus.field, - sortDirection: sortStatus.direction, - columns: [], - listType: this.listType_ - }; - var cm = this.table_.columnModel; - for (var i = 0; i < cm.totalSize; i++) { - prefs.columns.push(cm.getWidth(i)); - } - // Save the global default. - util.platform.setPreference(this.startupPrefName_, JSON.stringify(prefs)); - - // Save the window-specific preference. - if (window.appState) { - window.appState.viewOptions = prefs; - util.saveAppState(); - } - }; - - FileManager.prototype.refocus = function() { - var targetElement; - if (this.dialogType == DialogType.SELECT_SAVEAS_FILE) - targetElement = this.filenameInput_; - else - targetElement = this.currentList_; - - // Hack: if the tabIndex is disabled, we can assume a modal dialog is - // shown. Focus to a button on the dialog instead. - if (!targetElement.hasAttribute('tabIndex') || targetElement.tabIndex == -1) - targetElement = document.querySelector('button:not([tabIndex="-1"])'); - - if (targetElement) - targetElement.focus(); - }; - - /** - * File list focus handler. Used to select the top most element on the list - * if nothing was selected. - * - * @private - */ - FileManager.prototype.onFileListFocus_ = function() { - // Do not select default item if focused using mouse. - if (this.suppressFocus_) - return; - - var selection = this.getSelection(); - if (!selection || selection.totalCount != 0) - return; - - this.directoryModel_.selectIndex(0); - }; - - /** - * File list blur handler. - * - * @private - */ - FileManager.prototype.onFileListBlur_ = function() { - this.suppressFocus_ = false; - }; - - /** - * Index of selected item in the typeList of the dialog params. - * - * @return {number} 1-based index of selected type or 0 if no type selected. - * @private - */ - FileManager.prototype.getSelectedFilterIndex_ = function() { - var index = Number(this.fileTypeSelector_.selectedIndex); - if (index < 0) // Nothing selected. - return 0; - if (this.params_.includeAllFiles) // Already 1-based. - return index; - return index + 1; // Convert to 1-based; - }; - - FileManager.prototype.setListType = function(type) { - if (type && type == this.listType_) - return; - - this.table_.list.startBatchUpdates(); - this.grid_.startBatchUpdates(); - - // TODO(dzvorygin): style.display and dataModel setting order shouldn't - // cause any UI bugs. Currently, the only right way is first to set display - // style and only then set dataModel. - - if (type == FileManager.ListType.DETAIL) { - this.table_.dataModel = this.directoryModel_.getFileList(); - this.table_.selectionModel = this.directoryModel_.getFileListSelection(); - this.table_.hidden = false; - this.grid_.hidden = true; - this.grid_.selectionModel = this.emptySelectionModel_; - this.grid_.dataModel = this.emptyDataModel_; - this.table_.hidden = false; - /** @type {cr.ui.List} */ - this.currentList_ = this.table_.list; - this.detailViewButton_.setAttribute('checked', ''); - this.thumbnailViewButton_.removeAttribute('checked'); - this.detailViewButton_.setAttribute('disabled', ''); - this.thumbnailViewButton_.removeAttribute('disabled'); - } else if (type == FileManager.ListType.THUMBNAIL) { - this.grid_.dataModel = this.directoryModel_.getFileList(); - this.grid_.selectionModel = this.directoryModel_.getFileListSelection(); - this.grid_.hidden = false; - this.table_.hidden = true; - this.table_.selectionModel = this.emptySelectionModel_; - this.table_.dataModel = this.emptyDataModel_; - this.grid_.hidden = false; - /** @type {cr.ui.List} */ - this.currentList_ = this.grid_; - this.thumbnailViewButton_.setAttribute('checked', ''); - this.detailViewButton_.removeAttribute('checked'); - this.thumbnailViewButton_.setAttribute('disabled', ''); - this.detailViewButton_.removeAttribute('disabled'); - } else { - throw new Error('Unknown list type: ' + type); - } - - this.listType_ = type; - this.updateStartupPrefs_(); - this.onResize_(); - - this.table_.list.endBatchUpdates(); - this.grid_.endBatchUpdates(); - }; - - /** - * Initialize the file list table or grid. - * - * @param {cr.ui.List} list The list. - * @private - */ - FileManager.prototype.initList_ = function(list) { - // Overriding the default role 'list' to 'listbox' for better accessibility - // on ChromeOS. - list.setAttribute('role', 'listbox'); - list.addEventListener('click', this.onDetailClick_.bind(this)); - list.id = 'file-list'; - }; - - /** - * @private - */ - FileManager.prototype.onCopyProgress_ = function(event) { - if (event.reason == 'ERROR' && - event.error.code == util.FileOperationErrorType.FILESYSTEM_ERROR && - event.error.data.toDrive && - event.error.data.code == FileError.QUOTA_EXCEEDED_ERR) { - this.alert.showHtml( - strf('DRIVE_SERVER_OUT_OF_SPACE_HEADER'), - strf('DRIVE_SERVER_OUT_OF_SPACE_MESSAGE', - decodeURIComponent( - event.error.data.sourceFileUrl.split('/').pop()), - str('GOOGLE_DRIVE_BUY_STORAGE_URL'))); - } - }; - - /** - * Handler of file manager operations. Called when an entry has been - * changed. - * This updates directory model to reflect operation result immediately (not - * waiting for directory update event). Also, preloads thumbnails for the - * images of new entries. - * See also FileOperationManager.EventRouter. - * - * @param {Event} event An event for the entry change. - * @private - */ - FileManager.prototype.onEntryChanged_ = function(event) { - var kind = event.kind; - var entry = event.entry; - this.directoryModel_.onEntryChanged(kind, entry); - this.selectionHandler_.onFileSelectionChanged(); - - if (kind == util.EntryChangedKind.CREATE && FileType.isImage(entry)) { - // Preload a thumbnail if the new copied entry an image. - var metadata = entry.getMetadata(function(metadata) { - var url = entry.toURL(); - var thumbnailLoader_ = new ThumbnailLoader( - url, - ThumbnailLoader.LoaderType.CANVAS, - metadata, - undefined, // Media type. - FileType.isOnDrive(url) ? - ThumbnailLoader.UseEmbedded.USE_EMBEDDED : - ThumbnailLoader.UseEmbedded.NO_EMBEDDED, - 10); // Very low priority. - thumbnailLoader_.loadDetachedImage(function(success) {}); - }); - } - }; - - /** - * Fills the file type list or hides it. - * @private - */ - FileManager.prototype.initFileTypeFilter_ = function() { - if (this.params_.includeAllFiles) { - var option = this.document_.createElement('option'); - option.innerText = str('ALL_FILES_FILTER'); - this.fileTypeSelector_.appendChild(option); - option.value = 0; - } - - for (var i = 0; i < this.fileTypes_.length; i++) { - var fileType = this.fileTypes_[i]; - var option = this.document_.createElement('option'); - var description = fileType.description; - if (!description) { - // See if all the extensions in the group have the same description. - for (var j = 0; j != fileType.extensions.length; j++) { - var currentDescription = - FileType.getTypeString('.' + fileType.extensions[j]); - if (!description) // Set the first time. - description = currentDescription; - else if (description != currentDescription) { - // No single description, fall through to the extension list. - description = null; - break; - } - } - - if (!description) - // Convert ['jpg', 'png'] to '*.jpg, *.png'. - description = fileType.extensions.map(function(s) { - return '*.' + s; - }).join(', '); - } - option.innerText = description; - - option.value = i + 1; - - if (fileType.selected) - option.selected = true; - - this.fileTypeSelector_.appendChild(option); - } - - var options = this.fileTypeSelector_.querySelectorAll('option'); - if (options.length >= 2) { - // There is in fact no choice, show the selector. - this.fileTypeSelector_.hidden = false; - - this.fileTypeSelector_.addEventListener('change', - this.updateFileTypeFilter_.bind(this)); - } - }; - - /** - * Filters file according to the selected file type. - * @private - */ - FileManager.prototype.updateFileTypeFilter_ = function() { - this.fileFilter_.removeFilter('fileType'); - var selectedIndex = this.getSelectedFilterIndex_(); - if (selectedIndex > 0) { // Specific filter selected. - var regexp = new RegExp('.*(' + - this.fileTypes_[selectedIndex - 1].extensions.join('|') + ')$', 'i'); - var filter = function(entry) { - return entry.isDirectory || regexp.test(entry.name); - }; - this.fileFilter_.addFilter('fileType', filter); - } - }; - - /** - * Resize details and thumb views to fit the new window size. - * @private - */ - FileManager.prototype.onResize_ = function() { - if (this.listType_ == FileManager.ListType.THUMBNAIL) - this.grid_.relayout(); - else - this.table_.relayout(); - - // May not be available during initialization. - if (this.directoryTree_) - this.directoryTree_.relayout(); - - // TODO(mtomasz, yoshiki): Initialize navigation list earlier, before - // file system is available. - if (this.navigationList_) - this.navigationList_.redraw(); - - this.ui_.searchBox.updateSizeRelatedStyle(); - - this.previewPanel_.breadcrumbs.truncate(); - }; - - /** - * Handles local metadata changes in the currect directory. - * @param {Event} event Change event. - * @private - */ - FileManager.prototype.onWatcherMetadataChanged_ = function(event) { - this.updateMetadataInUI_( - event.metadataType, event.entries, event.properties); - }; - - /** - * Resize details and thumb views to fit the new window size. - * @private - */ - FileManager.prototype.onPreviewPanelVisibilityChange_ = function() { - // This method may be called on initialization. Some object may not be - // initialized. - - var panelHeight = this.previewPanel_.visible ? - this.previewPanel_.height : 0; - if (this.grid_) - this.grid_.setBottomMarginForPanel(panelHeight); - if (this.table_) - this.table_.setBottomMarginForPanel(panelHeight); - - if (this.directoryTree_) { - this.directoryTree_.setBottomMarginForPanel(panelHeight); - this.ensureDirectoryTreeItemNotBehindPreviewPanel_(); - } - }; - - /** - * Invoked when the drag is started on the list or the grid. - * @private - */ - FileManager.prototype.onDragStart_ = function() { - // On open file dialog, the preview panel is always shown. - if (DialogType.isOpenDialog(this.dialogType)) - return; - this.previewPanel_.visibilityType = - PreviewPanel.VisibilityType.ALWAYS_HIDDEN; - }; - - /** - * Invoked when the drag is ended on the list or the grid. - * @private - */ - FileManager.prototype.onDragEnd_ = function() { - // On open file dialog, the preview panel is always shown. - if (DialogType.isOpenDialog(this.dialogType)) - return; - this.previewPanel_.visibilityType = PreviewPanel.VisibilityType.AUTO; - }; - - /** - * Restores current directory and may be a selected item after page load (or - * reload) or popping a state (after click on back/forward). defaultPath - * primarily is used with save/open dialogs. - * Default path may also contain a file name. Freshly opened file manager - * window has neither. - * - * @private - */ - FileManager.prototype.setupCurrentDirectory_ = function() { - var tracker = this.directoryModel_.createDirectoryChangeTracker(); - var queue = new AsyncUtil.Queue(); - - // Wait until the volume manager is initialized. - queue.run(function(callback) { - tracker.start(); - this.volumeManager_.ensureInitialized(callback); - }.bind(this)); - - // Resolve the default path. - var defaultFullPath; - var candidateFullPath; - var candidateEntry; - queue.run(function(callback) { - // Cancel this sequence if the current directory has already changed. - if (tracker.hasChanged) { - callback(); - return; - } - - // Resolve the absolute path in case only the file name or an empty string - // is passed. - if (!this.defaultPath) { - defaultFullPath = PathUtil.DEFAULT_MOUNT_POINT; - } else if (this.defaultPath.indexOf('/') === -1) { - // Path is a file name. - defaultFullPath = PathUtil.DEFAULT_MOUNT_POINT + '/' + this.defaultPath; - } else { - defaultFullPath = this.defaultPath; - } - - // If Drive is disabled but the path points to Drive's entry, fallback to - // DEFAULT_MOUNT_POINT. - if (PathUtil.isDriveBasedPath(defaultFullPath) && - !this.volumeManager_.getVolumeInfo(RootDirectory.DRIVE)) { - candidateFullPath = PathUtil.DEFAULT_MOUNT_POINT + '/' + - PathUtil.basename(defaultFullPath); - } else { - candidateFullPath = defaultFullPath; - } - - // If the path points a fake entry, use the entry directly. - var fakeEntries = DirectoryModel.FAKE_DRIVE_SPECIAL_SEARCH_ENTRIES; - for (var i = 0; i < fakeEntries.length; i++) { - if (candidateFullPath === fakeEntries[i].fullPath) { - candidateEntry = fakeEntries[i]; - callback(); - return; - } - } - - // Convert the path to the directory entry and an optional selection - // entry. - // TODO(hirono): There may be a race here. The path on Drive, may not - // be available yet. - this.volumeManager_.resolveAbsolutePath(candidateFullPath, - function(inEntry) { - candidateEntry = inEntry; - callback(); - }, function() { - callback(); - }); - }.bind(this)); - - // Check the obtained entry. - var nextCurrentDirEntry; - var selectionEntry = null; - var suggestedName = null; - var error = null; - queue.run(function(callback) { - // Cancel this sequence if the current directory has already changed. - if (tracker.hasChanged) { - callback(); - return; - } - - if (candidateEntry) { - // The entry is directory. Use it. - if (candidateEntry.isDirectory) { - nextCurrentDirEntry = candidateEntry; - callback(); - return; - } - // The entry exists, but it is not a directory. Therefore use a - // parent. - candidateEntry.getParent(function(parentEntry) { - nextCurrentDirEntry = parentEntry; - selectionEntry = candidateEntry; - callback(); - }, function() { - error = new Error('Unable to resolve parent for: ' + - candidateEntry.fullPath); - callback(); - }); - return; - } - - // If the entry doesn't exist, most probably because the path contains a - // suggested name. Therefore try to open its parent. However, the parent - // may also not exist. In such situation, fallback. - var pathNodes = candidateFullPath.split('/'); - var baseName = pathNodes.pop(); - var parentPath = pathNodes.join('/'); - this.volumeManager_.resolveAbsolutePath( - parentPath, - function(parentEntry) { - nextCurrentDirEntry = parentEntry; - suggestedName = baseName; - callback(); - }, - callback); // In case of an error, continue. - }.bind(this)); - - // If the directory is not set at this stage, fallback to the default - // mount point. - queue.run(function(callback) { - // Cancel this sequence if the current directory has already changed, - // or the next current directory is already set. - if (tracker.hasChanged || nextCurrentDirEntry) { - callback(); - return; - } - this.volumeManager_.resolveAbsolutePath( - PathUtil.DEFAULT_MOUNT_POINT, - function(fallbackEntry) { - nextCurrentDirEntry = fallbackEntry; - callback(); - }, - function() { - // Fallback directory not available? Throw an error. - error = new Error('Unable to resolve the fallback directory: ' + - PathUtil.DEFAULT_MOUNT_POINT); - callback(); - }); - }.bind(this)); - - queue.run(function(callback) { - // Check error. - if (error) { - callback(); - throw error; - } - // Check directory change. - tracker.stop(); - if (tracker.hasChanged) { - callback(); - return; - } - // Finish setup current directory. - this.finishSetupCurrentDirectory_( - nextCurrentDirEntry, selectionEntry, suggestedName); - callback(); - }.bind(this)); - }; - - /** - * @param {DirectoryEntry} directoryEntry Directory to be opened. - * @param {Entry=} opt_selectionEntry Entry to be selected. - * @param {string=} opt_suggestedName Suggested name for a non-existing\ - * selection. - * @private - */ - FileManager.prototype.finishSetupCurrentDirectory_ = function( - directoryEntry, opt_selectionEntry, opt_suggestedName) { - // Open the directory, and select the selection (if passed). - if (util.isFakeEntry(directoryEntry)) { - this.directoryModel_.specialSearch(directoryEntry.fullPath, ''); - } else { - this.directoryModel_.changeDirectoryEntry(directoryEntry, function() { - if (opt_selectionEntry) - this.directoryModel_.selectEntry(opt_selectionEntry); - }.bind(this)); - } - - if (this.dialogType == DialogType.FULL_PAGE) { - // In the FULL_PAGE mode if the restored path points to a file we might - // have to invoke a task after selecting it. - if (this.params_.action == 'select') - return; - - var task = null; - if (opt_suggestedName) { - // Non-existent file or a directory. - if (this.params_.gallery) { - // Reloading while the Gallery is open with empty or multiple - // selection. Open the Gallery when the directory is scanned. - task = function() { - new FileTasks(this, this.params_).openGallery([]); - }.bind(this); - } - } else if (opt_selectionEntry) { - // There is a file to be selected. It means, that we are recovering - // the Files app. - // We call the appropriate methods of FileTasks directly as we do - // not need any of the preparations that |execute| method does. - // TODO(mtomasz): Change Entry.fullPath to Entry. - var mediaType = FileType.getMediaType(opt_selectionEntry.fullPath); - if (mediaType == 'image' || mediaType == 'video') { - task = function() { - // TODO(mtomasz): Replace the url with an entry. - new FileTasks(this, this.params_).openGallery([opt_selectionEntry]); - }.bind(this); - } else if (mediaType == 'archive') { - task = function() { - new FileTasks(this, this.params_).mountArchives( - [opt_selectionEntry]); - }.bind(this); - } - } - - // If there is a task to be run, run it after the scan is completed. - if (task) { - var listener = function() { - this.directoryModel_.removeEventListener( - 'scan-completed', listener); - task(); - }.bind(this); - this.directoryModel_.addEventListener('scan-completed', listener); - } - } else if (this.dialogType == DialogType.SELECT_SAVEAS_FILE) { - this.filenameInput_.value = opt_suggestedName || ''; - this.selectDefaultPathInFilenameInput_(); - } - }; - - /** - * Unmounts device. - * @param {string} path Path to a volume to unmount. - */ - FileManager.prototype.unmountVolume = function(path) { - var onError = function(error) { - this.alert.showHtml('', str('UNMOUNT_FAILED')); - }; - this.volumeManager_.unmount(path, function() {}, onError.bind(this)); - }; - - /** - * @private - */ - FileManager.prototype.refreshCurrentDirectoryMetadata_ = function() { - var entries = this.directoryModel_.getFileList().slice(); - var directoryEntry = this.directoryModel_.getCurrentDirEntry(); - if (!directoryEntry) - return; - // We don't pass callback here. When new metadata arrives, we have an - // observer registered to update the UI. - - // TODO(dgozman): refresh content metadata only when modificationTime - // changed. - var isFakeEntry = util.isFakeEntry(directoryEntry); - var getEntries = (isFakeEntry ? [] : [directoryEntry]).concat(entries); - if (!isFakeEntry) - this.metadataCache_.clearRecursively(directoryEntry, '*'); - this.metadataCache_.get(getEntries, 'filesystem', null); - - if (this.isOnDrive()) - this.metadataCache_.get(getEntries, 'drive', null); - - var visibleItems = this.currentList_.items; - var visibleEntries = []; - for (var i = 0; i < visibleItems.length; i++) { - var index = this.currentList_.getIndexOfListItem(visibleItems[i]); - var entry = this.directoryModel_.getFileList().item(index); - // The following check is a workaround for the bug in list: sometimes item - // does not have listIndex, and therefore is not found in the list. - if (entry) visibleEntries.push(entry); - } - this.metadataCache_.get(visibleEntries, 'thumbnail', null); - }; - - /** - * @private - */ - FileManager.prototype.dailyUpdateModificationTime_ = function() { - var fileList = this.directoryModel_.getFileList(); - var entries = []; - for (var i = 0; i < fileList.length; i++) { - entries.push(fileList.item(i)); - } - this.metadataCache_.get( - entries, - 'filesystem', - this.updateMetadataInUI_.bind(this, 'filesystem', entries)); - - setTimeout(this.dailyUpdateModificationTime_.bind(this), - MILLISECONDS_IN_DAY); - }; - - /** - * @param {string} type Type of metadata changed. - * @param {Array.<Entry>} entries Array of entries. - * @param {Object.<string, Object>} props Map from entry URLs to metadata - * props. - * @private - */ - FileManager.prototype.updateMetadataInUI_ = function( - type, entries, properties) { - if (this.listType_ == FileManager.ListType.DETAIL) - this.table_.updateListItemsMetadata(type, properties); - else - this.grid_.updateListItemsMetadata(type, properties); - // TODO: update bottom panel thumbnails. - }; - - /** - * Restore the item which is being renamed while refreshing the file list. Do - * nothing if no item is being renamed or such an item disappeared. - * - * While refreshing file list it gets repopulated with new file entries. - * There is not a big difference whether DOM items stay the same or not. - * Except for the item that the user is renaming. - * - * @private - */ - FileManager.prototype.restoreItemBeingRenamed_ = function() { - if (!this.isRenamingInProgress()) - return; - - var dm = this.directoryModel_; - var leadIndex = dm.getFileListSelection().leadIndex; - if (leadIndex < 0) - return; - - var leadEntry = dm.getFileList().item(leadIndex); - if (this.renameInput_.currentEntry.fullPath != leadEntry.fullPath) - return; - - var leadListItem = this.findListItemForNode_(this.renameInput_); - if (this.currentList_ == this.table_.list) { - this.table_.updateFileMetadata(leadListItem, leadEntry); - } - this.currentList_.restoreLeadItem(leadListItem); - }; - - /** - * @return {boolean} True if the current directory content is from Google - * Drive. - */ - FileManager.prototype.isOnDrive = function() { - var rootType = this.directoryModel_.getCurrentRootType(); - return rootType === RootType.DRIVE || - rootType === RootType.DRIVE_SHARED_WITH_ME || - rootType === RootType.DRIVE_RECENT || - rootType === RootType.DRIVE_OFFLINE; - }; - - /** - * Overrides default handling for clicks on hyperlinks. - * In a packaged apps links with targer='_blank' open in a new tab by - * default, other links do not open at all. - * - * @param {Event} event Click event. - * @private - */ - FileManager.prototype.onExternalLinkClick_ = function(event) { - if (event.target.tagName != 'A' || !event.target.href) - return; - - if (this.dialogType != DialogType.FULL_PAGE) - this.onCancel_(); - }; - - /** - * Task combobox handler. - * - * @param {Object} event Event containing task which was clicked. - * @private - */ - FileManager.prototype.onTaskItemClicked_ = function(event) { - var selection = this.getSelection(); - if (!selection.tasks) return; - - if (event.item.task) { - // Task field doesn't exist on change-default dropdown item. - selection.tasks.execute(event.item.task.taskId); - } else { - var extensions = []; - - for (var i = 0; i < selection.entries.length; i++) { - var match = /\.(\w+)$/g.exec(selection.entries[i].toURL()); - if (match) { - var ext = match[1].toUpperCase(); - if (extensions.indexOf(ext) == -1) { - extensions.push(ext); - } - } - } - - var format = ''; - - if (extensions.length == 1) { - format = extensions[0]; - } - - // Change default was clicked. We should open "change default" dialog. - selection.tasks.showTaskPicker(this.defaultTaskPicker, - loadTimeData.getString('CHANGE_DEFAULT_MENU_ITEM'), - strf('CHANGE_DEFAULT_CAPTION', format), - this.onDefaultTaskDone_.bind(this)); - } - }; - - /** - * Sets the given task as default, when this task is applicable. - * - * @param {Object} task Task to set as default. - * @private - */ - FileManager.prototype.onDefaultTaskDone_ = function(task) { - // TODO(dgozman): move this method closer to tasks. - var selection = this.getSelection(); - chrome.fileBrowserPrivate.setDefaultTask( - task.taskId, - util.entriesToURLs(selection.entries), - selection.mimeTypes); - selection.tasks = new FileTasks(this); - selection.tasks.init(selection.entries, selection.mimeTypes); - selection.tasks.display(this.taskItems_); - this.refreshCurrentDirectoryMetadata_(); - this.selectionHandler_.onFileSelectionChanged(); - }; - - /** - * @private - */ - FileManager.prototype.onPreferencesChanged_ = function() { - var self = this; - this.getPreferences_(function(prefs) { - self.initDateTimeFormatters_(); - self.refreshCurrentDirectoryMetadata_(); - - if (prefs.cellularDisabled) - self.syncButton.setAttribute('checked', ''); - else - self.syncButton.removeAttribute('checked'); - - if (self.hostedButton.hasAttribute('checked') != - prefs.hostedFilesDisabled && self.isOnDrive()) { - self.directoryModel_.rescan(); - } - - if (!prefs.hostedFilesDisabled) - self.hostedButton.setAttribute('checked', ''); - else - self.hostedButton.removeAttribute('checked'); - }, - true /* refresh */); - }; - - FileManager.prototype.onDriveConnectionChanged_ = function() { - var connection = this.volumeManager_.getDriveConnectionState(); - if (this.commandHandler) - this.commandHandler.updateAvailability(); - if (this.dialogContainer_) - this.dialogContainer_.setAttribute('connection', connection.type); - this.shareDialog_.hideWithResult(ShareDialog.Result.NETWORK_ERROR); - this.suggestAppsDialog.onDriveConnectionChanged(connection.type); - }; - - /** - * Get the metered status of Drive connection. - * - * @return {boolean} Returns true if drive should limit the traffic because - * the connection is metered and the 'disable-sync-on-metered' setting is - * enabled. Otherwise, returns false. - */ - FileManager.prototype.isDriveOnMeteredConnection = function() { - var connection = this.volumeManager_.getDriveConnectionState(); - return connection.type == util.DriveConnectionType.METERED; - }; - - /** - * Get the online/offline status of drive. - * - * @return {boolean} Returns true if the connection is offline. Otherwise, - * returns false. - */ - FileManager.prototype.isDriveOffline = function() { - var connection = this.volumeManager_.getDriveConnectionState(); - return connection.type == util.DriveConnectionType.OFFLINE; - }; - - FileManager.prototype.isOnReadonlyDirectory = function() { - return this.directoryModel_.isReadOnly(); - }; - - /** - * @param {Event} Unmount event. - * @private - */ - FileManager.prototype.onExternallyUnmounted_ = function(event) { - if (event.mountPath == this.directoryModel_.getCurrentRootPath()) { - if (this.closeOnUnmount_) { - // If the file manager opened automatically when a usb drive inserted, - // user have never changed current volume (that implies the current - // directory is still on the device) then close this window. - window.close(); - } - } - }; - - /** - * Show a modal-like file viewer/editor on top of the File Manager UI. - * - * @param {HTMLElement} popup Popup element. - * @param {function()} closeCallback Function to call after the popup is - * closed. - */ - FileManager.prototype.openFilePopup = function(popup, closeCallback) { - this.closeFilePopup(); - this.filePopup_ = popup; - this.filePopupCloseCallback_ = closeCallback; - this.dialogDom_.insertBefore( - this.filePopup_, this.dialogDom_.querySelector('#iframe-drag-area')); - this.filePopup_.focus(); - this.document_.body.setAttribute('overlay-visible', ''); - this.document_.querySelector('#iframe-drag-area').hidden = false; - }; - - /** - * Closes the modal-like file viewer/editor popup. - */ - FileManager.prototype.closeFilePopup = function() { - if (this.filePopup_) { - this.document_.body.removeAttribute('overlay-visible'); - this.document_.querySelector('#iframe-drag-area').hidden = true; - // The window resize would not be processed properly while the relevant - // divs had 'display:none', force resize after the layout fired. - setTimeout(this.onResize_.bind(this), 0); - if (this.filePopup_.contentWindow && - this.filePopup_.contentWindow.unload) { - this.filePopup_.contentWindow.unload(); - } - - if (this.filePopupCloseCallback_) { - this.filePopupCloseCallback_(); - this.filePopupCloseCallback_ = null; - } - - // These operations have to be in the end, otherwise v8 crashes on an - // assert. See: crbug.com/224174. - this.dialogDom_.removeChild(this.filePopup_); - this.filePopup_ = null; - } - }; - - /** - * Updates visibility of the draggable app region in the modal-like file - * viewer/editor. - * - * @param {boolean} visible True for visible, false otherwise. - */ - FileManager.prototype.onFilePopupAppRegionChanged = function(visible) { - if (!this.filePopup_) - return; - - this.document_.querySelector('#iframe-drag-area').hidden = !visible; - }; - - /** - * @return {Array.<Entry>} List of all entries in the current directory. - */ - FileManager.prototype.getAllEntriesInCurrentDirectory = function() { - return this.directoryModel_.getFileList().slice(); - }; - - FileManager.prototype.isRenamingInProgress = function() { - return !!this.renameInput_.currentEntry; - }; - - /** - * @private - */ - FileManager.prototype.focusCurrentList_ = function() { - if (this.listType_ == FileManager.ListType.DETAIL) - this.table_.focus(); - else // this.listType_ == FileManager.ListType.THUMBNAIL) - this.grid_.focus(); - }; - - /** - * Return full path of the current directory or null. - * @return {?string} The full path of the current directory. - */ - FileManager.prototype.getCurrentDirectory = function() { - return this.directoryModel_ && this.directoryModel_.getCurrentDirPath(); - }; - - /** - * Return URL of the current directory or null. - * @return {string} URL representing the current directory. - */ - FileManager.prototype.getCurrentDirectoryURL = function() { - return this.directoryModel_ && - this.directoryModel_.getCurrentDirectoryURL(); - }; - - /** - * Return DirectoryEntry of the current directory or null. - * @return {DirectoryEntry} DirectoryEntry of the current directory. Returns - * null if the directory model is not ready or the current directory is - * not set. - */ - FileManager.prototype.getCurrentDirectoryEntry = function() { - return this.directoryModel_ && this.directoryModel_.getCurrentDirEntry(); - }; - - /** - * Deletes the selected file and directories recursively. - */ - FileManager.prototype.deleteSelection = function() { - // TODO(mtomasz): Remove this temporary dialog. crbug.com/167364 - var entries = this.getSelection().entries; - var message = entries.length == 1 ? - strf('GALLERY_CONFIRM_DELETE_ONE', entries[0].name) : - strf('GALLERY_CONFIRM_DELETE_SOME', entries.length); - this.confirm.show(message, function() { - this.fileOperationManager_.deleteEntries(entries); - }.bind(this)); - }; - - /** - * Shows the share dialog for the selected file or directory. - */ - FileManager.prototype.shareSelection = function() { - var entries = this.getSelection().entries; - if (entries.length != 1) { - console.warn('Unable to share multiple items at once.'); - return; - } - // Add the overlapped class to prevent the applicaiton window from - // captureing mouse events. - this.shareDialog_.show(entries[0], function(result) { - if (result == ShareDialog.Result.NETWORK_ERROR) - this.error.show(str('SHARE_ERROR')); - }.bind(this)); - }; - - /** - * Creates a folder shortcut. - * @param {string} path A shortcut which refers to |path| to be created. - */ - FileManager.prototype.createFolderShortcut = function(path) { - // Duplicate entry. - if (this.folderShortcutExists(path)) - return; - - this.folderShortcutsModel_.add(path); - }; - - /** - * Checkes if the shortcut which refers to the given folder exists or not. - * @param {string} path Path of the folder to be checked. - */ - FileManager.prototype.folderShortcutExists = function(path) { - return this.folderShortcutsModel_.exists(path); - }; - - /** - * Removes the folder shortcut. - * @param {string} path The shortcut which refers to |path| is to be removed. - */ - FileManager.prototype.removeFolderShortcut = function(path) { - this.folderShortcutsModel_.remove(path); - }; - - /** - * Blinks the selection. Used to give feedback when copying or cutting the - * selection. - */ - FileManager.prototype.blinkSelection = function() { - var selection = this.getSelection(); - if (!selection || selection.totalCount == 0) - return; - - for (var i = 0; i < selection.entries.length; i++) { - var selectedIndex = selection.indexes[i]; - var listItem = this.currentList_.getListItemByIndex(selectedIndex); - if (listItem) - this.blinkListItem_(listItem); - } - }; - - /** - * @param {Element} listItem List item element. - * @private - */ - FileManager.prototype.blinkListItem_ = function(listItem) { - listItem.classList.add('blink'); - setTimeout(function() { - listItem.classList.remove('blink'); - }, 100); - }; - - /** - * @private - */ - FileManager.prototype.selectDefaultPathInFilenameInput_ = function() { - var input = this.filenameInput_; - input.focus(); - var selectionEnd = input.value.lastIndexOf('.'); - if (selectionEnd == -1) { - input.select(); - } else { - input.selectionStart = 0; - input.selectionEnd = selectionEnd; - } - // Clear, so we never do this again. - this.defaultPath = ''; - }; - - /** - * Handles mouse click or tap. - * - * @param {Event} event The click event. - * @private - */ - FileManager.prototype.onDetailClick_ = function(event) { - if (this.isRenamingInProgress()) { - // Don't pay attention to clicks during a rename. - return; - } - - var listItem = this.findListItemForEvent_(event); - var selection = this.getSelection(); - if (!listItem || !listItem.selected || selection.totalCount != 1) { - return; - } - - // React on double click, but only if both clicks hit the same item. - // TODO(mtomasz): Simplify it, and use a double click handler if possible. - var clickNumber = (this.lastClickedItem_ == listItem) ? 2 : undefined; - this.lastClickedItem_ = listItem; - - if (event.detail != clickNumber) - return; - - var entry = selection.entries[0]; - if (entry.isDirectory) { - this.onDirectoryAction_(entry); - } else { - this.dispatchSelectionAction_(); - } - }; - - /** - * @private - */ - FileManager.prototype.dispatchSelectionAction_ = function() { - if (this.dialogType == DialogType.FULL_PAGE) { - var selection = this.getSelection(); - var tasks = selection.tasks; - var urls = selection.urls; - var mimeTypes = selection.mimeTypes; - if (tasks) - tasks.executeDefault(); - return true; - } - if (!this.okButton_.disabled) { - this.onOk_(); - return true; - } - return false; - }; - - /** - * Opens the suggest file dialog. - * - * @param {Entry} entry Entry of the file. - * @param {function()} onSuccess Success callback. - * @param {function()} onCancelled User-cancelled callback. - * @param {function()} onFailure Failure callback. - * @private - */ - FileManager.prototype.openSuggestAppsDialog = - function(entry, onSuccess, onCancelled, onFailure) { - if (!url) { - onFailure(); - return; - } - - this.metadataCache_.get([entry], 'drive', function(props) { - if (!props || !props[0] || !props[0].contentMimeType) { - onFailure(); - return; - } - - var basename = entry.name; - var splitted = PathUtil.splitExtension(basename); - var filename = splitted[0]; - var extension = splitted[1]; - var mime = props[0].contentMimeType; - - // Returns with failure if the file has neither extension nor mime. - if (!extension || !mime) { - onFailure(); - return; - } - - var onDialogClosed = function(result) { - switch (result) { - case SuggestAppsDialog.Result.INSTALL_SUCCESSFUL: - onSuccess(); - break; - case SuggestAppsDialog.Result.FAILED: - onFailure(); - break; - default: - onCancelled(); - } - }; - - if (FileTasks.EXECUTABLE_EXTENSIONS.indexOf(extension) !== -1) { - this.suggestAppsDialog.showByFilename(filename, onDialogClosed); - } else { - this.suggestAppsDialog.showByExtensionAndMime( - extension, mime, onDialogClosed); - } - }.bind(this)); - }; - - /** - * Called when a dialog is shown or hidden. - * @param {boolean} flag True if a dialog is shown, false if hidden. */ - FileManager.prototype.onDialogShownOrHidden = function(show) { - // Set/unset a flag to disable dragging on the title area. - this.dialogContainer_.classList.toggle('disable-header-drag', show); - }; - - /** - * Executes directory action (i.e. changes directory). - * - * @param {DirectoryEntry} entry Directory entry to which directory should be - * changed. - * @private - */ - FileManager.prototype.onDirectoryAction_ = function(entry) { - return this.directoryModel_.changeDirectory(entry.fullPath); - }; - - /** - * Update the window title. - * @private - */ - FileManager.prototype.updateTitle_ = function() { - if (this.dialogType != DialogType.FULL_PAGE) - return; - - var path = this.getCurrentDirectory(); - var rootPath = PathUtil.getRootPath(path); - this.document_.title = PathUtil.getRootLabel(rootPath) + - path.substring(rootPath.length); - }; - - /** - * Update the gear menu. - * @private - */ - FileManager.prototype.updateGearMenu_ = function() { - var hideItemsForDrive = !this.isOnDrive(); - this.syncButton.hidden = hideItemsForDrive; - this.hostedButton.hidden = hideItemsForDrive; - this.document_.getElementById('drive-separator').hidden = - hideItemsForDrive; - - // If volume has changed, then fetch remaining space data. - if (this.previousRootUrl_ != this.directoryModel_.getCurrentMountPointUrl()) - this.refreshRemainingSpace_(true); // Show loading caption. - - this.previousRootUrl_ = this.directoryModel_.getCurrentMountPointUrl(); - }; - - /** - * Refreshes space info of the current volume. - * @param {boolean} showLoadingCaption Whether show loading caption or not. - * @private - */ - FileManager.prototype.refreshRemainingSpace_ = function(showLoadingCaption) { - var volumeSpaceInfoLabel = - this.dialogDom_.querySelector('#volume-space-info-label'); - var volumeSpaceInnerBar = - this.dialogDom_.querySelector('#volume-space-info-bar'); - var volumeSpaceOuterBar = - this.dialogDom_.querySelector('#volume-space-info-bar').parentNode; - - volumeSpaceInnerBar.setAttribute('pending', ''); - - if (showLoadingCaption) { - volumeSpaceInfoLabel.innerText = str('WAITING_FOR_SPACE_INFO'); - volumeSpaceInnerBar.style.width = '100%'; - } - - var currentMountPointUrl = this.directoryModel_.getCurrentMountPointUrl(); - chrome.fileBrowserPrivate.getSizeStats( - currentMountPointUrl, function(result) { - if (this.directoryModel_.getCurrentMountPointUrl() != - currentMountPointUrl) - return; - updateSpaceInfo(result, - volumeSpaceInnerBar, - volumeSpaceInfoLabel, - volumeSpaceOuterBar); - }.bind(this)); - }; - - /** - * Update the UI when the current directory changes. - * - * @param {Event} event The directory-changed event. - * @private - */ - FileManager.prototype.onDirectoryChanged_ = function(event) { - this.selectionHandler_.onFileSelectionChanged(); - this.ui_.searchBox.clear(); - util.updateAppState(this.getCurrentDirectory()); - - // If the current directory is moved from the device's volume, do not - // automatically close the window on device removal. - if (event.previousDirEntry && - PathUtil.getRootPath(event.previousDirEntry.fullPath) != - PathUtil.getRootPath(event.newDirEntry.fullPath)) - this.closeOnUnmount_ = false; - - if (this.commandHandler) - this.commandHandler.updateAvailability(); - this.updateUnformattedVolumeStatus_(); - this.updateTitle_(); - this.updateGearMenu_(); - var currentEntry = this.getCurrentDirectoryEntry(); - this.previewPanel_.currentEntry = util.isFakeEntry(currentEntry) ? - null : currentEntry; - }; - - FileManager.prototype.updateUnformattedVolumeStatus_ = function() { - var volumeInfo = this.volumeManager_.getVolumeInfo( - this.directoryModel_.getCurrentDirEntry()); - - if (volumeInfo && volumeInfo.error) { - this.dialogDom_.setAttribute('unformatted', ''); - - var errorNode = this.dialogDom_.querySelector('#format-panel > .error'); - if (volumeInfo.error == util.VolumeError.UNSUPPORTED_FILESYSTEM) { - errorNode.textContent = str('UNSUPPORTED_FILESYSTEM_WARNING'); - } else { - errorNode.textContent = str('UNKNOWN_FILESYSTEM_WARNING'); - } - - // Update 'canExecute' for format command so the format button's disabled - // property is properly set. - if (this.commandHandler) - this.commandHandler.updateAvailability(); - } else { - this.dialogDom_.removeAttribute('unformatted'); - } - }; - - FileManager.prototype.findListItemForEvent_ = function(event) { - return this.findListItemForNode_(event.touchedElement || event.srcElement); - }; - - FileManager.prototype.findListItemForNode_ = function(node) { - var item = this.currentList_.getListItemAncestor(node); - // TODO(serya): list should check that. - return item && this.currentList_.isItem(item) ? item : null; - }; - - /** - * Unload handler for the page. May be called manually for the file picker - * dialog, because it closes by calling extension API functions that do not - * return. - * - * TODO(hirono): This method is not called when Files.app is opend as a dialog - * and is closed by the close button in the dialog frame. crbug.com/309967 - * @private - */ - FileManager.prototype.onUnload_ = function() { - if (this.directoryModel_) - this.directoryModel_.dispose(); - if (this.volumeManager_) - this.volumeManager_.dispose(); - if (this.filePopup_ && - this.filePopup_.contentWindow && - this.filePopup_.contentWindow.unload) - this.filePopup_.contentWindow.unload(true /* exiting */); - if (this.progressCenterPanel_) - this.backgroundPage_.background.progressCenter.removePanel( - this.progressCenterPanel_); - if (this.fileOperationManager_) { - if (this.onCopyProgressBound_) { - this.fileOperationManager_.removeEventListener( - 'copy-progress', this.onCopyProgressBound_); - } - if (this.onEntryChangedBound_) { - this.fileOperationManager_.removeEventListener( - 'entry-changed', this.onEntryChangedBound_); - } - } - window.closing = true; - if (this.backgroundPage_ && util.platform.runningInBrowser()) - this.backgroundPage_.background.tryClose(); - }; - - FileManager.prototype.initiateRename = function() { - var item = this.currentList_.ensureLeadItemExists(); - if (!item) - return; - var label = item.querySelector('.filename-label'); - var input = this.renameInput_; - - input.value = label.textContent; - label.parentNode.setAttribute('renaming', ''); - label.parentNode.appendChild(input); - input.focus(); - var selectionEnd = input.value.lastIndexOf('.'); - if (selectionEnd == -1) { - input.select(); - } else { - input.selectionStart = 0; - input.selectionEnd = selectionEnd; - } - - // This has to be set late in the process so we don't handle spurious - // blur events. - input.currentEntry = this.currentList_.dataModel.item(item.listIndex); - }; - - /** - * @type {Event} Key event. - * @private - */ - FileManager.prototype.onRenameInputKeyDown_ = function(event) { - if (!this.isRenamingInProgress()) - return; - - // Do not move selection or lead item in list during rename. - if (event.keyIdentifier == 'Up' || event.keyIdentifier == 'Down') { - event.stopPropagation(); - } - - switch (util.getKeyModifiers(event) + event.keyCode) { - case '27': // Escape - this.cancelRename_(); - event.preventDefault(); - break; - - case '13': // Enter - this.commitRename_(); - event.preventDefault(); - break; - } - }; - - /** - * @type {Event} Blur event. - * @private - */ - FileManager.prototype.onRenameInputBlur_ = function(event) { - if (this.isRenamingInProgress() && !this.renameInput_.validation_) - this.commitRename_(); - }; - - /** - * @private - */ - FileManager.prototype.commitRename_ = function() { - var input = this.renameInput_; - var entry = input.currentEntry; - var newName = input.value; - - if (newName == entry.name) { - this.cancelRename_(); - return; - } - - var nameNode = this.findListItemForNode_(this.renameInput_). - querySelector('.filename-label'); - - input.validation_ = true; - var validationDone = function(valid) { - input.validation_ = false; - // Alert dialog restores focus unless the item removed from DOM. - if (this.document_.activeElement != input) - this.cancelRename_(); - if (!valid) - return; - - // Validation succeeded. Do renaming. - - this.cancelRename_(); - // Optimistically apply new name immediately to avoid flickering in - // case of success. - nameNode.textContent = newName; - - util.rename( - entry, newName, - function(newEntry) { - this.directoryModel_.onRenameEntry(entry, newEntry); - }.bind(this), - function(error) { - // Write back to the old name. - nameNode.textContent = entry.name; - - // Show error dialog. - var message; - if (error.code == FileError.PATH_EXISTS_ERR || - error.code == FileError.TYPE_MISMATCH_ERR) { - // Check the existing entry is file or not. - // 1) If the entry is a file: - // a) If we get PATH_EXISTS_ERR, a file exists. - // b) If we get TYPE_MISMATCH_ERR, a directory exists. - // 2) If the entry is a directory: - // a) If we get PATH_EXISTS_ERR, a directory exists. - // b) If we get TYPE_MISMATCH_ERR, a file exists. - message = strf( - (entry.isFile && error.code == FileError.PATH_EXISTS_ERR) || - (!entry.isFile && error.code == FileError.TYPE_MISMATCH_ERR) ? - 'FILE_ALREADY_EXISTS' : - 'DIRECTORY_ALREADY_EXISTS', - newName); - } else { - message = strf('ERROR_RENAMING', entry.name, - util.getFileErrorString(err.code)); - } - - this.alert.show(message); - }.bind(this)); - }; - - // TODO(haruki): this.getCurrentDirectoryURL() might not return the actual - // parent if the directory content is a search result. Fix it to do proper - // validation. - this.validateFileName_(this.getCurrentDirectoryURL(), - newName, - validationDone.bind(this)); - }; - - /** - * @private - */ - FileManager.prototype.cancelRename_ = function() { - this.renameInput_.currentEntry = null; - - var parent = this.renameInput_.parentNode; - if (parent) { - parent.removeAttribute('renaming'); - parent.removeChild(this.renameInput_); - } - }; - - /** - * @param {Event} Key event. - * @private - */ - FileManager.prototype.onFilenameInputInput_ = function() { - this.selectionHandler_.updateOkButton(); - }; - - /** - * @param {Event} Key event. - * @private - */ - FileManager.prototype.onFilenameInputKeyDown_ = function(event) { - if ((util.getKeyModifiers(event) + event.keyCode) === '13' /* Enter */) - this.okButton_.click(); - }; - - /** - * @param {Event} Focus event. - * @private - */ - FileManager.prototype.onFilenameInputFocus_ = function(event) { - var input = this.filenameInput_; - - // On focus we want to select everything but the extension, but - // Chrome will select-all after the focus event completes. We - // schedule a timeout to alter the focus after that happens. - setTimeout(function() { - var selectionEnd = input.value.lastIndexOf('.'); - if (selectionEnd == -1) { - input.select(); - } else { - input.selectionStart = 0; - input.selectionEnd = selectionEnd; - } - }, 0); - }; - - /** - * @private - */ - FileManager.prototype.onScanStarted_ = function() { - if (this.scanInProgress_) { - this.table_.list.endBatchUpdates(); - this.grid_.endBatchUpdates(); - } - - if (this.commandHandler) - this.commandHandler.updateAvailability(); - this.table_.list.startBatchUpdates(); - this.grid_.startBatchUpdates(); - this.scanInProgress_ = true; - - this.scanUpdatedAtLeastOnceOrCompleted_ = false; - if (this.scanCompletedTimer_) { - clearTimeout(this.scanCompletedTimer_); - this.scanCompletedTimer_ = null; - } - - if (this.scanUpdatedTimer_) { - clearTimeout(this.scanUpdatedTimer_); - this.scanUpdatedTimer_ = null; - } - - if (this.spinner_.hidden) { - this.cancelSpinnerTimeout_(); - this.showSpinnerTimeout_ = - setTimeout(this.showSpinner_.bind(this, true), 500); - } - }; - - /** - * @private - */ - FileManager.prototype.onScanCompleted_ = function() { - if (!this.scanInProgress_) { - console.error('Scan-completed event recieved. But scan is not started.'); - return; - } - - if (this.commandHandler) - this.commandHandler.updateAvailability(); - this.hideSpinnerLater_(); - - if (this.scanUpdatedTimer_) { - clearTimeout(this.scanUpdatedTimer_); - this.scanUpdatedTimer_ = null; - } - - // To avoid flickering postpone updating the ui by a small amount of time. - // There is a high chance, that metadata will be received within 50 ms. - this.scanCompletedTimer_ = setTimeout(function() { - // Check if batch updates are already finished by onScanUpdated_(). - if (!this.scanUpdatedAtLeastOnceOrCompleted_) { - this.scanUpdatedAtLeastOnceOrCompleted_ = true; - this.updateMiddleBarVisibility_(); - } - - this.scanInProgress_ = false; - this.table_.list.endBatchUpdates(); - this.grid_.endBatchUpdates(); - this.scanCompletedTimer_ = null; - }.bind(this), 50); - }; - - /** - * @private - */ - FileManager.prototype.onScanUpdated_ = function() { - if (!this.scanInProgress_) { - console.error('Scan-updated event recieved. But scan is not started.'); - return; - } - - if (this.scanUpdatedTimer_ || this.scanCompletedTimer_) - return; - - // Show contents incrementally by finishing batch updated, but only after - // 200ms elapsed, to avoid flickering when it is not necessary. - this.scanUpdatedTimer_ = setTimeout(function() { - // We need to hide the spinner only once. - if (!this.scanUpdatedAtLeastOnceOrCompleted_) { - this.scanUpdatedAtLeastOnceOrCompleted_ = true; - this.hideSpinnerLater_(); - this.updateMiddleBarVisibility_(); - } - - // Update the UI. - if (this.scanInProgress_) { - this.table_.list.endBatchUpdates(); - this.grid_.endBatchUpdates(); - this.table_.list.startBatchUpdates(); - this.grid_.startBatchUpdates(); - } - this.scanUpdatedTimer_ = null; - }.bind(this), 200); - }; - - /** - * @private - */ - FileManager.prototype.onScanCancelled_ = function() { - if (!this.scanInProgress_) { - console.error('Scan-cancelled event recieved. But scan is not started.'); - return; - } - - if (this.commandHandler) - this.commandHandler.updateAvailability(); - this.hideSpinnerLater_(); - if (this.scanCompletedTimer_) { - clearTimeout(this.scanCompletedTimer_); - this.scanCompletedTimer_ = null; - } - if (this.scanUpdatedTimer_) { - clearTimeout(this.scanUpdatedTimer_); - this.scanUpdatedTimer_ = null; - } - // Finish unfinished batch updates. - if (!this.scanUpdatedAtLeastOnceOrCompleted_) { - this.scanUpdatedAtLeastOnceOrCompleted_ = true; - this.updateMiddleBarVisibility_(); - } - - this.scanInProgress_ = false; - this.table_.list.endBatchUpdates(); - this.grid_.endBatchUpdates(); - }; - - /** - * Handle the 'rescan-completed' from the DirectoryModel. - * @private - */ - FileManager.prototype.onRescanCompleted_ = function() { - this.selectionHandler_.onFileSelectionChanged(); - }; - - /** - * @private - */ - FileManager.prototype.cancelSpinnerTimeout_ = function() { - if (this.showSpinnerTimeout_) { - clearTimeout(this.showSpinnerTimeout_); - this.showSpinnerTimeout_ = null; - } - }; - - /** - * @private - */ - FileManager.prototype.hideSpinnerLater_ = function() { - this.cancelSpinnerTimeout_(); - this.showSpinner_(false); - }; - - /** - * @param {boolean} on True to show, false to hide. - * @private - */ - FileManager.prototype.showSpinner_ = function(on) { - if (on && this.directoryModel_ && this.directoryModel_.isScanning()) - this.spinner_.hidden = false; - - if (!on && (!this.directoryModel_ || - !this.directoryModel_.isScanning() || - this.directoryModel_.getFileList().length != 0)) { - this.spinner_.hidden = true; - } - }; - - FileManager.prototype.createNewFolder = function() { - var defaultName = str('DEFAULT_NEW_FOLDER_NAME'); - - // Find a name that doesn't exist in the data model. - var files = this.directoryModel_.getFileList(); - var hash = {}; - for (var i = 0; i < files.length; i++) { - var name = files.item(i).name; - // Filtering names prevents from conflicts with prototype's names - // and '__proto__'. - if (name.substring(0, defaultName.length) == defaultName) - hash[name] = 1; - } - - var baseName = defaultName; - var separator = ''; - var suffix = ''; - var index = ''; - - var advance = function() { - separator = ' ('; - suffix = ')'; - index++; - }; - - var current = function() { - return baseName + separator + index + suffix; - }; - - // Accessing hasOwnProperty is safe since hash properties filtered. - while (hash.hasOwnProperty(current())) { - advance(); - } - - var self = this; - var list = self.currentList_; - var tryCreate = function() { - self.directoryModel_.createDirectory(current(), - onSuccess, onError); - }; - - var onSuccess = function(entry) { - metrics.recordUserAction('CreateNewFolder'); - list.selectedItem = entry; - self.initiateRename(); - }; - - var onError = function(error) { - self.alert.show(strf('ERROR_CREATING_FOLDER', current(), - util.getFileErrorString(error.code))); - }; - - tryCreate(); - }; - - /** - * @param {Event} event Click event. - * @private - */ - FileManager.prototype.onDetailViewButtonClick_ = function(event) { - // Stop propagate and hide the menu manually, in order to prevent the focus - // from being back to the button. (cf. http://crbug.com/248479) - event.stopPropagation(); - this.gearButton_.hideMenu(); - - this.setListType(FileManager.ListType.DETAIL); - this.currentList_.focus(); - }; - - /** - * @param {Event} event Click event. - * @private - */ - FileManager.prototype.onThumbnailViewButtonClick_ = function(event) { - // Stop propagate and hide the menu manually, in order to prevent the focus - // from being back to the button. (cf. http://crbug.com/248479) - event.stopPropagation(); - this.gearButton_.hideMenu(); - - this.setListType(FileManager.ListType.THUMBNAIL); - this.currentList_.focus(); - }; - - /** - * KeyDown event handler for the document. - * @param {Event} event Key event. - * @private - */ - FileManager.prototype.onKeyDown_ = function(event) { - if (event.srcElement === this.renameInput_) { - // Ignore keydown handler in the rename input box. - return; - } - - switch (util.getKeyModifiers(event) + event.keyCode) { - case 'Ctrl-190': // Ctrl-. => Toggle filter files. - this.fileFilter_.setFilterHidden( - !this.fileFilter_.isFilterHiddenOn()); - event.preventDefault(); - return; - - case '27': // Escape => Cancel dialog. - if (this.dialogType != DialogType.FULL_PAGE) { - // If there is nothing else for ESC to do, then cancel the dialog. - event.preventDefault(); - this.cancelButton_.click(); - } - break; - } - }; - - /** - * KeyDown event handler for the div#list-container element. - * @param {Event} event Key event. - * @private - */ - FileManager.prototype.onListKeyDown_ = function(event) { - if (event.srcElement.tagName == 'INPUT') { - // Ignore keydown handler in the rename input box. - return; - } - - switch (util.getKeyModifiers(event) + event.keyCode) { - case '8': // Backspace => Up one directory. - event.preventDefault(); - var path = this.getCurrentDirectory(); - if (path && !PathUtil.isRootPath(path)) { - var path = path.replace(/\/[^\/]+$/, ''); - this.directoryModel_.changeDirectory(path); - } - break; - - case '13': // Enter => Change directory or perform default action. - // TODO(dgozman): move directory action to dispatchSelectionAction. - var selection = this.getSelection(); - if (selection.totalCount == 1 && - selection.entries[0].isDirectory && - !DialogType.isFolderDialog(this.dialogType)) { - event.preventDefault(); - this.onDirectoryAction_(selection.entries[0]); - } else if (this.dispatchSelectionAction_()) { - event.preventDefault(); - } - break; - } - - switch (event.keyIdentifier) { - case 'Home': - case 'End': - case 'Up': - case 'Down': - case 'Left': - case 'Right': - // When navigating with keyboard we hide the distracting mouse hover - // highlighting until the user moves the mouse again. - this.setNoHover_(true); - break; - } - }; - - /** - * Suppress/restore hover highlighting in the list container. - * @param {boolean} on True to temporarity hide hover state. - * @private - */ - FileManager.prototype.setNoHover_ = function(on) { - if (on) { - this.listContainer_.classList.add('nohover'); - } else { - this.listContainer_.classList.remove('nohover'); - } - }; - - /** - * KeyPress event handler for the div#list-container element. - * @param {Event} event Key event. - * @private - */ - FileManager.prototype.onListKeyPress_ = function(event) { - if (event.srcElement.tagName == 'INPUT') { - // Ignore keypress handler in the rename input box. - return; - } - - if (event.ctrlKey || event.metaKey || event.altKey) - return; - - var now = new Date(); - var char = String.fromCharCode(event.charCode).toLowerCase(); - var text = now - this.textSearchState_.date > 1000 ? '' : - this.textSearchState_.text; - this.textSearchState_ = {text: text + char, date: now}; - - this.doTextSearch_(); - }; - - /** - * Mousemove event handler for the div#list-container element. - * @param {Event} event Mouse event. - * @private - */ - FileManager.prototype.onListMouseMove_ = function(event) { - // The user grabbed the mouse, restore the hover highlighting. - this.setNoHover_(false); - }; - - /** - * Performs a 'text search' - selects a first list entry with name - * starting with entered text (case-insensitive). - * @private - */ - FileManager.prototype.doTextSearch_ = function() { - var text = this.textSearchState_.text; - if (!text) - return; - - var dm = this.directoryModel_.getFileList(); - for (var index = 0; index < dm.length; ++index) { - var name = dm.item(index).name; - if (name.substring(0, text.length).toLowerCase() == text) { - this.currentList_.selectionModel.selectedIndexes = [index]; - return; - } - } - - this.textSearchState_.text = ''; - }; - - /** - * Handle a click of the cancel button. Closes the window. - * TODO(jamescook): Make unload handler work automatically, crbug.com/104811 - * - * @param {Event} event The click event. - * @private - */ - FileManager.prototype.onCancel_ = function(event) { - chrome.fileBrowserPrivate.cancelDialog(); - this.onUnload_(); - window.close(); - }; - - /** - * Resolves selected file urls returned from an Open dialog. - * - * For drive files this involves some special treatment. - * Starts getting drive files if needed. - * - * @param {Array.<string>} fileUrls Drive URLs. - * @param {function(Array.<string>)} callback To be called with fixed URLs. - * @private - */ - FileManager.prototype.resolveSelectResults_ = function(fileUrls, callback) { - if (this.isOnDrive()) { - chrome.fileBrowserPrivate.getDriveFiles( - fileUrls, - function(localPaths) { - callback(fileUrls); - }); - } else { - callback(fileUrls); - } - }; - - /** - * Closes this modal dialog with some files selected. - * TODO(jamescook): Make unload handler work automatically, crbug.com/104811 - * @param {Object} selection Contains urls, filterIndex and multiple fields. - * @private - */ - FileManager.prototype.callSelectFilesApiAndClose_ = function(selection) { - var self = this; - function callback() { - self.onUnload_(); - window.close(); - } - if (selection.multiple) { - chrome.fileBrowserPrivate.selectFiles( - selection.urls, this.params_.shouldReturnLocalPath, callback); - } else { - var forOpening = (this.dialogType != DialogType.SELECT_SAVEAS_FILE); - chrome.fileBrowserPrivate.selectFile( - selection.urls[0], selection.filterIndex, forOpening, - this.params_.shouldReturnLocalPath, callback); - } - }; - - /** - * Tries to close this modal dialog with some files selected. - * Performs preprocessing if needed (e.g. for Drive). - * @param {Object} selection Contains urls, filterIndex and multiple fields. - * @private - */ - FileManager.prototype.selectFilesAndClose_ = function(selection) { - if (!this.isOnDrive() || - this.dialogType == DialogType.SELECT_SAVEAS_FILE) { - setTimeout(this.callSelectFilesApiAndClose_.bind(this, selection), 0); - return; - } - - var shade = this.document_.createElement('div'); - shade.className = 'shade'; - var footer = this.dialogDom_.querySelector('.button-panel'); - var progress = footer.querySelector('.progress-track'); - progress.style.width = '0%'; - var cancelled = false; - - var progressMap = {}; - var filesStarted = 0; - var filesTotal = selection.urls.length; - for (var index = 0; index < selection.urls.length; index++) { - progressMap[selection.urls[index]] = -1; - } - var lastPercent = 0; - var bytesTotal = 0; - var bytesDone = 0; - - var onFileTransfersUpdated = function(statusList) { - for (var index = 0; index < statusList.length; index++) { - var status = statusList[index]; - var escaped = encodeURI(status.fileUrl); - if (!(escaped in progressMap)) continue; - if (status.total == -1) continue; - - var old = progressMap[escaped]; - if (old == -1) { - // -1 means we don't know file size yet. - bytesTotal += status.total; - filesStarted++; - old = 0; - } - bytesDone += status.processed - old; - progressMap[escaped] = status.processed; - } - - var percent = bytesTotal == 0 ? 0 : bytesDone / bytesTotal; - // For files we don't have information about, assume the progress is zero. - percent = percent * filesStarted / filesTotal * 100; - // Do not decrease the progress. This may happen, if first downloaded - // file is small, and the second one is large. - lastPercent = Math.max(lastPercent, percent); - progress.style.width = lastPercent + '%'; - }.bind(this); - - var setup = function() { - this.document_.querySelector('.dialog-container').appendChild(shade); - setTimeout(function() { shade.setAttribute('fadein', 'fadein') }, 100); - footer.setAttribute('progress', 'progress'); - this.cancelButton_.removeEventListener('click', this.onCancelBound_); - this.cancelButton_.addEventListener('click', onCancel); - chrome.fileBrowserPrivate.onFileTransfersUpdated.addListener( - onFileTransfersUpdated); - }.bind(this); - - var cleanup = function() { - shade.parentNode.removeChild(shade); - footer.removeAttribute('progress'); - this.cancelButton_.removeEventListener('click', onCancel); - this.cancelButton_.addEventListener('click', this.onCancelBound_); - chrome.fileBrowserPrivate.onFileTransfersUpdated.removeListener( - onFileTransfersUpdated); - }.bind(this); - - var onCancel = function() { - cancelled = true; - // According to API cancel may fail, but there is no proper UI to reflect - // this. So, we just silently assume that everything is cancelled. - chrome.fileBrowserPrivate.cancelFileTransfers( - selection.urls, function(response) {}); - cleanup(); - }.bind(this); - - var onResolved = function(resolvedUrls) { - if (cancelled) return; - cleanup(); - selection.urls = resolvedUrls; - // Call next method on a timeout, as it's unsafe to - // close a window from a callback. - setTimeout(this.callSelectFilesApiAndClose_.bind(this, selection), 0); - }.bind(this); - - var onProperties = function(properties) { - for (var i = 0; i < properties.length; i++) { - if (!properties[i] || properties[i].present) { - // For files already in GCache, we don't get any transfer updates. - filesTotal--; - } - } - this.resolveSelectResults_(selection.urls, onResolved); - }.bind(this); - - setup(); - - // TODO(mtomasz): Use Entry instead of URLs, if possible. - util.URLsToEntries(selection.urls, function(entries) { - this.metadataCache_.get(entries, 'drive', onProperties); - }.bind(this)); - }; - - /** - * Handle a click of the ok button. - * - * The ok button has different UI labels depending on the type of dialog, but - * in code it's always referred to as 'ok'. - * - * @param {Event} event The click event. - * @private - */ - FileManager.prototype.onOk_ = function(event) { - if (this.dialogType == DialogType.SELECT_SAVEAS_FILE) { - // Save-as doesn't require a valid selection from the list, since - // we're going to take the filename from the text input. - var filename = this.filenameInput_.value; - if (!filename) - throw new Error('Missing filename!'); - - var directory = this.getCurrentDirectoryEntry(); - var currentDirUrl = directory.toURL(); - if (currentDirUrl.charAt(currentDirUrl.length - 1) != '/') - currentDirUrl += '/'; - this.validateFileName_(currentDirUrl, filename, function(isValid) { - if (!isValid) - return; - - if (util.isFakeEntry(directory)) { - // Can't save a file into a fake directory. - return; - } - - var selectFileAndClose = function() { - this.selectFilesAndClose_({ - urls: [currentDirUrl + encodeURIComponent(filename)], - multiple: false, - filterIndex: this.getSelectedFilterIndex_(filename) - }); - }.bind(this); - - directory.getFile( - filename, {create: false}, - function(entry) { - // An existing file is found. Show confirmation dialog to - // overwrite it. If the user select "OK" on the dialog, save it. - this.confirm.show(strf('CONFIRM_OVERWRITE_FILE', filename), - selectFileAndClose); - }.bind(this), - function(error) { - if (error.code == FileError.NOT_FOUND_ERR) { - // The file does not exist, so it should be ok to create a - // new file. - selectFileAndClose(); - return; - } - if (error.code == FileError.TYPE_MISMATCH_ERR) { - // An directory is found. - // Do not allow to overwrite directory. - this.alert.show(strf('DIRECTORY_ALREADY_EXISTS', filename)); - return; - } - - // Unexpected error. - console.error('File save failed: ' + error.code); - }.bind(this)); - }.bind(this)); - return; - } - - var files = []; - var selectedIndexes = this.currentList_.selectionModel.selectedIndexes; - - if (DialogType.isFolderDialog(this.dialogType) && - selectedIndexes.length == 0) { - var url = this.getCurrentDirectoryURL(); - var singleSelection = { - urls: [url], - multiple: false, - filterIndex: this.getSelectedFilterIndex_() - }; - this.selectFilesAndClose_(singleSelection); - return; - } - - // All other dialog types require at least one selected list item. - // The logic to control whether or not the ok button is enabled should - // prevent us from ever getting here, but we sanity check to be sure. - if (!selectedIndexes.length) - throw new Error('Nothing selected!'); - - var dm = this.directoryModel_.getFileList(); - for (var i = 0; i < selectedIndexes.length; i++) { - var entry = dm.item(selectedIndexes[i]); - if (!entry) { - console.error('Error locating selected file at index: ' + i); - continue; - } - - files.push(entry.toURL()); - } - - // Multi-file selection has no other restrictions. - if (this.dialogType == DialogType.SELECT_OPEN_MULTI_FILE) { - var multipleSelection = { - urls: files, - multiple: true - }; - this.selectFilesAndClose_(multipleSelection); - return; - } - - // Everything else must have exactly one. - if (files.length > 1) - throw new Error('Too many files selected!'); - - var selectedEntry = dm.item(selectedIndexes[0]); - - if (DialogType.isFolderDialog(this.dialogType)) { - if (!selectedEntry.isDirectory) - throw new Error('Selected entry is not a folder!'); - } else if (this.dialogType == DialogType.SELECT_OPEN_FILE) { - if (!selectedEntry.isFile) - throw new Error('Selected entry is not a file!'); - } - - var singleSelection = { - urls: [files[0]], - multiple: false, - filterIndex: this.getSelectedFilterIndex_() - }; - this.selectFilesAndClose_(singleSelection); - }; - - /** - * Verifies the user entered name for file or folder to be created or - * renamed to. Name restrictions must correspond to File API restrictions - * (see DOMFilePath::isValidPath). Curernt WebKit implementation is - * out of date (spec is - * http://dev.w3.org/2009/dap/file-system/file-dir-sys.html, 8.3) and going to - * be fixed. Shows message box if the name is invalid. - * - * It also verifies if the name length is in the limit of the filesystem. - * - * @param {string} parentUrl The URL of the parent directory entry. - * @param {string} name New file or folder name. - * @param {function} onDone Function to invoke when user closes the - * warning box or immediatelly if file name is correct. If the name was - * valid it is passed true, and false otherwise. - * @private - */ - FileManager.prototype.validateFileName_ = function(parentUrl, name, onDone) { - var msg; - var testResult = /[\/\\\<\>\:\?\*\"\|]/.exec(name); - if (testResult) { - msg = strf('ERROR_INVALID_CHARACTER', testResult[0]); - } else if (/^\s*$/i.test(name)) { - msg = str('ERROR_WHITESPACE_NAME'); - } else if (/^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i.test(name)) { - msg = str('ERROR_RESERVED_NAME'); - } else if (this.fileFilter_.isFilterHiddenOn() && name[0] == '.') { - msg = str('ERROR_HIDDEN_NAME'); - } - - if (msg) { - this.alert.show(msg, function() { - onDone(false); - }); - return; - } - - var self = this; - chrome.fileBrowserPrivate.validatePathNameLength( - parentUrl, name, function(valid) { - if (!valid) { - self.alert.show(str('ERROR_LONG_NAME'), - function() { onDone(false); }); - } else { - onDone(true); - } - }); - }; - - /** - * Handler invoked on preference setting in drive context menu. - * - * @param {string} pref The preference to alter. - * @param {boolean} inverted Invert the value if true. - * @param {Event} event The click event. - * @private - */ - FileManager.prototype.onDrivePrefClick_ = function(pref, inverted, event) { - var newValue = !event.target.hasAttribute('checked'); - if (newValue) - event.target.setAttribute('checked', 'checked'); - else - event.target.removeAttribute('checked'); - - var changeInfo = {}; - changeInfo[pref] = inverted ? !newValue : newValue; - chrome.fileBrowserPrivate.setPreferences(changeInfo); - }; - - /** - * Invoked when the search box is changed. - * - * @param {Event} event The changed event. - * @private - */ - FileManager.prototype.onSearchBoxUpdate_ = function(event) { - var searchString = this.searchBox_.value; - - if (this.isOnDrive()) { - // When the search text is changed, finishes the search and showes back - // the last directory by passing an empty string to - // {@code DirectoryModel.search()}. - if (this.directoryModel_.isSearching() && - this.lastSearchQuery_ != searchString) { - this.doSearch(''); - } - - // On drive, incremental search is not invoked since we have an auto- - // complete suggestion instead. - return; - } - - this.search_(searchString); - }; - - /** - * Handle the search clear button click. - * @private - */ - FileManager.prototype.onSearchClearButtonClick_ = function() { - this.ui_.searchBox.clear(); - this.onSearchBoxUpdate_(); - }; - - /** - * Search files and update the list with the search result. - * - * @param {string} searchString String to be searched with. - * @private - */ - FileManager.prototype.search_ = function(searchString) { - var noResultsDiv = this.document_.getElementById('no-search-results'); - - var reportEmptySearchResults = function() { - if (this.directoryModel_.getFileList().length === 0) { - // The string 'SEARCH_NO_MATCHING_FILES_HTML' may contain HTML tags, - // hence we escapes |searchString| here. - var html = strf('SEARCH_NO_MATCHING_FILES_HTML', - util.htmlEscape(searchString)); - noResultsDiv.innerHTML = html; - noResultsDiv.setAttribute('show', 'true'); - } else { - noResultsDiv.removeAttribute('show'); - } - }; - - var hideNoResultsDiv = function() { - noResultsDiv.removeAttribute('show'); - }; - - this.doSearch(searchString, - reportEmptySearchResults.bind(this), - hideNoResultsDiv.bind(this)); - }; - - /** - * Performs search and displays results. - * - * @param {string} query Query that will be searched for. - * @param {function()=} opt_onSearchRescan Function that will be called when - * the search directory is rescanned (i.e. search results are displayed). - * @param {function()=} opt_onClearSearch Function to be called when search - * state gets cleared. - */ - FileManager.prototype.doSearch = function( - searchString, opt_onSearchRescan, opt_onClearSearch) { - var onSearchRescan = opt_onSearchRescan || function() {}; - var onClearSearch = opt_onClearSearch || function() {}; - - this.lastSearchQuery_ = searchString; - this.directoryModel_.search(searchString, onSearchRescan, onClearSearch); - }; - - /** - * Requests autocomplete suggestions for files on Drive. - * Once the suggestions are returned, the autocomplete popup will show up. - * - * @param {string} query The text to autocomplete from. - * @private - */ - FileManager.prototype.requestAutocompleteSuggestions_ = function(query) { - query = query.trimLeft(); - - // Only Drive supports auto-compelete - if (!this.isOnDrive()) - return; - - // Remember the most recent query. If there is an other request in progress, - // then it's result will be discarded and it will call a new request for - // this query. - this.lastAutocompleteQuery_ = query; - if (this.autocompleteSuggestionsBusy_) - return; - - // The autocomplete list should be resized and repositioned here as the - // search box is resized when it's focused. - this.autocompleteList_.syncWidthAndPositionToInput(); - - if (!query) { - this.autocompleteList_.suggestions = []; - return; - } - - var headerItem = {isHeaderItem: true, searchQuery: query}; - if (!this.autocompleteList_.dataModel || - this.autocompleteList_.dataModel.length == 0) - this.autocompleteList_.suggestions = [headerItem]; - else - // Updates only the head item to prevent a flickering on typing. - this.autocompleteList_.dataModel.splice(0, 1, headerItem); - - this.autocompleteSuggestionsBusy_ = true; - - var searchParams = { - 'query': query, - 'types': 'ALL', - 'maxResults': 4 - }; - chrome.fileBrowserPrivate.searchDriveMetadata( - searchParams, - function(suggestions) { - this.autocompleteSuggestionsBusy_ = false; - - // Discard results for previous requests and fire a new search - // for the most recent query. - if (query != this.lastAutocompleteQuery_) { - this.requestAutocompleteSuggestions_(this.lastAutocompleteQuery_); - return; - } - - // Keeps the items in the suggestion list. - this.autocompleteList_.suggestions = [headerItem].concat(suggestions); - }.bind(this)); - }; - - /** - * Opens the currently selected suggestion item. - * @private - */ - FileManager.prototype.openAutocompleteSuggestion_ = function() { - var selectedItem = this.autocompleteList_.selectedItem; - - // If the entry is the search item or no entry is selected, just change to - // the search result. - if (!selectedItem || selectedItem.isHeaderItem) { - var query = selectedItem ? - selectedItem.searchQuery : this.searchBox_.value; - this.search_(query); - return; - } - - var entry = selectedItem.entry; - // If the entry is a directory, just change the directory. - if (entry.isDirectory) { - this.onDirectoryAction_(entry); - return; - } - - var entries = [entry]; - var self = this; - - // To open a file, first get the mime type. - this.metadataCache_.get(entries, 'drive', function(props) { - var mimeType = props[0].contentMimeType || ''; - var mimeTypes = [mimeType]; - var openIt = function() { - if (self.dialogType == DialogType.FULL_PAGE) { - var tasks = new FileTasks(self); - tasks.init(entries, mimeTypes); - tasks.executeDefault(); - } else { - self.onOk_(); - } - }; - - // Change the current directory to the directory that contains the - // selected file. Note that this is necessary for an image or a video, - // which should be opened in the gallery mode, as the gallery mode - // requires the entry to be in the current directory model. For - // consistency, the current directory is always changed regardless of - // the file type. - entry.getParent(function(parent) { - var onDirectoryChanged = function(event) { - self.directoryModel_.removeEventListener('scan-completed', - onDirectoryChanged); - self.directoryModel_.selectEntry(entry); - openIt(); - }; - // changeDirectory() returns immediately. We should wait until the - // directory scan is complete. - self.directoryModel_.addEventListener('scan-completed', - onDirectoryChanged); - self.directoryModel_.changeDirectory( - parent.fullPath, - function() { - // Remove the listner if the change directory failed. - self.directoryModel_.removeEventListener('scan-completed', - onDirectoryChanged); - }); - }); - }); - }; - - FileManager.prototype.decorateSplitter = function(splitterElement) { - var self = this; - - var Splitter = cr.ui.Splitter; - - var customSplitter = cr.ui.define('div'); - - customSplitter.prototype = { - __proto__: Splitter.prototype, - - handleSplitterDragStart: function(e) { - Splitter.prototype.handleSplitterDragStart.apply(this, arguments); - this.ownerDocument.documentElement.classList.add('col-resize'); - }, - - handleSplitterDragMove: function(deltaX) { - Splitter.prototype.handleSplitterDragMove.apply(this, arguments); - self.onResize_(); - }, - - handleSplitterDragEnd: function(e) { - Splitter.prototype.handleSplitterDragEnd.apply(this, arguments); - this.ownerDocument.documentElement.classList.remove('col-resize'); - } - }; - - customSplitter.decorate(splitterElement); - }; - - /** - * Updates default action menu item to match passed taskItem (icon, - * label and action). - * - * @param {Object} defaultItem - taskItem to match. - * @param {boolean} isMultiple - if multiple tasks available. - */ - FileManager.prototype.updateContextMenuActionItems = function(defaultItem, - isMultiple) { - if (defaultItem) { - if (defaultItem.iconType) { - this.defaultActionMenuItem_.style.backgroundImage = ''; - this.defaultActionMenuItem_.setAttribute('file-type-icon', - defaultItem.iconType); - } else if (defaultItem.iconUrl) { - this.defaultActionMenuItem_.style.backgroundImage = - 'url(' + defaultItem.iconUrl + ')'; - } else { - this.defaultActionMenuItem_.style.backgroundImage = ''; - } - - this.defaultActionMenuItem_.label = defaultItem.title; - this.defaultActionMenuItem_.disabled = !!defaultItem.disabled; - this.defaultActionMenuItem_.taskId = defaultItem.taskId; - } - - var defaultActionSeparator = - this.dialogDom_.querySelector('#default-action-separator'); - - this.openWithCommand_.canExecuteChange(); - this.openWithCommand_.setHidden(!(defaultItem && isMultiple)); - this.openWithCommand_.disabled = defaultItem && !!defaultItem.disabled; - - this.defaultActionMenuItem_.hidden = !defaultItem; - defaultActionSeparator.hidden = !defaultItem; - }; - - /** - * Window beforeunload handler. - * @return {string} Message to show. Ignored when running as a packaged app. - * @private - */ - FileManager.prototype.onBeforeUnload_ = function() { - if (this.filePopup_ && - this.filePopup_.contentWindow && - this.filePopup_.contentWindow.beforeunload) { - // The gallery might want to prevent the unload if it is busy. - return this.filePopup_.contentWindow.beforeunload(); - } - return null; - }; - - /** - * @return {FileSelection} Selection object. - */ - FileManager.prototype.getSelection = function() { - return this.selectionHandler_.selection; - }; - - /** - * @return {ArrayDataModel} File list. - */ - FileManager.prototype.getFileList = function() { - return this.directoryModel_.getFileList(); - }; - - /** - * @return {cr.ui.List} Current list object. - */ - FileManager.prototype.getCurrentList = function() { - return this.currentList_; - }; - - /** - * Retrieve the preferences of the files.app. This method caches the result - * and returns it unless opt_update is true. - * @param {function(Object.<string, *>)} callback Callback to get the - * preference. - * @param {boolean=} opt_update If is's true, don't use the cache and - * retrieve latest preference. Default is false. - * @private - */ - FileManager.prototype.getPreferences_ = function(callback, opt_update) { - if (!opt_update && this.preferences_ !== undefined) { - callback(this.preferences_); - return; - } - - chrome.fileBrowserPrivate.getPreferences(function(prefs) { - this.preferences_ = prefs; - callback(prefs); - }.bind(this)); - }; -})(); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/file_manager_commands.js b/chromium/chrome/browser/resources/file_manager/foreground/js/file_manager_commands.js deleted file mode 100644 index 52a26b92a64..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/file_manager_commands.js +++ /dev/null @@ -1,828 +0,0 @@ -// 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. - -'use strict'; - -/** - * TODO(dzvorygin): Here we use this hack, since 'hidden' is standard - * attribute and we can't use it's setter as usual. - * @param {boolean} value New value of hidden property. - */ -cr.ui.Command.prototype.setHidden = function(value) { - this.__lookupSetter__('hidden').call(this, value); -}; - -/** - * A command. - * @interface - */ -var Command = function() {}; - -/** - * Handles the execute event. - * @param {Event} event Command event. - * @param {FileManager} fileManager FileManager. - */ -Command.prototype.execute = function(event, fileManager) {}; - -/** - * Handles the can execute event. - * @param {Event} event Can execute event. - * @param {FileManager} fileManager FileManager. - */ -Command.prototype.canExecute = function(event, fileManager) {}; - -/** - * Utility for commands. - */ -var CommandUtil = {}; - -/** - * Extracts entry on which command event was dispatched. - * - * @param {DirectoryTree|DirectoryItem|NavigationList|HTMLLIElement|cr.ui.List} - * element Directory to extract a path from. - * @return {Entry} Entry of the found node. - */ -CommandUtil.getCommandEntry = function(element) { - if (element instanceof NavigationList) { - // element is a NavigationList. - - /** @type {NavigationModelItem} */ - var selectedItem = element.selectedItem; - return selectedItem && selectedItem.getCachedEntry(); - } else if (element instanceof NavigationListItem) { - // element is a subitem of NavigationList. - /** @type {NavigationList} */ - var navigationList = element.parentElement; - var index = navigationList.getIndexOfListItem(element); - /** @type {NavigationModelItem} */ - var item = (index != -1) ? navigationList.dataModel.item(index) : null; - return item && item.getCachedEntry(); - } else if (element instanceof DirectoryTree) { - // element is a DirectoryTree. - return element.selectedItem; - } else if (element instanceof DirectoryItem) { - // element is a sub item in DirectoryTree. - - // DirectoryItem.fullPath is set on initialization, but entry is lazily. - // We may use fullPath just in case that the entry has not been set yet. - return element.entry; - } else if (element instanceof cr.ui.List) { - // element is a normal List (eg. the file list on the right panel). - var entry = element.selectedItem; - // Check if it is Entry or not by referring the fullPath member variable. - return entry && entry.fullPath ? entry : null; - } else { - console.warn('Unsupported element'); - return null; - } -}; - -/** - * @param {NavigationList} navigationList navigation list to extract root node. - * @return {?RootType} Type of the found root. - */ -CommandUtil.getCommandRootType = function(navigationList) { - var root = CommandUtil.getCommandEntry(navigationList); - return root && - PathUtil.isRootPath(root.fullPath) && - PathUtil.getRootType(root.fullPath); -}; - -/** - * Checks if command can be executed on drive. - * @param {Event} event Command event to mark. - * @param {FileManager} fileManager FileManager to use. - */ -CommandUtil.canExecuteEnabledOnDriveOnly = function(event, fileManager) { - event.canExecute = fileManager.isOnDrive(); -}; - -/** - * Checks if command should be visible on drive. - * @param {Event} event Command event to mark. - * @param {FileManager} fileManager FileManager to use. - */ -CommandUtil.canExecuteVisibleOnDriveOnly = function(event, fileManager) { - event.canExecute = fileManager.isOnDrive(); - event.command.setHidden(!fileManager.isOnDrive()); -}; - -/** - * Sets as the command as always enabled. - * @param {Event} event Command event to mark. - */ -CommandUtil.canExecuteAlways = function(event) { - event.canExecute = true; -}; - -/** - * Returns a single selected/passed entry or null. - * @param {Event} event Command event. - * @param {FileManager} fileManager FileManager to use. - * @return {FileEntry} The entry or null. - */ -CommandUtil.getSingleEntry = function(event, fileManager) { - if (event.target.entry) { - return event.target.entry; - } - var selection = fileManager.getSelection(); - if (selection.totalCount == 1) { - return selection.entries[0]; - } - return null; -}; - -/** - * Obtains target entries that can be pinned from the selection. - * If directories are included in the selection, it just returns an empty - * array to avoid confusing because pinning directory is not supported - * currently. - * - * @return {Array.<Entry>} Target entries. - */ -CommandUtil.getPinTargetEntries = function() { - var hasDirectory = false; - var results = fileManager.getSelection().entries.filter(function(entry) { - hasDirectory = hasDirectory || entry.isDirectory; - if (!entry || hasDirectory) - return false; - var metadata = fileManager.metadataCache_.getCached(entry, 'drive'); - if (!metadata || metadata.hosted) - return false; - entry.pinned = metadata.pinned; - return true; - }); - return hasDirectory ? [] : results; -}; - -/** - * Sets the default handler for the commandId and prevents handling - * the keydown events for this command. Not doing that breaks relationship - * of original keyboard event and the command. WebKit would handle it - * differently in some cases. - * @param {Node} node to register command handler on. - * @param {string} commandId Command id to respond to. - */ -CommandUtil.forceDefaultHandler = function(node, commandId) { - var doc = node.ownerDocument; - var command = doc.querySelector('command[id="' + commandId + '"]'); - node.addEventListener('keydown', function(e) { - if (command.matchesEvent(e)) { - // Prevent cr.ui.CommandManager of handling it and leave it - // for the default handler. - e.stopPropagation(); - } - }); - node.addEventListener('command', function(event) { - if (event.command.id !== commandId) - return; - document.execCommand(event.command.id); - event.cancelBubble = true; - }); - node.addEventListener('canExecute', function(event) { - if (event.command.id === commandId) - event.canExecute = document.queryCommandEnabled(event.command.id); - }); -}; - -/** - * Default command. - * @type {Command} - */ -CommandUtil.defaultCommand = { - execute: function(event, fileManager) { - fileManager.document.execCommand(event.command.id); - }, - canExecute: function(event, fileManager) { - event.canExecute = fileManager.document.queryCommandEnabled( - event.command.id); - } -}; - -/** - * Creates the volume switch command with index. - * @param {number} index Volume index from 1 to 9. - * @return {Command} Volume switch command. - */ -CommandUtil.createVolumeSwitchCommand = function(index) { - return { - execute: function(event, fileManager) { - fileManager.navigationList.selectByIndex(index - 1); - }, - canExecute: function(event, fileManager) { - event.canExecute = index > 0 && - index <= fileManager.navigationList.dataModel.length; - } - }; -}; - -/** - * Handle of the command events. - * @param {FileManager} fileManager FileManager. - * @constructor - */ -var CommandHandler = function(fileManager) { - /** - * FileManager. - * @type {FileManager} - * @private - */ - this.fileManager_ = fileManager; - - /** - * Command elements. - * @type {Object.<string, cr.ui.Command>} - * @private - */ - this.commands_ = {}; - - /** - * Whether the ctrl key is pressed or not. - * @type {boolean} - * @private - */ - this.ctrlKeyPressed_ = false; - - Object.seal(this); - - // Decorate command tags in the document. - var commands = fileManager.document.querySelectorAll('command'); - for (var i = 0; i < commands.length; i++) { - cr.ui.Command.decorate(commands[i]); - this.commands_[commands[i].id] = commands[i]; - } - - // Register events. - fileManager.document.addEventListener('command', this.onCommand_.bind(this)); - fileManager.document.addEventListener('canExecute', - this.onCanExecute_.bind(this)); - fileManager.document.addEventListener('keydown', this.onKeyDown_.bind(this)); - fileManager.document.addEventListener('keyup', this.onKeyUp_.bind(this)); -}; - -/** - * Updates the availability of all commands. - */ -CommandHandler.prototype.updateAvailability = function() { - for (var id in this.commands_) { - this.commands_[id].canExecuteChange(); - } -}; - -/** - * Checks if the handler should ignore the current event, eg. since there is - * a popup dialog currently opened. - * - * @return {boolean} True if the event should be ignored, false otherwise. - * @private - */ -CommandHandler.prototype.shouldIgnoreEvents_ = function() { - // Do not handle commands, when a dialog is shown. - if (this.fileManager_.document.querySelector('.cr-dialog-container.shown')) - return true; - - return false; // Do not ignore. -}; - -/** - * Handles command events. - * @param {Event} event Command event. - * @private - */ -CommandHandler.prototype.onCommand_ = function(event) { - if (this.shouldIgnoreEvents_()) - return; - var handler = CommandHandler.COMMANDS_[event.command.id]; - handler.execute.call(this, event, this.fileManager_); -}; - -/** - * Handles canExecute events. - * @param {Event} event Can execute event. - * @private - */ -CommandHandler.prototype.onCanExecute_ = function(event) { - if (this.shouldIgnoreEvents_()) - return; - var handler = CommandHandler.COMMANDS_[event.command.id]; - handler.canExecute.call(this, event, this.fileManager_); -}; - -/** - * Handle key down event. - * @param {Event} event Key down event. - * @private - */ -CommandHandler.prototype.onKeyDown_ = function(event) { - // 17 is the keycode of Ctrl key and it means the event is not for other keys - // with Ctrl modifier but for ctrl key itself. - if (util.getKeyModifiers(event) + event.keyCode == 'Ctrl-17') { - this.ctrlKeyPressed_ = true; - this.updateAvailability(); - } -}; - -/** - * Handle key up event. - * @param {Event} event Key up event. - * @private - */ -CommandHandler.prototype.onKeyUp_ = function(event) { - // 17 is the keycode of Ctrl key and it means the event is not for other keys - // with Ctrl modifier but for ctrl key itself. - if (util.getKeyModifiers(event) + event.keyCode == '17') { - this.ctrlKeyPressed_ = false; - this.updateAvailability(); - } -}; - -/** - * Commands. - * @type {Object.<string, Command>} - * @const - * @private - */ -CommandHandler.COMMANDS_ = {}; - -/** - * Unmounts external drive. - * @type {Command} - */ -CommandHandler.COMMANDS_['unmount'] = { - /** - * @param {Event} event Command event. - * @param {FileManager} fileManager The file manager instance. - */ - execute: function(event, fileManager) { - var root = CommandUtil.getCommandEntry(event.target); - if (root) - fileManager.unmountVolume(PathUtil.getRootPath(root.fullPath)); - }, - /** - * @param {Event} event Command event. - */ - canExecute: function(event, fileManager) { - var rootType = CommandUtil.getCommandRootType(event.target); - - event.canExecute = (rootType == RootType.ARCHIVE || - rootType == RootType.REMOVABLE); - event.command.setHidden(!event.canExecute); - event.command.label = rootType == RootType.ARCHIVE ? - str('CLOSE_ARCHIVE_BUTTON_LABEL') : - str('UNMOUNT_DEVICE_BUTTON_LABEL'); - } -}; - -/** - * Formats external drive. - * @type {Command} - */ -CommandHandler.COMMANDS_['format'] = { - /** - * @param {Event} event Command event. - * @param {FileManager} fileManager The file manager instance. - */ - execute: function(event, fileManager) { - var directoryModel = fileManager.directoryModel; - var root = CommandUtil.getCommandEntry(event.target); - // If an entry is not found from the event target, use the current - // directory. This can happen for the format button for unsupported and - // unrecognized volumes. - if (!root) - root = directoryModel.getCurrentDirEntry(); - - // TODO(satorux): Stop assuming fullPath to be unique. crbug.com/320967 - var mountPath = root.fullPath; - var volumeInfo = fileManager.volumeManager.getVolumeInfo(mountPath); - if (volumeInfo) { - fileManager.confirm.show( - loadTimeData.getString('FORMATTING_WARNING'), - chrome.fileBrowserPrivate.formatVolume.bind(null, - volumeInfo.volumeId)); - } - }, - /** - * @param {Event} event Command event. - * @param {FileManager} fileManager The file manager instance. - */ - canExecute: function(event, fileManager) { - var directoryModel = fileManager.directoryModel; - var root = CommandUtil.getCommandEntry(event.target); - // See the comment in execute() for why doing this. - if (!root) - root = directoryModel.getCurrentDirEntry(); - var removable = root && - PathUtil.getRootType(root.fullPath) == RootType.REMOVABLE; - // Don't check if the volume is read-only. Unformatted volume is - // considered read-only per directoryModel.isPathReadOnly(), but can be - // formatted. An error will be raised if formatting failed anyway. - event.canExecute = removable; - event.command.setHidden(!removable); - } -}; - -/** - * Initiates new folder creation. - * @type {Command} - */ -CommandHandler.COMMANDS_['new-folder'] = { - execute: function(event, fileManager) { - fileManager.createNewFolder(); - }, - canExecute: function(event, fileManager) { - var directoryModel = fileManager.directoryModel; - event.canExecute = !fileManager.isOnReadonlyDirectory() && - !fileManager.isRenamingInProgress() && - !directoryModel.isSearching() && - !directoryModel.isScanning(); - } -}; - -/** - * Initiates new window creation. - * @type {Command} - */ -CommandHandler.COMMANDS_['new-window'] = { - execute: function(event, fileManager) { - fileManager.backgroundPage.launchFileManager({ - defaultPath: fileManager.getCurrentDirectory() - }); - }, - canExecute: function(event, fileManager) { - event.canExecute = - fileManager.getCurrentDirectoryEntry() && - (fileManager.dialogType === DialogType.FULL_PAGE); - } -}; - -/** - * Deletes selected files. - * @type {Command} - */ -CommandHandler.COMMANDS_['delete'] = { - execute: function(event, fileManager) { - fileManager.deleteSelection(); - }, - canExecute: function(event, fileManager) { - var allowDeletingWhileOffline = - fileManager.directoryModel.getCurrentRootType() === RootType.DRIVE; - var selection = fileManager.getSelection(); - event.canExecute = (!fileManager.isOnReadonlyDirectory() || - allowDeletingWhileOffline) && - selection && - selection.totalCount > 0; - } -}; - -/** - * Pastes files from clipboard. - * @type {Command} - */ -CommandHandler.COMMANDS_['paste'] = { - execute: function() { - document.execCommand(event.command.id); - }, - canExecute: function(event, fileManager) { - var document = fileManager.document; - var fileTransferController = fileManager.fileTransferController; - event.canExecute = (fileTransferController && - fileTransferController.queryPasteCommandEnabled()); - } -}; - -CommandHandler.COMMANDS_['cut'] = CommandUtil.defaultCommand; -CommandHandler.COMMANDS_['copy'] = CommandUtil.defaultCommand; - -/** - * Initiates file renaming. - * @type {Command} - */ -CommandHandler.COMMANDS_['rename'] = { - execute: function(event, fileManager) { - fileManager.initiateRename(); - }, - canExecute: function(event, fileManager) { - var allowRenamingWhileOffline = - fileManager.directoryModel.getCurrentRootType() === RootType.DRIVE; - var selection = fileManager.getSelection(); - event.canExecute = - !fileManager.isRenamingInProgress() && - (!fileManager.isOnReadonlyDirectory() || allowRenamingWhileOffline) && - selection && - selection.totalCount == 1; - } -}; - -/** - * Opens drive help. - * @type {Command} - */ -CommandHandler.COMMANDS_['volume-help'] = { - execute: function(event, fileManager) { - if (fileManager.isOnDrive()) - util.visitURL(str('GOOGLE_DRIVE_HELP_URL')); - else - util.visitURL(str('FILES_APP_HELP_URL')); - }, - canExecute: CommandUtil.canExecuteAlways -}; - -/** - * Opens drive buy-more-space url. - * @type {Command} - */ -CommandHandler.COMMANDS_['drive-buy-more-space'] = { - execute: function(event, fileManager) { - util.visitURL(str('GOOGLE_DRIVE_BUY_STORAGE_URL')); - }, - canExecute: CommandUtil.canExecuteVisibleOnDriveOnly -}; - -/** - * Opens drive.google.com. - * @type {Command} - */ -CommandHandler.COMMANDS_['drive-go-to-drive'] = { - execute: function(event, fileManager) { - util.visitURL(str('GOOGLE_DRIVE_ROOT_URL')); - }, - canExecute: CommandUtil.canExecuteVisibleOnDriveOnly -}; - -/** - * Displays open with dialog for current selection. - * @type {Command} - */ -CommandHandler.COMMANDS_['open-with'] = { - execute: function(event, fileManager) { - var tasks = fileManager.getSelection().tasks; - if (tasks) { - tasks.showTaskPicker(fileManager.defaultTaskPicker, - str('OPEN_WITH_BUTTON_LABEL'), - null, - function(task) { - tasks.execute(task.taskId); - }); - } - }, - canExecute: function(event, fileManager) { - var tasks = fileManager.getSelection().tasks; - event.canExecute = tasks && tasks.size() > 1; - } -}; - -/** - * Focuses search input box. - * @type {Command} - */ -CommandHandler.COMMANDS_['search'] = { - execute: function(event, fileManager) { - var element = fileManager.document.querySelector('#search-box input'); - element.focus(); - element.select(); - }, - canExecute: function(event, fileManager) { - event.canExecute = !fileManager.isRenamingInProgress(); - } -}; - -/** - * Activates the n-th volume. - * @type {Command} - */ -CommandHandler.COMMANDS_['volume-switch-1'] = - CommandUtil.createVolumeSwitchCommand(1); -CommandHandler.COMMANDS_['volume-switch-2'] = - CommandUtil.createVolumeSwitchCommand(2); -CommandHandler.COMMANDS_['volume-switch-3'] = - CommandUtil.createVolumeSwitchCommand(3); -CommandHandler.COMMANDS_['volume-switch-4'] = - CommandUtil.createVolumeSwitchCommand(4); -CommandHandler.COMMANDS_['volume-switch-5'] = - CommandUtil.createVolumeSwitchCommand(5); -CommandHandler.COMMANDS_['volume-switch-6'] = - CommandUtil.createVolumeSwitchCommand(6); -CommandHandler.COMMANDS_['volume-switch-7'] = - CommandUtil.createVolumeSwitchCommand(7); -CommandHandler.COMMANDS_['volume-switch-8'] = - CommandUtil.createVolumeSwitchCommand(8); -CommandHandler.COMMANDS_['volume-switch-9'] = - CommandUtil.createVolumeSwitchCommand(9); - -/** - * Flips 'available offline' flag on the file. - * @type {Command} - */ -CommandHandler.COMMANDS_['toggle-pinned'] = { - execute: function(event, fileManager) { - var pin = !event.command.checked; - event.command.checked = pin; - var entries = CommandUtil.getPinTargetEntries(); - var currentEntry; - var error = false; - var steps = { - // Pick an entry and pin it. - start: function() { - // Check if all the entries are pinned or not. - if (entries.length == 0) - return; - currentEntry = entries.shift(); - chrome.fileBrowserPrivate.pinDriveFile( - currentEntry.toURL(), - pin, - steps.entryPinned); - }, - - // Check the result of pinning - entryPinned: function() { - // Convert to boolean. - error = !!chrome.runtime.lastError; - if (error && pin) { - fileManager.metadataCache_.get( - currentEntry, 'filesystem', steps.showError); - } - fileManager.metadataCache_.clear(currentEntry, 'drive'); - fileManager.metadataCache_.get( - currentEntry, 'drive', steps.updateUI.bind(this)); - }, - - // Update the user interface accoding to the cache state. - updateUI: function(drive) { - fileManager.updateMetadataInUI_( - 'drive', [currentEntry.toURL()], [drive]); - if (!error) - steps.start(); - }, - - // Show the error - showError: function(filesystem) { - fileManager.alert.showHtml(str('DRIVE_OUT_OF_SPACE_HEADER'), - strf('DRIVE_OUT_OF_SPACE_MESSAGE', - unescape(currentEntry.name), - util.bytesToString(filesystem.size))); - } - }; - steps.start(); - }, - - canExecute: function(event, fileManager) { - var entries = CommandUtil.getPinTargetEntries(); - var checked = true; - for (var i = 0; i < entries.length; i++) { - checked = checked && entries[i].pinned; - } - if (entries.length > 0) { - event.canExecute = true; - event.command.setHidden(false); - event.command.checked = checked; - } else { - event.canExecute = false; - event.command.setHidden(true); - } - } -}; - -/** - * Creates zip file for current selection. - * @type {Command} - */ -CommandHandler.COMMANDS_['zip-selection'] = { - execute: function(event, fileManager) { - var dirEntry = fileManager.getCurrentDirectoryEntry(); - var selectionEntries = fileManager.getSelection().entries; - fileManager.fileOperationManager_.zipSelection(dirEntry, selectionEntries); - }, - canExecute: function(event, fileManager) { - var dirEntry = fileManager.getCurrentDirectoryEntry(); - var selection = fileManager.getSelection(); - event.canExecute = - dirEntry && - !fileManager.isOnReadonlyDirectory() && - !fileManager.isOnDrive() && - selection && selection.totalCount > 0; - } -}; - -/** - * Shows the share dialog for the current selection (single only). - * @type {Command} - */ -CommandHandler.COMMANDS_['share'] = { - execute: function(event, fileManager) { - fileManager.shareSelection(); - }, - canExecute: function(event, fileManager) { - var selection = fileManager.getSelection(); - event.canExecute = fileManager.isOnDrive() && - !fileManager.isDriveOffline() && - selection && selection.totalCount == 1; - event.command.setHidden(!fileManager.isOnDrive()); - } -}; - -/** - * Creates a shortcut of the selected folder (single only). - * @type {Command} - */ -CommandHandler.COMMANDS_['create-folder-shortcut'] = { - /** - * @param {Event} event Command event. - * @param {FileManager} fileManager The file manager instance. - */ - execute: function(event, fileManager) { - var entry = CommandUtil.getCommandEntry(event.target); - if (entry) - fileManager.createFolderShortcut(entry.fullPath); - }, - - /** - * @param {Event} event Command event. - * @param {FileManager} fileManager The file manager instance. - */ - canExecute: function(event, fileManager) { - var entry = CommandUtil.getCommandEntry(event.target); - var folderShortcutExists = entry && - fileManager.folderShortcutExists(entry.fullPath); - - var onlyOneFolderSelected = true; - // Only on list, user can select multiple files. The command is enabled only - // when a single file is selected. - if (event.target instanceof cr.ui.List && - !(event.target instanceof NavigationList)) { - var items = event.target.selectedItems; - onlyOneFolderSelected = (items.length == 1 && items[0].isDirectory); - } - - var eligible = entry && - PathUtil.isEligibleForFolderShortcut(entry.fullPath); - event.canExecute = - eligible && onlyOneFolderSelected && !folderShortcutExists; - event.command.setHidden(!eligible || !onlyOneFolderSelected); - } -}; - -/** - * Removes the folder shortcut. - * @type {Command} - */ -CommandHandler.COMMANDS_['remove-folder-shortcut'] = { - /** - * @param {Event} event Command event. - * @param {FileManager} fileManager The file manager instance. - */ - execute: function(event, fileManager) { - var entry = CommandUtil.getCommandEntry(event.target); - if (entry && entry.fullPath) - fileManager.removeFolderShortcut(entry.fullPath); - }, - - /** - * @param {Event} event Command event. - * @param {FileManager} fileManager The file manager instance. - */ - canExecute: function(event, fileManager) { - var entry = CommandUtil.getCommandEntry(event.target); - var path = entry && entry.fullPath; - - var eligible = path && PathUtil.isEligibleForFolderShortcut(path); - var isShortcut = path && fileManager.folderShortcutExists(path); - event.canExecute = isShortcut && eligible; - event.command.setHidden(!event.canExecute); - } -}; - -/** - * Zoom in to the Files.app. - * @type {Command} - */ -CommandHandler.COMMANDS_['zoom-in'] = { - execute: function(event, fileManager) { - chrome.fileBrowserPrivate.zoom('in'); - }, - canExecute: CommandUtil.canExecuteAlways -}; - -/** - * Zoom out from the Files.app. - * @type {Command} - */ -CommandHandler.COMMANDS_['zoom-out'] = { - execute: function(event, fileManager) { - chrome.fileBrowserPrivate.zoom('out'); - }, - canExecute: CommandUtil.canExecuteAlways -}; - -/** - * Reset the zoom factor. - * @type {Command} - */ -CommandHandler.COMMANDS_['zoom-reset'] = { - execute: function(event, fileManager) { - chrome.fileBrowserPrivate.zoom('reset'); - }, - canExecute: CommandUtil.canExecuteAlways -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/file_operation_manager_wrapper.js b/chromium/chrome/browser/resources/file_manager/foreground/js/file_operation_manager_wrapper.js deleted file mode 100644 index 583b9bf549e..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/file_operation_manager_wrapper.js +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * While FileOperationManager is run in the background page, this class is - * used to communicate with it. - * @param {DOMWindow} backgroundPage Window object of the background page. - * @constructor - */ -function FileOperationManagerWrapper(backgroundPage) { - this.fileOperationManager_ = - backgroundPage.FileOperationManager.getInstance(); -} - -/** - * Create a new instance or get existing instance of FCMW. - * @param {DOMWindow} backgroundPage Window object of the background page. - * @return {FileOperationManagerWrapper} FileOperationManagerWrapper instance. - */ -FileOperationManagerWrapper.getInstance = function(backgroundPage) { - if (!FileOperationManagerWrapper.instance_) - FileOperationManagerWrapper.instance_ = - new FileOperationManagerWrapper(backgroundPage); - - return FileOperationManagerWrapper.instance_; -}; - -/** - * @return {boolean} True if there is a running task. - */ -FileOperationManagerWrapper.prototype.isRunning = function() { - return this.fileOperationManager_.hasQueuedTasks(); -}; - -/** - * Decorates a FileOperationManager method, so it will be executed after - * initializing the FileOperationManager instance in background page. - * @param {string} method The method name. - */ -FileOperationManagerWrapper.decorateAsyncMethod = function(method) { - FileOperationManagerWrapper.prototype[method] = function() { - this.fileOperationManager_[method].apply( - this.fileOperationManager_, arguments); - }; -}; - -FileOperationManagerWrapper.decorateAsyncMethod('paste'); -FileOperationManagerWrapper.decorateAsyncMethod('deleteEntries'); -FileOperationManagerWrapper.decorateAsyncMethod('forceDeleteTask'); -FileOperationManagerWrapper.decorateAsyncMethod('cancelDeleteTask'); -FileOperationManagerWrapper.decorateAsyncMethod('zipSelection'); -FileOperationManagerWrapper.decorateAsyncMethod('addEventListener'); -FileOperationManagerWrapper.decorateAsyncMethod('removeEventListener'); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/file_selection.js b/chromium/chrome/browser/resources/file_manager/foreground/js/file_selection.js deleted file mode 100644 index 945a48bfa0e..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/file_selection.js +++ /dev/null @@ -1,360 +0,0 @@ -// 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. - -'use strict'; - -/** - * The current selection object. - * - * @param {FileManager} fileManager FileManager instance. - * @param {Array.<number>} indexes Selected indexes. - * @constructor - */ -function FileSelection(fileManager, indexes) { - this.fileManager_ = fileManager; - this.computeBytesSequence_ = 0; - this.indexes = indexes; - this.entries = []; - this.totalCount = 0; - this.fileCount = 0; - this.directoryCount = 0; - this.bytes = 0; - this.showBytes = false; - this.allDriveFilesPresent = false, - this.iconType = null; - this.bytesKnown = false; - this.mustBeHidden_ = false; - this.mimeTypes = null; - - // Synchronously compute what we can. - for (var i = 0; i < this.indexes.length; i++) { - var entry = fileManager.getFileList().item(this.indexes[i]); - if (!entry) - continue; - - this.entries.push(entry); - - if (this.iconType == null) { - this.iconType = FileType.getIcon(entry); - } else if (this.iconType != 'unknown') { - var iconType = FileType.getIcon(entry); - if (this.iconType != iconType) - this.iconType = 'unknown'; - } - - if (entry.isFile) { - this.fileCount += 1; - } else { - this.directoryCount += 1; - } - this.totalCount++; - } - - this.tasks = new FileTasks(this.fileManager_); - - Object.seal(this); -} - -/** - * Computes data required to get file tasks and requests the tasks. - * - * @param {function} callback The callback. - */ -FileSelection.prototype.createTasks = function(callback) { - if (!this.fileManager_.isOnDrive()) { - this.tasks.init(this.entries); - callback(); - return; - } - - this.fileManager_.metadataCache_.get(this.entries, 'drive', function(props) { - var present = props.filter(function(p) { return p && p.availableOffline }); - this.allDriveFilesPresent = present.length == props.length; - - // Collect all of the mime types and push that info into the selection. - this.mimeTypes = props.map(function(value) { - return (value && value.contentMimeType) || ''; - }); - - this.tasks.init(this.entries, this.mimeTypes); - callback(); - }.bind(this)); -}; - -/** - * Computes the total size of selected files. - * - * @param {function} callback Completion callback. Not called when cancelled, - * or a new call has been invoked in the meantime. - */ -FileSelection.prototype.computeBytes = function(callback) { - if (this.entries.length == 0) { - this.bytesKnown = true; - this.showBytes = false; - this.bytes = 0; - return; - } - - var computeBytesSequence = ++this.computeBytesSequence_; - var pendingMetadataCount = 0; - - var maybeDone = function() { - if (pendingMetadataCount == 0) { - this.bytesKnown = true; - callback(); - } - }.bind(this); - - var onProps = function(properties) { - // Ignore if the call got cancelled, or there is another new one fired. - if (computeBytesSequence != this.computeBytesSequence_) - return; - - // It may happen that the metadata is not available because a file has been - // deleted in the meantime. - if (properties) - this.bytes += properties.size; - pendingMetadataCount--; - maybeDone(); - }.bind(this); - - for (var index = 0; index < this.entries.length; index++) { - var entry = this.entries[index]; - if (entry.isFile) { - this.showBytes |= !FileType.isHosted(entry); - pendingMetadataCount++; - this.fileManager_.metadataCache_.get(entry, 'filesystem', onProps); - } else if (entry.isDirectory) { - // Don't compute the directory size as it's expensive. - // crbug.com/179073. - this.showBytes = false; - break; - } - } - maybeDone(); -}; - -/** - * Cancels any async computation by increasing the sequence number. Results - * of any previous call to computeBytes() will be discarded. - * - * @private - */ -FileSelection.prototype.cancelComputing_ = function() { - this.computeBytesSequence_++; -}; - -/** - * This object encapsulates everything related to current selection. - * - * @param {FileManager} fileManager File manager instance. - * @extends {cr.EventTarget} - * @constructor - */ -function FileSelectionHandler(fileManager) { - this.fileManager_ = fileManager; - // TODO(dgozman): create a shared object with most of UI elements. - this.okButton_ = fileManager.okButton_; - this.filenameInput_ = fileManager.filenameInput_; - this.previewPanel_ = fileManager.previewPanel_; - this.taskItems_ = fileManager.taskItems_; -} - -/** - * Create the temporary disabled action menu item. - * @return {Object} Created disabled item. - * @private - */ -FileSelectionHandler.createTemporaryDisabledActionMenuItem_ = function() { - if (!FileSelectionHandler.cachedDisabledActionMenuItem_) { - FileSelectionHandler.cachedDisabledActionMenuItem_ = { - label: str('ACTION_OPEN'), - disabled: true - }; - } - - return FileSelectionHandler.cachedDisabledActionMenuItem_; -}; - -/** - * Cached the temporary disabled action menu item. Used inside - * FileSelectionHandler.createTemporaryDisabledActionMenuItem_(). - * @private - */ -FileSelectionHandler.cachedDisabledActionMenuItem_ = null; - -/** - * FileSelectionHandler extends cr.EventTarget. - */ -FileSelectionHandler.prototype.__proto__ = cr.EventTarget.prototype; - -/** - * Maximum amount of thumbnails in the preview pane. - * - * @const - * @type {number} - */ -FileSelectionHandler.MAX_PREVIEW_THUMBNAIL_COUNT = 4; - -/** - * Maximum width or height of an image what pops up when the mouse hovers - * thumbnail in the bottom panel (in pixels). - * - * @const - * @type {number} - */ -FileSelectionHandler.IMAGE_HOVER_PREVIEW_SIZE = 200; - -/** - * Update the UI when the selection model changes. - * - * @param {Event} event The change event. - */ -FileSelectionHandler.prototype.onFileSelectionChanged = function(event) { - var indexes = - this.fileManager_.getCurrentList().selectionModel.selectedIndexes; - if (this.selection) this.selection.cancelComputing_(); - var selection = new FileSelection(this.fileManager_, indexes); - this.selection = selection; - - if (this.fileManager_.dialogType == DialogType.SELECT_SAVEAS_FILE) { - // If this is a save-as dialog, copy the selected file into the filename - // input text box. - if (this.selection.totalCount == 1 && - this.selection.entries[0].isFile && - this.filenameInput_.value != this.selection.entries[0].name) { - this.filenameInput_.value = this.selection.entries[0].name; - } - } - - this.updateOkButton(); - - if (this.selectionUpdateTimer_) { - clearTimeout(this.selectionUpdateTimer_); - this.selectionUpdateTimer_ = null; - } - - // The rest of the selection properties are computed via (sometimes lengthy) - // asynchronous calls. We initiate these calls after a timeout. If the - // selection is changing quickly we only do this once when it slows down. - - var updateDelay = 200; - var now = Date.now(); - if (now > (this.lastFileSelectionTime_ || 0) + updateDelay) { - // The previous selection change happened a while ago. Update the UI soon. - updateDelay = 0; - } - this.lastFileSelectionTime_ = now; - - if (this.fileManager_.dialogType === DialogType.FULL_PAGE && - selection.directoryCount === 0 && selection.fileCount > 0) { - // Show disabled items for position calculation of the menu. They will be - // overridden in this.updateFileSelectionAsync(). - this.fileManager_.updateContextMenuActionItems( - FileSelectionHandler.createTemporaryDisabledActionMenuItem_(), true); - } else { - // Update context menu. - this.fileManager_.updateContextMenuActionItems(null, false); - } - - this.selectionUpdateTimer_ = setTimeout(function() { - this.selectionUpdateTimer_ = null; - if (this.selection == selection) - this.updateFileSelectionAsync(selection); - }.bind(this), updateDelay); -}; - -/** - * Updates the Ok button enabled state. - * - * @return {boolean} Whether button is enabled. - */ -FileSelectionHandler.prototype.updateOkButton = function() { - var selectable; - var dialogType = this.fileManager_.dialogType; - - if (DialogType.isFolderDialog(dialogType)) { - // In SELECT_FOLDER mode, we allow to select current directory - // when nothing is selected. - selectable = this.selection.directoryCount <= 1 && - this.selection.fileCount == 0; - } else if (dialogType == DialogType.SELECT_OPEN_FILE) { - selectable = (this.isFileSelectionAvailable() && - this.selection.directoryCount == 0 && - this.selection.fileCount == 1); - } else if (dialogType == DialogType.SELECT_OPEN_MULTI_FILE) { - selectable = (this.isFileSelectionAvailable() && - this.selection.directoryCount == 0 && - this.selection.fileCount >= 1); - } else if (dialogType == DialogType.SELECT_SAVEAS_FILE) { - if (this.fileManager_.isOnReadonlyDirectory()) { - selectable = false; - } else { - selectable = !!this.filenameInput_.value; - } - } else if (dialogType == DialogType.FULL_PAGE) { - // No "select" buttons on the full page UI. - selectable = true; - } else { - throw new Error('Unknown dialog type'); - } - - this.okButton_.disabled = !selectable; - return selectable; -}; - -/** - * Check if all the files in the current selection are available. The only - * case when files might be not available is when the selection contains - * uncached Drive files and the browser is offline. - * - * @return {boolean} True if all files in the current selection are - * available. - */ -FileSelectionHandler.prototype.isFileSelectionAvailable = function() { - return !this.fileManager_.isOnDrive() || - !this.fileManager_.isDriveOffline() || - this.selection.allDriveFilesPresent; -}; - -/** - * Calculates async selection stats and updates secondary UI elements. - * - * @param {FileSelection} selection The selection object. - */ -FileSelectionHandler.prototype.updateFileSelectionAsync = function(selection) { - if (this.selection != selection) return; - - // Update the file tasks. - if (this.fileManager_.dialogType === DialogType.FULL_PAGE && - selection.directoryCount === 0 && selection.fileCount > 0) { - selection.createTasks(function() { - if (this.selection != selection) - return; - selection.tasks.display(this.taskItems_); - selection.tasks.updateMenuItem(); - }.bind(this)); - } else { - this.taskItems_.hidden = true; - } - - // Update preview panels. - var wasVisible = this.previewPanel_.visible; - this.previewPanel_.setSelection(selection); - - // Scroll to item - if (!wasVisible && this.selection.totalCount == 1) { - var list = this.fileManager_.getCurrentList(); - list.scrollIndexIntoView(list.selectionModel.selectedIndex); - } - - // Sync the commands availability. - if (this.fileManager_.commandHandler) - this.fileManager_.commandHandler.updateAvailability(); - - // Inform tests it's OK to click buttons now. - if (selection.totalCount > 0) { - chrome.test.sendMessage('selection-change-complete'); - } -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/file_table.js b/chromium/chrome/browser/resources/file_manager/foreground/js/file_table.js deleted file mode 100644 index 3280de32953..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/file_table.js +++ /dev/null @@ -1,1036 +0,0 @@ -// 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. - -'use strict'; - -/** - * Namespace for utility functions. - */ -var filelist = {}; - -/** - * Custom column model for advanced auto-resizing. - * - * @param {Array.<cr.ui.table.TableColumn>} tableColumns Table columns. - * @extends {cr.ui.table.TableColumnModel} - * @constructor - */ -function FileTableColumnModel(tableColumns) { - cr.ui.table.TableColumnModel.call(this, tableColumns); -} - -/** - * The columns whose index is less than the constant are resizable. - * @const - * @type {number} - * @private - */ -FileTableColumnModel.RESIZABLE_LENGTH_ = 4; - -/** - * Inherits from cr.ui.TableColumnModel. - */ -FileTableColumnModel.prototype.__proto__ = - cr.ui.table.TableColumnModel.prototype; - -/** - * Minimum width of column. - * @const - * @type {number} - * @private - */ -FileTableColumnModel.MIN_WIDTH_ = 10; - -/** - * Sets column width so that the column dividers move to the specified position. - * This function also check the width of each column and keep the width larger - * than MIN_WIDTH_. - * - * @private - * @param {Array.<number>} newPos Positions of each column dividers. - */ -FileTableColumnModel.prototype.applyColumnPositions_ = function(newPos) { - // Check the minimum width and adjust the positions. - for (var i = 0; i < newPos.length - 2; i++) { - if (newPos[i + 1] - newPos[i] < FileTableColumnModel.MIN_WIDTH_) { - newPos[i + 1] = newPos[i] + FileTableColumnModel.MIN_WIDTH_; - } - } - for (var i = newPos.length - 1; i >= 2; i--) { - if (newPos[i] - newPos[i - 1] < FileTableColumnModel.MIN_WIDTH_) { - newPos[i - 1] = newPos[i] - FileTableColumnModel.MIN_WIDTH_; - } - } - // Set the new width of columns - for (var i = 0; i < FileTableColumnModel.RESIZABLE_LENGTH_; i++) { - this.columns_[i].width = newPos[i + 1] - newPos[i]; - } -}; - -/** - * Normalizes widths to make their sum 100% if possible. Uses the proportional - * approach with some additional constraints. - * - * @param {number} contentWidth Target width. - * @override - */ -FileTableColumnModel.prototype.normalizeWidths = function(contentWidth) { - var totalWidth = 0; - var fixedWidth = 0; - // Some columns have fixed width. - for (var i = 0; i < this.columns_.length; i++) { - if (i < FileTableColumnModel.RESIZABLE_LENGTH_) - totalWidth += this.columns_[i].width; - else - fixedWidth += this.columns_[i].width; - } - var newTotalWidth = Math.max(contentWidth - fixedWidth, 0); - var positions = [0]; - var sum = 0; - for (var i = 0; i < FileTableColumnModel.RESIZABLE_LENGTH_; i++) { - var column = this.columns_[i]; - sum += column.width; - // Faster alternative to Math.floor for non-negative numbers. - positions[i + 1] = ~~(newTotalWidth * sum / totalWidth); - } - this.applyColumnPositions_(positions); -}; - -/** - * Handles to the start of column resizing by splitters. - */ -FileTableColumnModel.prototype.handleSplitterDragStart = function() { - this.columnPos_ = [0]; - for (var i = 0; i < this.columns_.length; i++) { - this.columnPos_[i + 1] = this.columns_[i].width + this.columnPos_[i]; - } -}; - -/** - * Handles to the end of column resizing by splitters. - */ -FileTableColumnModel.prototype.handleSplitterDragEnd = function() { - this.columnPos_ = null; -}; - -/** - * Sets the width of column with keeping the total width of table. - * @param {number} columnIndex Index of column that is resized. - * @param {number} columnWidth New width of the column. - */ -FileTableColumnModel.prototype.setWidthAndKeepTotal = function( - columnIndex, columnWidth) { - // Skip to resize 'selection' column - if (columnIndex < 0 || - columnIndex >= FileTableColumnModel.RESIZABLE_LENGTH_ || - !this.columnPos_) { - return; - } - - // Calculate new positions of column splitters. - var newPosStart = - this.columnPos_[columnIndex] + Math.max(columnWidth, - FileTableColumnModel.MIN_WIDTH_); - var newPos = []; - var posEnd = this.columnPos_[FileTableColumnModel.RESIZABLE_LENGTH_]; - for (var i = 0; i < columnIndex + 1; i++) { - newPos[i] = this.columnPos_[i]; - } - for (var i = columnIndex + 1; - i < FileTableColumnModel.RESIZABLE_LENGTH_; - i++) { - var posStart = this.columnPos_[columnIndex + 1]; - newPos[i] = (posEnd - newPosStart) * - (this.columnPos_[i] - posStart) / - (posEnd - posStart) + - newPosStart; - // Faster alternative to Math.floor for non-negative numbers. - newPos[i] = ~~newPos[i]; - } - newPos[columnIndex] = this.columnPos_[columnIndex]; - newPos[FileTableColumnModel.RESIZABLE_LENGTH_] = posEnd; - this.applyColumnPositions_(newPos); - - // Notifiy about resizing - cr.dispatchSimpleEvent(this, 'resize'); -}; - -/** - * Custom splitter that resizes column with retaining the sum of all the column - * width. - */ -var FileTableSplitter = cr.ui.define('div'); - -/** - * Inherits from cr.ui.TableSplitter. - */ -FileTableSplitter.prototype.__proto__ = cr.ui.TableSplitter.prototype; - -/** - * Handles the drag start event. - */ -FileTableSplitter.prototype.handleSplitterDragStart = function() { - cr.ui.TableSplitter.prototype.handleSplitterDragStart.call(this); - this.table_.columnModel.handleSplitterDragStart(); -}; - -/** - * Handles the drag move event. - * @param {number} deltaX Horizontal mouse move offset. - */ -FileTableSplitter.prototype.handleSplitterDragMove = function(deltaX) { - this.table_.columnModel.setWidthAndKeepTotal(this.columnIndex, - this.columnWidth_ + deltaX, - true); -}; - -/** - * Handles the drag end event. - */ -FileTableSplitter.prototype.handleSplitterDragEnd = function() { - cr.ui.TableSplitter.prototype.handleSplitterDragEnd.call(this); - this.table_.columnModel.handleSplitterDragEnd(); -}; - -/** - * File list Table View. - * @constructor - */ -function FileTable() { - throw new Error('Designed to decorate elements'); -} - -/** - * Inherits from cr.ui.Table. - */ -FileTable.prototype.__proto__ = cr.ui.Table.prototype; - -/** - * Decorates the element. - * @param {HTMLElement} self Table to decorate. - * @param {MetadataCache} metadataCache To retrieve metadata. - * @param {boolean} fullPage True if it's full page File Manager, - * False if a file open/save dialog. - */ -FileTable.decorate = function(self, metadataCache, fullPage) { - cr.ui.Table.decorate(self); - self.__proto__ = FileTable.prototype; - self.metadataCache_ = metadataCache; - self.collator_ = Intl.Collator([], {numeric: true, sensitivity: 'base'}); - - var columns = [ - new cr.ui.table.TableColumn('name', str('NAME_COLUMN_LABEL'), - fullPage ? 386 : 324), - new cr.ui.table.TableColumn('size', str('SIZE_COLUMN_LABEL'), - 110, true), - new cr.ui.table.TableColumn('type', str('TYPE_COLUMN_LABEL'), - fullPage ? 110 : 110), - new cr.ui.table.TableColumn('modificationTime', - str('DATE_COLUMN_LABEL'), - fullPage ? 150 : 210) - ]; - - columns[0].renderFunction = self.renderName_.bind(self); - columns[1].renderFunction = self.renderSize_.bind(self); - columns[1].defaultOrder = 'desc'; - columns[2].renderFunction = self.renderType_.bind(self); - columns[3].renderFunction = self.renderDate_.bind(self); - columns[3].defaultOrder = 'desc'; - - var tableColumnModelClass; - tableColumnModelClass = FileTableColumnModel; - if (self.showCheckboxes) { - columns.push(new cr.ui.table.TableColumn('selection', - '', - 50, true)); - columns[4].renderFunction = self.renderSelection_.bind(self); - columns[4].headerRenderFunction = - self.renderSelectionColumnHeader_.bind(self); - columns[4].fixed = true; - } - - var columnModel = Object.create(tableColumnModelClass.prototype, { - /** - * The number of columns. - * @type {number} - */ - size: { - /** - * @this {FileTableColumnModel} - * @return {number} Number of columns. - */ - get: function() { - return this.totalSize; - } - }, - - /** - * The number of columns. - * @type {number} - */ - totalSize: { - /** - * @this {FileTableColumnModel} - * @return {number} Number of columns. - */ - get: function() { - return columns.length; - } - }, - - /** - * Obtains a column by the specified horizontal position. - */ - getHitColumn: { - /** - * @this {FileTableColumnModel} - * @param {number} x Horizontal position. - * @return {object} The object that contains column index, column width, - * and hitPosition where the horizontal position is hit in the column. - */ - value: function(x) { - for (var i = 0; x >= this.columns_[i].width; i++) { - x -= this.columns_[i].width; - } - if (i >= this.columns_.length) - return null; - return {index: i, hitPosition: x, width: this.columns_[i].width}; - } - } - }); - - tableColumnModelClass.call(columnModel, columns); - self.columnModel = columnModel; - self.setDateTimeFormat(true); - self.setRenderFunction(self.renderTableRow_.bind(self, - self.getRenderFunction())); - - self.scrollBar_ = MainPanelScrollBar(); - self.scrollBar_.initialize(self, self.list); - // Keep focus on the file list when clicking on the header. - self.header.addEventListener('mousedown', function(e) { - self.list.focus(); - e.preventDefault(); - }); - - var handleSelectionChange = function() { - var selectAll = self.querySelector('#select-all-checkbox'); - if (selectAll) - self.updateSelectAllCheckboxState_(selectAll); - }; - - self.relayoutAggregation_ = - new AsyncUtil.Aggregation(self.relayoutImmediately_.bind(self)); - - Object.defineProperty(self.list_, 'selectionModel', { - /** - * @this {cr.ui.List} - * @return {cr.ui.ListSelectionModel} The current selection model. - */ - get: function() { - return this.selectionModel_; - }, - /** - * @this {cr.ui.List} - */ - set: function(value) { - var sm = this.selectionModel; - if (sm) - sm.removeEventListener('change', handleSelectionChange); - - util.callInheritedSetter(this, 'selectionModel', value); - sm = value; - - if (sm) - sm.addEventListener('change', handleSelectionChange); - handleSelectionChange(); - } - }); - - // Override header#redraw to use FileTableSplitter. - self.header_.redraw = function() { - this.__proto__.redraw.call(this); - // Extend table splitters - var splitters = this.querySelectorAll('.table-header-splitter'); - for (var i = 0; i < splitters.length; i++) { - if (splitters[i] instanceof FileTableSplitter) - continue; - FileTableSplitter.decorate(splitters[i]); - } - }; - - // Save the last selection. This is used by shouldStartDragSelection. - self.list.addEventListener('mousedown', function(e) { - this.lastSelection_ = this.selectionModel.selectedIndexes; - }.bind(self), true); - self.list.shouldStartDragSelection = - self.shouldStartDragSelection_.bind(self); - - /** - * Obtains the index list of elements that are hit by the point or the - * rectangle. - * - * @param {number} x X coordinate value. - * @param {number} y Y coordinate value. - * @param {=number} opt_width Width of the coordinate. - * @param {=number} opt_height Height of the coordinate. - * @return {Array.<number>} Index list of hit elements. - */ - self.list.getHitElements = function(x, y, opt_width, opt_height) { - var currentSelection = []; - var bottom = y + (opt_height || 0); - for (var i = 0; i < this.selectionModel_.length; i++) { - var itemMetrics = this.getHeightsForIndex_(i); - if (itemMetrics.top < bottom && itemMetrics.top + itemMetrics.height >= y) - currentSelection.push(i); - } - return currentSelection; - }; -}; - -/** - * Sets date and time format. - * @param {boolean} use12hourClock True if 12 hours clock, False if 24 hours. - */ -FileTable.prototype.setDateTimeFormat = function(use12hourClock) { - this.timeFormatter_ = Intl.DateTimeFormat( - [] /* default locale */, - {hour: 'numeric', minute: 'numeric', - hour12: use12hourClock}); - this.dateFormatter_ = Intl.DateTimeFormat( - [] /* default locale */, - {year: 'numeric', month: 'short', day: 'numeric', - hour: 'numeric', minute: 'numeric', - hour12: use12hourClock}); -}; - -/** - * Obtains if the drag selection should be start or not by referring the mouse - * event. - * @param {MouseEvent} event Drag start event. - * @return {boolean} True if the mouse is hit to the background of the list. - * @private - */ -FileTable.prototype.shouldStartDragSelection_ = function(event) { - // If the shift key is pressed, it should starts drag selection. - if (event.shiftKey) - return true; - - // If the position values are negative, it points the out of list. - // It should start the drag selection. - var pos = DragSelector.getScrolledPosition(this.list, event); - if (!pos) - return false; - if (pos.x < 0 || pos.y < 0) - return true; - - // If the item index is out of range, it should start the drag selection. - var itemHeight = this.list.measureItem().height; - // Faster alternative to Math.floor for non-negative numbers. - var itemIndex = ~~(pos.y / itemHeight); - if (itemIndex >= this.list.dataModel.length) - return true; - - // If the pointed item is already selected, it should not start the drag - // selection. - if (this.lastSelection_.indexOf(itemIndex) != -1) - return false; - - // If the horizontal value is not hit to column, it should start the drag - // selection. - var hitColumn = this.columnModel.getHitColumn(pos.x); - if (!hitColumn) - return true; - - // Check if the point is on the column contents or not. - var item = this.list.getListItemByIndex(itemIndex); - switch (this.columnModel.columns_[hitColumn.index].id) { - case 'name': - var spanElement = item.querySelector('.filename-label span'); - var spanRect = spanElement.getBoundingClientRect(); - // The this.list.cachedBounds_ object is set by - // DragSelector.getScrolledPosition. - if (!this.list.cachedBounds) - return true; - var textRight = - spanRect.left - this.list.cachedBounds.left + spanRect.width; - return textRight <= hitColumn.hitPosition; - default: - return true; - } -}; - -/** - * Update check and disable states of the 'Select all' checkbox. - * @param {HTMLInputElement} checkbox The checkbox. If not passed, using - * the default one. - * @private - */ -FileTable.prototype.updateSelectAllCheckboxState_ = function(checkbox) { - // TODO(serya): introduce this.selectionModel.selectedCount. - checkbox.checked = this.dataModel.length > 0 && - this.dataModel.length == this.selectionModel.selectedIndexes.length; - checkbox.disabled = this.dataModel.length == 0; -}; - -/** - * Prepares the data model to be sorted by columns. - * @param {cr.ui.ArrayDataModel} dataModel Data model to prepare. - */ -FileTable.prototype.setupCompareFunctions = function(dataModel) { - dataModel.setCompareFunction('name', - this.compareName_.bind(this)); - dataModel.setCompareFunction('modificationTime', - this.compareMtime_.bind(this)); - dataModel.setCompareFunction('size', - this.compareSize_.bind(this)); - dataModel.setCompareFunction('type', - this.compareType_.bind(this)); -}; - -/** - * Render the Name column of the detail table. - * - * Invoked by cr.ui.Table when a file needs to be rendered. - * - * @param {Entry} entry The Entry object to render. - * @param {string} columnId The id of the column to be rendered. - * @param {cr.ui.Table} table The table doing the rendering. - * @return {HTMLDivElement} Created element. - * @private - */ -FileTable.prototype.renderName_ = function(entry, columnId, table) { - var label = this.ownerDocument.createElement('div'); - label.appendChild(this.renderIconType_(entry, columnId, table)); - label.entry = entry; - label.className = 'detail-name'; - label.appendChild(filelist.renderFileNameLabel(this.ownerDocument, entry)); - return label; -}; - -/** - * Render the Selection column of the detail table. - * - * Invoked by cr.ui.Table when a file needs to be rendered. - * - * @param {Entry} entry The Entry object to render. - * @param {string} columnId The id of the column to be rendered. - * @param {cr.ui.Table} table The table doing the rendering. - * @return {HTMLDivElement} Created element. - * @private - */ -FileTable.prototype.renderSelection_ = function(entry, columnId, table) { - var label = this.ownerDocument.createElement('div'); - label.className = 'selection-label'; - if (this.selectionModel.multiple) { - var checkBox = this.ownerDocument.createElement('input'); - filelist.decorateSelectionCheckbox(checkBox, entry, this.list); - label.appendChild(checkBox); - } - return label; -}; - -/** - * Render the Size column of the detail table. - * - * @param {Entry} entry The Entry object to render. - * @param {string} columnId The id of the column to be rendered. - * @param {cr.ui.Table} table The table doing the rendering. - * @return {HTMLDivElement} Created element. - * @private - */ -FileTable.prototype.renderSize_ = function(entry, columnId, table) { - var div = this.ownerDocument.createElement('div'); - div.className = 'size'; - this.updateSize_( - div, entry, this.metadataCache_.getCached(entry, 'filesystem')); - - return div; -}; - -/** - * Sets up or updates the size cell. - * - * @param {HTMLDivElement} div The table cell. - * @param {Entry} entry The corresponding entry. - * @param {Object} filesystemProps Metadata. - * @private - */ -FileTable.prototype.updateSize_ = function(div, entry, filesystemProps) { - if (!filesystemProps) { - div.textContent = '...'; - } else if (filesystemProps.size == -1) { - div.textContent = '--'; - } else if (filesystemProps.size == 0 && - FileType.isHosted(entry)) { - div.textContent = '--'; - } else { - div.textContent = util.bytesToString(filesystemProps.size); - } -}; - -/** - * Render the Type column of the detail table. - * - * @param {Entry} entry The Entry object to render. - * @param {string} columnId The id of the column to be rendered. - * @param {cr.ui.Table} table The table doing the rendering. - * @return {HTMLDivElement} Created element. - * @private - */ -FileTable.prototype.renderType_ = function(entry, columnId, table) { - var div = this.ownerDocument.createElement('div'); - div.className = 'type'; - div.textContent = FileType.getTypeString(entry); - return div; -}; - -/** - * Render the Date column of the detail table. - * - * @param {Entry} entry The Entry object to render. - * @param {string} columnId The id of the column to be rendered. - * @param {cr.ui.Table} table The table doing the rendering. - * @return {HTMLDivElement} Created element. - * @private - */ -FileTable.prototype.renderDate_ = function(entry, columnId, table) { - var div = this.ownerDocument.createElement('div'); - div.className = 'date'; - - this.updateDate_(div, - this.metadataCache_.getCached(entry, 'filesystem')); - return div; -}; - -/** - * Sets up or updates the date cell. - * - * @param {HTMLDivElement} div The table cell. - * @param {Object} filesystemProps Metadata. - * @private - */ -FileTable.prototype.updateDate_ = function(div, filesystemProps) { - if (!filesystemProps) { - div.textContent = '...'; - return; - } - - var modTime = filesystemProps.modificationTime; - var today = new Date(); - today.setHours(0); - today.setMinutes(0); - today.setSeconds(0); - today.setMilliseconds(0); - - /** - * Number of milliseconds in a day. - */ - var MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000; - - if (modTime >= today && - modTime < today.getTime() + MILLISECONDS_IN_DAY) { - div.textContent = strf('TIME_TODAY', this.timeFormatter_.format(modTime)); - } else if (modTime >= today - MILLISECONDS_IN_DAY && modTime < today) { - div.textContent = strf('TIME_YESTERDAY', - this.timeFormatter_.format(modTime)); - } else { - div.textContent = - this.dateFormatter_.format(filesystemProps.modificationTime); - } -}; - -/** - * Updates the file metadata in the table item. - * - * @param {Element} item Table item. - * @param {Entry} entry File entry. - */ -FileTable.prototype.updateFileMetadata = function(item, entry) { - var props = this.metadataCache_.getCached(entry, 'filesystem'); - this.updateDate_(item.querySelector('.date'), props); - this.updateSize_(item.querySelector('.size'), entry, props); -}; - -/** - * Updates list items 'in place' on metadata change. - * @param {string} type Type of metadata change. - * @param {Object.<sting, Object>} propsMap Map from entry URLs to metadata - * properties. - */ -FileTable.prototype.updateListItemsMetadata = function(type, propsMap) { - var forEachCell = function(selector, callback) { - var cells = this.querySelectorAll(selector); - for (var i = 0; i < cells.length; i++) { - var cell = cells[i]; - var listItem = this.list_.getListItemAncestor(cell); - var entry = this.dataModel.item(listItem.listIndex); - if (entry) { - var props = propsMap[entry.toURL()]; - if (props) - callback.call(this, cell, entry, props, listItem); - } - } - }.bind(this); - if (type == 'filesystem') { - forEachCell('.table-row-cell > .date', function(item, entry, props) { - this.updateDate_(item, props); - }); - forEachCell('.table-row-cell > .size', function(item, entry, props) { - this.updateSize_(item, entry, props); - }); - } else if (type == 'drive') { - // The cell name does not matter as the entire list item is needed. - forEachCell('.table-row-cell > .date', - function(item, entry, props, listItem) { - filelist.updateListItemDriveProps(listItem, props); - }); - } -}; - -/** - * Compare by mtime first, then by name. - * @param {Entry} a First entry. - * @param {Entry} b Second entry. - * @return {number} Compare result. - * @private - */ -FileTable.prototype.compareName_ = function(a, b) { - return this.collator_.compare(a.name, b.name); -}; - -/** - * Compare by mtime first, then by name. - * @param {Entry} a First entry. - * @param {Entry} b Second entry. - * @return {number} Compare result. - * @private - */ -FileTable.prototype.compareMtime_ = function(a, b) { - var aCachedFilesystem = this.metadataCache_.getCached(a, 'filesystem'); - var aTime = aCachedFilesystem ? aCachedFilesystem.modificationTime : 0; - - var bCachedFilesystem = this.metadataCache_.getCached(b, 'filesystem'); - var bTime = bCachedFilesystem ? bCachedFilesystem.modificationTime : 0; - - if (aTime > bTime) - return 1; - - if (aTime < bTime) - return -1; - - return this.collator_.compare(a.name, b.name); -}; - -/** - * Compare by size first, then by name. - * @param {Entry} a First entry. - * @param {Entry} b Second entry. - * @return {number} Compare result. - * @private - */ -FileTable.prototype.compareSize_ = function(a, b) { - var aCachedFilesystem = this.metadataCache_.getCached(a, 'filesystem'); - var aSize = aCachedFilesystem ? aCachedFilesystem.size : 0; - - var bCachedFilesystem = this.metadataCache_.getCached(b, 'filesystem'); - var bSize = bCachedFilesystem ? bCachedFilesystem.size : 0; - - if (aSize != bSize) return aSize - bSize; - return this.collator_.compare(a.name, b.name); -}; - -/** - * Compare by type first, then by subtype and then by name. - * @param {Entry} a First entry. - * @param {Entry} b Second entry. - * @return {number} Compare result. - * @private - */ -FileTable.prototype.compareType_ = function(a, b) { - // Directories precede files. - if (a.isDirectory != b.isDirectory) - return Number(b.isDirectory) - Number(a.isDirectory); - - var aType = FileType.getTypeString(a); - var bType = FileType.getTypeString(b); - - var result = this.collator_.compare(aType, bType); - if (result != 0) - return result; - - return this.collator_.compare(a.name, b.name); -}; - -/** - * Renders table row. - * @param {function(Entry, cr.ui.Table)} baseRenderFunction Base renderer. - * @param {Entry} entry Corresponding entry. - * @return {HTMLLiElement} Created element. - * @private - */ -FileTable.prototype.renderTableRow_ = function(baseRenderFunction, entry) { - var item = baseRenderFunction(entry, this); - filelist.decorateListItem(item, entry, this.metadataCache_); - return item; -}; - -/** - * Renders the name column header. - * @param {string} name Localized column name. - * @return {HTMLLiElement} Created element. - * @private - */ -FileTable.prototype.renderNameColumnHeader_ = function(name) { - if (!this.selectionModel.multiple) - return this.ownerDocument.createTextNode(name); - - var input = this.ownerDocument.createElement('input'); - input.setAttribute('type', 'checkbox'); - input.setAttribute('tabindex', -1); - input.id = 'select-all-checkbox'; - input.className = 'common'; - - this.updateSelectAllCheckboxState_(input); - - input.addEventListener('click', function(event) { - if (input.checked) - this.selectionModel.selectAll(); - else - this.selectionModel.unselectAll(); - event.stopPropagation(); - }.bind(this)); - - var fragment = this.ownerDocument.createDocumentFragment(); - fragment.appendChild(input); - fragment.appendChild(this.ownerDocument.createTextNode(name)); - return fragment; -}; - -/** - * Renders the selection column header. - * @param {string} name Localized column name. - * @return {HTMLLiElement} Created element. - * @private - */ -FileTable.prototype.renderSelectionColumnHeader_ = function(name) { - if (!this.selectionModel.multiple) - return this.ownerDocument.createTextNode(''); - - var input = this.ownerDocument.createElement('input'); - input.setAttribute('type', 'checkbox'); - input.setAttribute('tabindex', -1); - input.id = 'select-all-checkbox'; - input.className = 'common'; - - this.updateSelectAllCheckboxState_(input); - - input.addEventListener('click', function(event) { - if (input.checked) - this.selectionModel.selectAll(); - else - this.selectionModel.unselectAll(); - event.stopPropagation(); - }.bind(this)); - - var fragment = this.ownerDocument.createDocumentFragment(); - fragment.appendChild(input); - return fragment; -}; - -/** - * Render the type column of the detail table. - * - * Invoked by cr.ui.Table when a file needs to be rendered. - * - * @param {Entry} entry The Entry object to render. - * @param {string} columnId The id of the column to be rendered. - * @param {cr.ui.Table} table The table doing the rendering. - * @return {HTMLDivElement} Created element. - * @private - */ -FileTable.prototype.renderIconType_ = function(entry, columnId, table) { - var icon = this.ownerDocument.createElement('div'); - icon.className = 'detail-icon'; - icon.setAttribute('file-type-icon', FileType.getIcon(entry)); - return icon; -}; - -/** - * Sets the margin height for the transparent preview panel at the bottom. - * @param {number} margin Margin to be set in px. - */ -FileTable.prototype.setBottomMarginForPanel = function(margin) { - this.list_.style.paddingBottom = margin + 'px'; - this.scrollBar_.setBottomMarginForPanel(margin); -}; - -/** - * Redraws the UI. Skips multiple consecutive calls. - */ -FileTable.prototype.relayout = function() { - this.relayoutAggregation_.run(); -}; - -/** - * Redraws the UI immediately. - * @private - */ -FileTable.prototype.relayoutImmediately_ = function() { - if (this.clientWidth > 0) - this.normalizeColumns(); - this.redraw(); - cr.dispatchSimpleEvent(this.list, 'relayout'); -}; - -/** - * Decorates (and wire up) a checkbox to be used in either a detail or a - * thumbnail list item. - * @param {HTMLInputElement} input Element to decorate. - */ -filelist.decorateCheckbox = function(input) { - var stopEventPropagation = function(event) { - if (!event.shiftKey) - event.stopPropagation(); - }; - input.setAttribute('type', 'checkbox'); - input.setAttribute('tabindex', -1); - input.classList.add('common'); - input.addEventListener('mousedown', stopEventPropagation); - input.addEventListener('mouseup', stopEventPropagation); - - input.addEventListener( - 'click', - /** - * @this {HTMLInputElement} - */ - function(event) { - // Revert default action and swallow the event - // if this is a multiple click or Shift is pressed. - if (event.detail > 1 || event.shiftKey) { - this.checked = !this.checked; - stopEventPropagation(event); - } - }); -}; - -/** - * Decorates selection checkbox. - * @param {HTMLInputElement} input Element to decorate. - * @param {Entry} entry Corresponding entry. - * @param {cr.ui.List} list Owner list. - */ -filelist.decorateSelectionCheckbox = function(input, entry, list) { - filelist.decorateCheckbox(input); - input.classList.add('file-checkbox'); - input.addEventListener('click', function(e) { - var sm = list.selectionModel; - var listIndex = list.getListItemAncestor(this).listIndex; - sm.setIndexSelected(listIndex, this.checked); - sm.leadIndex = listIndex; - if (sm.anchorIndex == -1) - sm.anchorIndex = listIndex; - - }); - // Since we do not want to open the item when tap on checkbox, we need to - // stop propagation of TAP event dispatched by checkbox ideally. But all - // touch events from touch_handler are dispatched to the list control. So we - // have to stop propagation of native touchstart event to prevent list - // control from generating TAP event here. The synthetic click event will - // select the touched checkbox/item. - input.addEventListener('touchstart', - function(e) { e.stopPropagation() }); - - var index = list.dataModel.indexOf(entry); - // Our DOM nodes get discarded as soon as we're scrolled out of view, - // so we have to make sure the check state is correct when we're brought - // back to life. - input.checked = list.selectionModel.getIndexSelected(index); -}; - -/** - * Common item decoration for table's and grid's items. - * @param {ListItem} li List item. - * @param {Entry} entry The entry. - * @param {MetadataCache} metadataCache Cache to retrieve metadada. - */ -filelist.decorateListItem = function(li, entry, metadataCache) { - li.classList.add(entry.isDirectory ? 'directory' : 'file'); - if (FileType.isOnDrive(entry)) { - // The metadata may not yet be ready. In that case, the list item will be - // updated when the metadata is ready via updateListItemsMetadata. - var driveProps = metadataCache.getCached(entry, 'drive'); - if (driveProps) - filelist.updateListItemDriveProps(li, driveProps); - } - - // Overriding the default role 'list' to 'listbox' for better - // accessibility on ChromeOS. - li.setAttribute('role', 'option'); - - Object.defineProperty(li, 'selected', { - /** - * @this {ListItem} - * @return {boolean} True if the list item is selected. - */ - get: function() { - return this.hasAttribute('selected'); - }, - - /** - * @this {ListItem} - */ - set: function(v) { - if (v) - this.setAttribute('selected', ''); - else - this.removeAttribute('selected'); - var checkBox = this.querySelector('input.file-checkbox'); - if (checkBox) - checkBox.checked = !!v; - } - }); -}; - -/** - * Render filename label for grid and list view. - * @param {HTMLDocument} doc Owner document. - * @param {Entry} entry The Entry object to render. - * @return {HTMLDivElement} The label. - */ -filelist.renderFileNameLabel = function(doc, entry) { - // Filename need to be in a '.filename-label' container for correct - // work of inplace renaming. - var box = doc.createElement('div'); - box.className = 'filename-label'; - var fileName = doc.createElement('span'); - fileName.textContent = entry.name; - box.appendChild(fileName); - - return box; -}; - -/** - * Updates grid item or table row for the driveProps. - * @param {cr.ui.ListItem} li List item. - * @param {Object} driveProps Metadata. - */ -filelist.updateListItemDriveProps = function(li, driveProps) { - if (li.classList.contains('file')) { - if (driveProps.availableOffline) - li.classList.remove('dim-offline'); - else - li.classList.add('dim-offline'); - // TODO(mtomasz): Consider adding some vidual indication for files which - // are not cached on LTE. Currently we show them as normal files. - // crbug.com/246611. - } - - if (driveProps.customIconUrl) { - var iconDiv = li.querySelector('.detail-icon'); - if (!iconDiv) - return; - iconDiv.style.backgroundImage = 'url(' + driveProps.customIconUrl + ')'; - } -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/file_tasks.js b/chromium/chrome/browser/resources/file_manager/foreground/js/file_tasks.js deleted file mode 100644 index 7bde88ca9c2..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/file_tasks.js +++ /dev/null @@ -1,834 +0,0 @@ -// 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. - -'use strict'; - -/** - * This object encapsulates everything related to tasks execution. - * - * @param {FileManager} fileManager FileManager instance. - * @param {Object=} opt_params File manager load parameters. - * @constructor - */ -function FileTasks(fileManager, opt_params) { - this.fileManager_ = fileManager; - this.params_ = opt_params; - this.tasks_ = null; - this.defaultTask_ = null; - this.entries_ = null; - - /** - * List of invocations to be called once tasks are available. - * - * @private - * @type {Array.<Object>} - */ - this.pendingInvocations_ = []; -} - -/** - * Location of the FAQ about the file actions. - * - * @const - * @type {string} - */ -FileTasks.NO_ACTION_FOR_FILE_URL = 'http://support.google.com/chromeos/bin/' + - 'answer.py?answer=1700055&topic=29026&ctx=topic'; - -/** - * Location of the Chrome Web Store. - * - * @const - * @type {string} - */ -FileTasks.CHROME_WEB_STORE_URL = 'https://chrome.google.com/webstore'; - -/** - * Base URL of apps list in the Chrome Web Store. This constant is used in - * FileTasks.createWebStoreLink(). - * - * @const - * @type {string} - */ -FileTasks.WEB_STORE_HANDLER_BASE_URL = - 'https://chrome.google.com/webstore/category/collection/file_handlers'; - -/** - * Returns URL of the Chrome Web Store which show apps supporting the given - * file-extension and mime-type. - * - * @param {string} extension Extension of the file (with the first dot). - * @param {string} mimeType Mime type of the file. - * @return {string} URL - */ -FileTasks.createWebStoreLink = function(extension, mimeType) { - if (!extension) - return FileTasks.CHROME_WEB_STORE_URL; - - if (extension[0] === '.') - extension = extension.substr(1); - else - console.warn('Please pass an extension with a dot to createWebStoreLink.'); - - var url = FileTasks.WEB_STORE_HANDLER_BASE_URL; - url += '?_fe=' + extension.toLowerCase().replace(/[^\w]/g, ''); - - // If a mime is given, add it into the URL. - if (mimeType) - url += '&_fmt=' + mimeType.replace(/[^-\w\/]/g, ''); - return url; -}; - -/** - * Complete the initialization. - * - * @param {Array.<Entry>} entries List of file entries. - * @param {Array.<string>=} opt_mimeTypes List of MIME types for each - * of the files. - */ -FileTasks.prototype.init = function(entries, opt_mimeTypes) { - this.entries_ = entries; - this.mimeTypes_ = opt_mimeTypes || []; - - // TODO(mtomasz): Move conversion from entry to url to custom bindings. - var urls = util.entriesToURLs(entries); - if (urls.length > 0) { - chrome.fileBrowserPrivate.getFileTasks(urls, this.mimeTypes_, - this.onTasks_.bind(this)); - } -}; - -/** - * Returns amount of tasks. - * - * @return {number} amount of tasks. - */ -FileTasks.prototype.size = function() { - return (this.tasks_ && this.tasks_.length) || 0; -}; - -/** - * Callback when tasks found. - * - * @param {Array.<Object>} tasks The tasks. - * @private - */ -FileTasks.prototype.onTasks_ = function(tasks) { - this.processTasks_(tasks); - for (var index = 0; index < this.pendingInvocations_.length; index++) { - var name = this.pendingInvocations_[index][0]; - var args = this.pendingInvocations_[index][1]; - this[name].apply(this, args); - } - this.pendingInvocations_ = []; -}; - -/** - * The list of known extensions to record UMA. - * Note: Because the data is recorded by the index, so new item shouldn't be - * inserted. - * - * @const - * @type {Array.<string>} - * @private - */ -FileTasks.knownExtensions_ = [ - 'other', '.3ga', '.3gp', '.aac', '.alac', '.asf', '.avi', '.bmp', '.csv', - '.doc', '.docx', '.flac', '.gif', '.ico', '.jpeg', '.jpg', '.log', '.m3u', - '.m3u8', '.m4a', '.m4v', '.mid', '.mkv', '.mov', '.mp3', '.mp4', '.mpg', - '.odf', '.odp', '.ods', '.odt', '.oga', '.ogg', '.ogv', '.pdf', '.png', - '.ppt', '.pptx', '.ra', '.ram', '.rar', '.rm', '.rtf', '.wav', '.webm', - '.webp', '.wma', '.wmv', '.xls', '.xlsx', -]; - -/** - * The list of excutable file extensions. - * - * @const - * @type {Array.<string>} - */ -FileTasks.EXECUTABLE_EXTENSIONS = Object.freeze([ - '.exe', '.lnk', '.deb', '.dmg', '.jar', '.msi', -]); - -/** - * The list of extensions to skip the suggest app dialog. - * @const - * @type {Array.<string>} - * @private - */ -FileTasks.EXTENSIONS_TO_SKIP_SUGGEST_APPS_ = Object.freeze([ - '.crdownload', '.dsc', '.inf', '.crx', -]); - -/** - * Records trial of opening file grouped by extensions. - * - * @param {Array.<Entry>} entries The entries to be opened. - * @private - */ -FileTasks.recordViewingFileTypeUMA_ = function(entries) { - for (var i = 0; i < entries.length; i++) { - var entry = entries[i]; - var extension = FileType.getExtension(entry).toLowerCase(); - if (FileTasks.knownExtensions_.indexOf(extension) < 0) { - extension = 'other'; - } - metrics.recordEnum( - 'ViewingFileType', extension, FileTasks.knownExtensions_); - } -}; - -/** - * Returns true if the taskId is for an internal task. - * - * @param {string} taskId Task identifier. - * @return {boolean} True if the task ID is for an internal task. - * @private - */ -FileTasks.isInternalTask_ = function(taskId) { - var taskParts = taskId.split('|'); - var appId = taskParts[0]; - var taskType = taskParts[1]; - var actionId = taskParts[2]; - // The action IDs here should match ones used in executeInternalTask_(). - return (appId === chrome.runtime.id && - taskType === 'file' && - (actionId === 'play' || - actionId === 'watch' || - actionId === 'mount-archive' || - actionId === 'gallery')); -}; - -/** - * Processes internal tasks. - * - * @param {Array.<Object>} tasks The tasks. - * @private - */ -FileTasks.prototype.processTasks_ = function(tasks) { - this.tasks_ = []; - var id = chrome.runtime.id; - var isOnDrive = false; - for (var index = 0; index < this.entries_.length; ++index) { - if (FileType.isOnDrive(this.entries_[index])) { - isOnDrive = true; - break; - } - } - - for (var i = 0; i < tasks.length; i++) { - var task = tasks[i]; - var taskParts = task.taskId.split('|'); - - // Skip internal Files.app's handlers. - if (taskParts[0] === id && (taskParts[2] === 'auto-open' || - taskParts[2] === 'select' || taskParts[2] === 'open')) { - continue; - } - - // Tweak images, titles of internal tasks. - if (taskParts[0] === id && taskParts[1] === 'file') { - if (taskParts[2] === 'play') { - // TODO(serya): This hack needed until task.iconUrl is working - // (see GetFileTasksFileBrowserFunction::RunImpl). - task.iconType = 'audio'; - task.title = loadTimeData.getString('ACTION_LISTEN'); - } else if (taskParts[2] === 'mount-archive') { - task.iconType = 'archive'; - task.title = loadTimeData.getString('MOUNT_ARCHIVE'); - } else if (taskParts[2] === 'gallery') { - task.iconType = 'image'; - task.title = loadTimeData.getString('ACTION_OPEN'); - } else if (taskParts[2] === 'watch') { - task.iconType = 'video'; - task.title = loadTimeData.getString('ACTION_WATCH'); - } else if (taskParts[2] === 'open-hosted-generic') { - if (this.entries_.length > 1) - task.iconType = 'generic'; - else // Use specific icon. - task.iconType = FileType.getIcon(this.entries_[0]); - task.title = loadTimeData.getString('ACTION_OPEN'); - } else if (taskParts[2] === 'open-hosted-gdoc') { - task.iconType = 'gdoc'; - task.title = loadTimeData.getString('ACTION_OPEN_GDOC'); - } else if (taskParts[2] === 'open-hosted-gsheet') { - task.iconType = 'gsheet'; - task.title = loadTimeData.getString('ACTION_OPEN_GSHEET'); - } else if (taskParts[2] === 'open-hosted-gslides') { - task.iconType = 'gslides'; - task.title = loadTimeData.getString('ACTION_OPEN_GSLIDES'); - } else if (taskParts[2] === 'view-swf') { - // Do not render this task if disabled. - if (!loadTimeData.getBoolean('SWF_VIEW_ENABLED')) - continue; - task.iconType = 'generic'; - task.title = loadTimeData.getString('ACTION_VIEW'); - } else if (taskParts[2] === 'view-pdf') { - // Do not render this task if disabled. - if (!loadTimeData.getBoolean('PDF_VIEW_ENABLED')) - continue; - task.iconType = 'pdf'; - task.title = loadTimeData.getString('ACTION_VIEW'); - } else if (taskParts[2] === 'view-in-browser') { - task.iconType = 'generic'; - task.title = loadTimeData.getString('ACTION_VIEW'); - } - } - - if (!task.iconType && taskParts[1] === 'web-intent') { - task.iconType = 'generic'; - } - - this.tasks_.push(task); - if (this.defaultTask_ === null && task.isDefault) { - this.defaultTask_ = task; - } - } - if (!this.defaultTask_ && this.tasks_.length > 0) { - // If we haven't picked a default task yet, then just pick the first one. - // This is not the preferred way we want to pick this, but better this than - // no default at all if the C++ code didn't set one. - this.defaultTask_ = this.tasks_[0]; - } -}; - -/** - * Executes default task. - * - * @param {function(boolean, Array.<string>)=} opt_callback Called when the - * default task is executed, or the error is occurred. - * @private - */ -FileTasks.prototype.executeDefault_ = function(opt_callback) { - FileTasks.recordViewingFileTypeUMA_(this.entries_); - this.executeDefaultInternal_(this.entries_, opt_callback); -}; - -/** - * Executes default task. - * - * @param {Array.<Entry>} entries Entries to execute. - * @param {function(boolean, Array.<Entry>)=} opt_callback Called when the - * default task is executed, or the error is occurred. - * @private - */ -FileTasks.prototype.executeDefaultInternal_ = function(entries, opt_callback) { - var callback = opt_callback || function(arg1, arg2) {}; - - if (this.defaultTask_ !== null) { - this.executeInternal_(this.defaultTask_.taskId, entries); - callback(true, entries); - return; - } - - // We don't have tasks, so try to show a file in a browser tab. - // We only do that for single selection to avoid confusion. - if (entries.length !== 1 || !entries[0]) - return; - - var filename = entries[0].name; - var extension = PathUtil.splitExtension(filename)[1]; - var mimeType = this.mimeTypes_[0]; - - var showAlert = function() { - var textMessageId; - var titleMessageId; - switch (extension) { - case '.exe': - textMessageId = 'NO_ACTION_FOR_EXECUTABLE'; - break; - case '.crx': - textMessageId = 'NO_ACTION_FOR_CRX'; - titleMessageId = 'NO_ACTION_FOR_CRX_TITLE'; - break; - default: - textMessageId = 'NO_ACTION_FOR_FILE'; - } - - var webStoreUrl = FileTasks.createWebStoreLink(extension, mimeType); - var text = strf(textMessageId, - webStoreUrl, - FileTasks.NO_ACTION_FOR_FILE_URL); - var title = titleMessageId ? str(titleMessageId) : filename; - this.fileManager_.alert.showHtml(title, text, function() {}); - callback(false, urls); - }.bind(this); - - var onViewFilesFailure = function() { - var fm = this.fileManager_; - if (fm.enableExperimentalWebStoreIntegration_) { - showAlert(); - return; - } - - if (!fm.isOnDrive() || - !entries[0] || - FileTasks.EXTENSIONS_TO_SKIP_SUGGEST_APPS_.indexOf(extension) !== -1) { - showAlert(); - return; - } - - fm.openSuggestAppsDialog( - entries[0], - function() { - var newTasks = new FileTasks(fm); - newTasks.init(entries, this.mimeTypes_); - newTasks.executeDefault(); - callback(true, entries); - }.bind(this), - // Cancelled callback. - function() { - callback(false, entries); - }, - showAlert); - }.bind(this); - - var onViewFiles = function(success) { - if (success) - callback(success, entries); - else - onViewFilesFailure(); - }.bind(this); - - this.checkAvailability_(function() { - // TODO(mtomasz): Pass entries instead. - var urls = util.entriesToURLs(entries); - util.viewFilesInBrowser(urls, onViewFiles); - }.bind(this)); -}; - -/** - * Executes a single task. - * - * @param {string} taskId Task identifier. - * @param {Array.<Entry>=} opt_entries Entries to xecute on instead of - * this.entries_|. - * @private - */ -FileTasks.prototype.execute_ = function(taskId, opt_entries) { - var entries = opt_entries || this.entries_; - FileTasks.recordViewingFileTypeUMA_(entries); - this.executeInternal_(taskId, entries); -}; - -/** - * The core implementation to execute a single task. - * - * @param {string} taskId Task identifier. - * @param {Array.<Entry>} entries Entries to execute. - * @private - */ -FileTasks.prototype.executeInternal_ = function(taskId, entries) { - this.checkAvailability_(function() { - if (FileTasks.isInternalTask_(taskId)) { - var taskParts = taskId.split('|'); - this.executeInternalTask_(taskParts[2], entries); - } else { - // TODO(mtomasz): Pass entries instead. - var urls = util.entriesToURLs(entries); - chrome.fileBrowserPrivate.executeTask(taskId, urls); - } - }.bind(this)); -}; - -/** - * Checks whether the remote files are available right now. - * - * @param {function} callback The callback. - * @private - */ -FileTasks.prototype.checkAvailability_ = function(callback) { - var areAll = function(props, name) { - var isOne = function(e) { - // If got no properties, we safely assume that item is unavailable. - return e && e[name]; - }; - return props.filter(isOne).length === props.length; - }; - - var fm = this.fileManager_; - var entries = this.entries_; - - if (fm.isOnDrive() && fm.isDriveOffline()) { - fm.metadataCache_.get(entries, 'drive', function(props) { - if (areAll(props, 'availableOffline')) { - callback(); - return; - } - - fm.alert.showHtml( - loadTimeData.getString('OFFLINE_HEADER'), - props[0].hosted ? - loadTimeData.getStringF( - entries.length === 1 ? - 'HOSTED_OFFLINE_MESSAGE' : - 'HOSTED_OFFLINE_MESSAGE_PLURAL') : - loadTimeData.getStringF( - entries.length === 1 ? - 'OFFLINE_MESSAGE' : - 'OFFLINE_MESSAGE_PLURAL', - loadTimeData.getString('OFFLINE_COLUMN_LABEL'))); - }); - return; - } - - if (fm.isOnDrive() && fm.isDriveOnMeteredConnection()) { - fm.metadataCache_.get(entries, 'drive', function(driveProps) { - if (areAll(driveProps, 'availableWhenMetered')) { - callback(); - return; - } - - fm.metadataCache_.get(entries, 'filesystem', function(fileProps) { - var sizeToDownload = 0; - for (var i = 0; i !== entries.length; i++) { - if (!driveProps[i].availableWhenMetered) - sizeToDownload += fileProps[i].size; - } - fm.confirm.show( - loadTimeData.getStringF( - entries.length === 1 ? - 'CONFIRM_MOBILE_DATA_USE' : - 'CONFIRM_MOBILE_DATA_USE_PLURAL', - util.bytesToString(sizeToDownload)), - callback); - }); - }); - return; - } - - callback(); -}; - -/** - * Executes an internal task. - * - * @param {string} id The short task id. - * @param {Array.<Entry>} entries The entries to execute on. - * @private - */ -FileTasks.prototype.executeInternalTask_ = function(id, entries) { - var fm = this.fileManager_; - - if (id === 'play') { - var position = 0; - if (entries.length === 1) { - // If just a single audio file is selected pass along every audio file - // in the directory. - var selectedEntries = entries[0]; - entries = fm.getAllEntriesInCurrentDirectory().filter(FileType.isAudio); - position = entries.indexOf(selectedEntries); - } - // TODO(mtomasz): Pass entries instead. - var urls = util.entriesToURLs(entries); - fm.backgroundPage.launchAudioPlayer({items: urls, position: position}); - return; - } - - if (id === 'watch') { - console.assert(entries.length === 1, 'Cannot open multiple videos'); - // TODO(mtomasz): Pass an entry instead. - fm.backgroundPage.launchVideoPlayer(entries[0].toURL()); - return; - } - - if (id === 'mount-archive') { - this.mountArchivesInternal_(entries); - return; - } - - if (id === 'gallery') { - this.openGalleryInternal_(entries); - return; - } - - console.error('Unexpected action ID: ' + id); -}; - -/** - * Mounts archives. - * - * @param {Array.<Entry>} entries Mount file entries list. - */ -FileTasks.prototype.mountArchives = function(entries) { - FileTasks.recordViewingFileTypeUMA_(entries); - this.mountArchivesInternal_(entries); -}; - -/** - * The core implementation of mounts archives. - * - * @param {Array.<Entry>} entries Mount file entries list. - * @private - */ -FileTasks.prototype.mountArchivesInternal_ = function(entries) { - var fm = this.fileManager_; - - var tracker = fm.directoryModel.createDirectoryChangeTracker(); - tracker.start(); - - // TODO(mtomasz): Pass Entries instead of URLs. - var urls = util.entriesToURLs(entries); - fm.resolveSelectResults_(urls, function(resolvedURLs) { - for (var index = 0; index < resolvedURLs.length; ++index) { - // TODO(mtomasz): Pass Entry instead of URL. - fm.volumeManager.mountArchive(resolvedURLs[index], - function(mountPath) { - tracker.stop(); - if (!tracker.hasChanged) - fm.directoryModel.changeDirectory(mountPath); - }, function(url, error) { - tracker.stop(); - var path = util.extractFilePath(url); - var namePos = path.lastIndexOf('/'); - fm.alert.show(strf('ARCHIVE_MOUNT_FAILED', - path.substr(namePos + 1), error)); - }.bind(null, resolvedURLs[index])); - } - }); -}; - -/** - * Open the Gallery. - * - * @param {Array.<Entry>} entries List of selected entries. - */ -FileTasks.prototype.openGallery = function(entries) { - FileTasks.recordViewingFileTypeUMA_(entries); - this.openGalleryInternal_(entries); -}; - -/** - * The core implementation to open the Gallery. - * - * @param {Array.<Entry>} entries List of selected entries. - * @private - */ -FileTasks.prototype.openGalleryInternal_ = function(entries) { - var fm = this.fileManager_; - - var allEntries = - fm.getAllEntriesInCurrentDirectory().filter(FileType.isImageOrVideo); - - var galleryFrame = fm.document_.createElement('iframe'); - galleryFrame.className = 'overlay-pane'; - galleryFrame.scrolling = 'no'; - galleryFrame.setAttribute('webkitallowfullscreen', true); - - if (this.params_ && this.params_.gallery) { - // Remove the Gallery state from the location, we do not need it any more. - util.updateAppState(null /* keep path */, '' /* remove search. */); - } - - var savedAppState = window.appState; - var savedTitle = document.title; - - // Push a temporary state which will be replaced every time the selection - // changes in the Gallery and popped when the Gallery is closed. - util.updateAppState(); - - var onBack = function(selectedEntries) { - fm.directoryModel.selectEntries(selectedEntries); - fm.closeFilePopup(); // Will call Gallery.unload. - window.appState = savedAppState; - util.saveAppState(); - document.title = savedTitle; - }; - - var onClose = function() { - fm.onClose(); - }; - - var onMaximize = function() { - fm.onMaximize(); - }; - - var onAppRegionChanged = function(visible) { - fm.onFilePopupAppRegionChanged(visible); - }; - - galleryFrame.onload = function() { - galleryFrame.contentWindow.ImageUtil.metrics = metrics; - - // TODO(haruki): isOnReadonlyDirectory() only checks the permission for the - // root. We should check more granular permission to know whether the file - // is writable or not. - var readonly = fm.isOnReadonlyDirectory(); - var currentDir = fm.getCurrentDirectoryEntry(); - var downloadsVolume = - fm.volumeManager.getCurrentProfileVolumeInfo(RootType.DOWNLOADS); - var downloadsDir = downloadsVolume && downloadsVolume.root; - var readonlyDirName = null; - if (readonly && currentDir) { - var rootPath = PathUtil.getRootPath(currentDir.fullPath); - readonlyDirName = fm.isOnDrive() ? - PathUtil.getRootLabel(rootPath) : - PathUtil.basename(rootPath); - } - - var context = { - // We show the root label in readonly warning (e.g. archive name). - readonlyDirName: readonlyDirName, - curDirEntry: currentDir, - saveDirEntry: readonly ? downloadsDir : null, - searchResults: fm.directoryModel.isSearching(), - metadataCache: fm.metadataCache_, - pageState: this.params_, - appWindow: chrome.app.window.current(), - onBack: onBack, - onClose: onClose, - onMaximize: onMaximize, - onAppRegionChanged: onAppRegionChanged, - displayStringFunction: strf - }; - galleryFrame.contentWindow.Gallery.open( - context, fm.volumeManager, allEntries, entries); - }.bind(this); - - galleryFrame.src = 'gallery.html'; - fm.openFilePopup(galleryFrame, fm.updateTitle_.bind(fm)); -}; - -/** - * Displays the list of tasks in a task picker combobutton. - * - * @param {cr.ui.ComboButton} combobutton The task picker element. - * @private - */ -FileTasks.prototype.display_ = function(combobutton) { - if (this.tasks_.length === 0) { - combobutton.hidden = true; - return; - } - - combobutton.clear(); - combobutton.hidden = false; - combobutton.defaultItem = this.createCombobuttonItem_(this.defaultTask_); - - var items = this.createItems_(); - - if (items.length > 1) { - var defaultIdx = 0; - - for (var j = 0; j < items.length; j++) { - combobutton.addDropDownItem(items[j]); - if (items[j].task.taskId === this.defaultTask_.taskId) - defaultIdx = j; - } - - combobutton.addSeparator(); - var changeDefaultMenuItem = combobutton.addDropDownItem({ - label: loadTimeData.getString('CHANGE_DEFAULT_MENU_ITEM') - }); - changeDefaultMenuItem.classList.add('change-default'); - } -}; - -/** - * Creates sorted array of available task descriptions such as title and icon. - * - * @return {Array} created array can be used to feed combobox, menus and so on. - * @private - */ -FileTasks.prototype.createItems_ = function() { - var items = []; - var title = this.defaultTask_.title + ' ' + - loadTimeData.getString('DEFAULT_ACTION_LABEL'); - items.push(this.createCombobuttonItem_(this.defaultTask_, title, true)); - - for (var index = 0; index < this.tasks_.length; index++) { - var task = this.tasks_[index]; - if (task !== this.defaultTask_) - items.push(this.createCombobuttonItem_(task)); - } - - items.sort(function(a, b) { - return a.label.localeCompare(b.label); - }); - - return items; -}; - -/** - * Updates context menu with default item. - * @private - */ - -FileTasks.prototype.updateMenuItem_ = function() { - this.fileManager_.updateContextMenuActionItems(this.defaultTask_, - this.tasks_.length > 1); -}; - -/** - * Creates combobutton item based on task. - * - * @param {Object} task Task to convert. - * @param {string=} opt_title Title. - * @param {boolean=} opt_bold Make a menu item bold. - * @return {Object} Item appendable to combobutton drop-down list. - * @private - */ -FileTasks.prototype.createCombobuttonItem_ = function(task, opt_title, - opt_bold) { - return { - label: opt_title || task.title, - iconUrl: task.iconUrl, - iconType: task.iconType, - task: task, - bold: opt_bold || false - }; -}; - - -/** - * Decorates a FileTasks method, so it will be actually executed after the tasks - * are available. - * This decorator expects an implementation called |method + '_'|. - * - * @param {string} method The method name. - */ -FileTasks.decorate = function(method) { - var privateMethod = method + '_'; - FileTasks.prototype[method] = function() { - if (this.tasks_) { - this[privateMethod].apply(this, arguments); - } else { - this.pendingInvocations_.push([privateMethod, arguments]); - } - return this; - }; -}; - -/** - * Shows modal action picker dialog with currently available list of tasks. - * - * @param {DefaultActionDialog} actionDialog Action dialog to show and update. - * @param {string} title Title to use. - * @param {string} message Message to use. - * @param {function(Object)} onSuccess Callback to pass selected task. - */ -FileTasks.prototype.showTaskPicker = function(actionDialog, title, message, - onSuccess) { - var items = this.createItems_(); - - var defaultIdx = 0; - for (var j = 0; j < items.length; j++) { - if (items[j].task.taskId === this.defaultTask_.taskId) - defaultIdx = j; - } - - actionDialog.show( - title, - message, - items, defaultIdx, - function(item) { - onSuccess(item.task); - }); -}; - -FileTasks.decorate('display'); -FileTasks.decorate('updateMenuItem'); -FileTasks.decorate('execute'); -FileTasks.decorate('executeDefault'); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/file_transfer_controller.js b/chromium/chrome/browser/resources/file_manager/foreground/js/file_transfer_controller.js deleted file mode 100644 index 3f8900c88d1..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/file_transfer_controller.js +++ /dev/null @@ -1,860 +0,0 @@ -// 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. - -'use strict'; - -/** - * Global (placed in the window object) variable name to hold internal - * file dragging information. Needed to show visual feedback while dragging - * since DataTransfer object is in protected state. Reachable from other - * file manager instances. - */ -var DRAG_AND_DROP_GLOBAL_DATA = '__drag_and_drop_global_data'; - -/** - * @param {HTMLDocument} doc Owning document. - * @param {FileOperationManager} fileOperationManager File operation manager - * instance. - * @param {MetadataCache} metadataCache Metadata cache service. - * @param {DirectoryModel} directoryModel Directory model instance. - * @constructor - */ -function FileTransferController(doc, - fileOperationManager, - metadataCache, - directoryModel) { - this.document_ = doc; - this.fileOperationManager_ = fileOperationManager; - this.metadataCache_ = metadataCache; - this.directoryModel_ = directoryModel; - - this.directoryModel_.getFileListSelection().addEventListener('change', - this.onSelectionChanged_.bind(this)); - - /** - * DOM element to represent selected file in drag operation. Used if only - * one element is selected. - * @type {HTMLElement} - * @private - */ - this.preloadedThumbnailImageNode_ = null; - - /** - * File objects for selected files. - * - * @type {Array.<File>} - * @private - */ - this.selectedFileObjects_ = []; - - /** - * Drag selector. - * @type {DragSelector} - * @private - */ - this.dragSelector_ = new DragSelector(); - - /** - * Whether a user is touching the device or not. - * @type {boolean} - * @private - */ - this.touching_ = false; -} - -FileTransferController.prototype = { - __proto__: cr.EventTarget.prototype, - - /** - * @this {FileTransferController} - * @param {cr.ui.List} list Items in the list will be draggable. - */ - attachDragSource: function(list) { - list.style.webkitUserDrag = 'element'; - list.addEventListener('dragstart', this.onDragStart_.bind(this, list)); - list.addEventListener('dragend', this.onDragEnd_.bind(this, list)); - list.addEventListener('touchstart', this.onTouchStart_.bind(this)); - list.addEventListener('touchend', this.onTouchEnd_.bind(this)); - }, - - /** - * @this {FileTransferController} - * @param {cr.ui.List} list List itself and its directory items will could - * be drop target. - * @param {boolean=} opt_onlyIntoDirectories If true only directory list - * items could be drop targets. Otherwise any other place of the list - * accetps files (putting it into the current directory). - */ - attachFileListDropTarget: function(list, opt_onlyIntoDirectories) { - list.addEventListener('dragover', this.onDragOver_.bind(this, - !!opt_onlyIntoDirectories, list)); - list.addEventListener('dragenter', - this.onDragEnterFileList_.bind(this, list)); - list.addEventListener('dragleave', this.onDragLeave_.bind(this, list)); - list.addEventListener('drop', - this.onDrop_.bind(this, !!opt_onlyIntoDirectories)); - }, - - /** - * @this {FileTransferController} - * @param {DirectoryTree} tree Its sub items will could be drop target. - */ - attachTreeDropTarget: function(tree) { - tree.addEventListener('dragover', this.onDragOver_.bind(this, true, tree)); - tree.addEventListener('dragenter', this.onDragEnterTree_.bind(this, tree)); - tree.addEventListener('dragleave', this.onDragLeave_.bind(this, tree)); - tree.addEventListener('drop', this.onDrop_.bind(this, true)); - }, - - /** - * @this {FileTransferController} - * @param {NavigationList} tree Its sub items will could be drop target. - */ - attachNavigationListDropTarget: function(list) { - list.addEventListener('dragover', - this.onDragOver_.bind(this, true /* onlyIntoDirectories */, list)); - list.addEventListener('dragenter', - this.onDragEnterVolumesList_.bind(this, list)); - list.addEventListener('dragleave', this.onDragLeave_.bind(this, list)); - list.addEventListener('drop', - this.onDrop_.bind(this, true /* onlyIntoDirectories */)); - }, - - /** - * Attach handlers of copy, cut and paste operations to the document. - * - * @this {FileTransferController} - */ - attachCopyPasteHandlers: function() { - this.document_.addEventListener('beforecopy', - this.onBeforeCopy_.bind(this)); - this.document_.addEventListener('copy', - this.onCopy_.bind(this)); - this.document_.addEventListener('beforecut', - this.onBeforeCut_.bind(this)); - this.document_.addEventListener('cut', - this.onCut_.bind(this)); - this.document_.addEventListener('beforepaste', - this.onBeforePaste_.bind(this)); - this.document_.addEventListener('paste', - this.onPaste_.bind(this)); - this.copyCommand_ = this.document_.querySelector('command#copy'); - }, - - /** - * Write the current selection to system clipboard. - * - * @this {FileTransferController} - * @param {DataTransfer} dataTransfer DataTransfer from the event. - * @param {string} effectAllowed Value must be valid for the - * |dataTransfer.effectAllowed| property ('move', 'copy', 'copyMove'). - */ - cutOrCopy_: function(dataTransfer, effectAllowed) { - // Tag to check it's filemanager data. - dataTransfer.setData('fs/tag', 'filemanager-data'); - dataTransfer.setData('fs/sourceRoot', - this.directoryModel_.getCurrentRootPath()); - var sourcePaths = - this.selectedEntries_.map(function(e) { return e.fullPath; }); - dataTransfer.setData('fs/sources', sourcePaths.join('\n')); - dataTransfer.effectAllowed = effectAllowed; - dataTransfer.setData('fs/effectallowed', effectAllowed); - - for (var i = 0; i < this.selectedFileObjects_.length; i++) { - dataTransfer.items.add(this.selectedFileObjects_[i]); - } - }, - - /** - * Extracts source root from the |dataTransfer| object. - * - * @this {FileTransferController} - * @param {DataTransfer} dataTransfer DataTransfer object from the event. - * @return {string} Path or empty string (if unknown). - */ - getSourceRoot_: function(dataTransfer) { - var sourceRoot = dataTransfer.getData('fs/sourceRoot'); - if (sourceRoot) - return sourceRoot; - - // |dataTransfer| in protected mode. - if (window[DRAG_AND_DROP_GLOBAL_DATA]) - return window[DRAG_AND_DROP_GLOBAL_DATA].sourceRoot; - - // Dragging from other tabs/windows. - var views = chrome && chrome.extension ? chrome.extension.getViews() : []; - for (var i = 0; i < views.length; i++) { - if (views[i][DRAG_AND_DROP_GLOBAL_DATA]) - return views[i][DRAG_AND_DROP_GLOBAL_DATA].sourceRoot; - } - - // Unknown source. - return ''; - }, - - /** - * Queue up a file copy operation based on the current system clipboard. - * - * @this {FileTransferController} - * @param {DataTransfer} dataTransfer System data transfer object. - * @param {string=} opt_destinationPath Paste destination. - * @param {string=} opt_effect Desired drop/paste effect. Could be - * 'move'|'copy' (default is copy). Ignored if conflicts with - * |dataTransfer.effectAllowed|. - * @return {string} Either "copy" or "move". - */ - paste: function(dataTransfer, opt_destinationPath, opt_effect) { - var sourcePaths = (dataTransfer.getData('fs/sources') || '').split('\n'); - var destinationPath = opt_destinationPath || - this.currentDirectoryContentPath; - // effectAllowed set in copy/paste handlers stay uninitialized. DnD handlers - // work fine. - var effectAllowed = dataTransfer.effectAllowed != 'uninitialized' ? - dataTransfer.effectAllowed : dataTransfer.getData('fs/effectallowed'); - var toMove = effectAllowed == 'move' || - (effectAllowed == 'copyMove' && opt_effect == 'move'); - - // Start the pasting operation. - this.fileOperationManager_.paste(sourcePaths, destinationPath, toMove); - return toMove ? 'move' : 'copy'; - }, - - /** - * Preloads an image thumbnail for the specified file entry. - * - * @this {FileTransferController} - * @param {Entry} entry Entry to preload a thumbnail for. - */ - preloadThumbnailImage_: function(entry) { - var metadataTypes = 'thumbnail|filesystem'; - var thumbnailContainer = this.document_.createElement('div'); - this.preloadedThumbnailImageNode_ = thumbnailContainer; - this.preloadedThumbnailImageNode_.className = 'img-container'; - this.metadataCache_.get( - entry, - metadataTypes, - function(metadata) { - new ThumbnailLoader(entry.toURL(), - ThumbnailLoader.LoaderType.IMAGE, - metadata). - load(thumbnailContainer, - ThumbnailLoader.FillMode.FILL); - }.bind(this)); - }, - - /** - * Renders a drag-and-drop thumbnail. - * - * @this {FileTransferController} - * @return {HTMLElement} Element containing the thumbnail. - */ - renderThumbnail_: function() { - var length = this.selectedEntries_.length; - - var container = this.document_.querySelector('#drag-container'); - var contents = this.document_.createElement('div'); - contents.className = 'drag-contents'; - container.appendChild(contents); - - var thumbnailImage; - if (this.preloadedThumbnailImageNode_) - thumbnailImage = this.preloadedThumbnailImageNode_.querySelector('img'); - - // Option 1. Multiple selection, render only a label. - if (length > 1) { - var label = this.document_.createElement('div'); - label.className = 'label'; - label.textContent = strf('DRAGGING_MULTIPLE_ITEMS', length); - contents.appendChild(label); - return container; - } - - // Option 2. Thumbnail image available, then render it without - // a label. - if (thumbnailImage) { - thumbnailImage.classList.add('drag-thumbnail'); - contents.classList.add('for-image'); - contents.appendChild(this.preloadedThumbnailImageNode_); - return container; - } - - // Option 3. Thumbnail not available. Render an icon and a label. - var entry = this.selectedEntries_[0]; - var icon = this.document_.createElement('div'); - icon.className = 'detail-icon'; - icon.setAttribute('file-type-icon', FileType.getIcon(entry)); - contents.appendChild(icon); - var label = this.document_.createElement('div'); - label.className = 'label'; - label.textContent = entry.name; - contents.appendChild(label); - return container; - }, - - /** - * @this {FileTransferController} - * @param {cr.ui.List} list Drop target list - * @param {Event} event A dragstart event of DOM. - */ - onDragStart_: function(list, event) { - // If a user is touching, Files.app does not receive drag operations. - if (this.touching_) { - event.preventDefault(); - return; - } - - // Check if a drag selection should be initiated or not. - if (list.shouldStartDragSelection(event)) { - this.dragSelector_.startDragSelection(list, event); - return; - } - - // Nothing selected. - if (!this.selectedEntries_.length) { - event.preventDefault(); - return; - } - - var dt = event.dataTransfer; - - if (this.canCopyOrDrag_(dt)) { - if (this.canCutOrDrag_(dt)) - this.cutOrCopy_(dt, 'copyMove'); - else - this.cutOrCopy_(dt, 'copy'); - } else { - event.preventDefault(); - return; - } - - var dragThumbnail = this.renderThumbnail_(); - dt.setDragImage(dragThumbnail, 1000, 1000); - - window[DRAG_AND_DROP_GLOBAL_DATA] = { - sourceRoot: this.directoryModel_.getCurrentRootPath() - }; - }, - - /** - * @this {FileTransferController} - * @param {cr.ui.List} list Drop target list. - * @param {Event} event A dragend event of DOM. - */ - onDragEnd_: function(list, event) { - var container = this.document_.querySelector('#drag-container'); - container.textContent = ''; - this.clearDropTarget_(); - delete window[DRAG_AND_DROP_GLOBAL_DATA]; - }, - - /** - * @this {FileTransferController} - * @param {boolean} onlyIntoDirectories True if the drag is only into - * directories. - * @param {cr.ui.List} list Drop target list. - * @param {Event} event A dragover event of DOM. - */ - onDragOver_: function(onlyIntoDirectories, list, event) { - event.preventDefault(); - var path = this.destinationPath_ || - (!onlyIntoDirectories && this.currentDirectoryContentPath); - event.dataTransfer.dropEffect = this.selectDropEffect_(event, path); - event.preventDefault(); - }, - - /** - * @this {FileTransferController} - * @param {cr.ui.List} list Drop target list. - * @param {Event} event A dragenter event of DOM. - */ - onDragEnterFileList_: function(list, event) { - event.preventDefault(); // Required to prevent the cursor flicker. - this.lastEnteredTarget_ = event.target; - var item = list.getListItemAncestor(event.target); - item = item && list.isItem(item) ? item : null; - if (item == this.dropTarget_) - return; - - var entry = item && list.dataModel.item(item.listIndex); - if (entry) { - this.setDropTarget_(item, entry.isDirectory, event.dataTransfer, - entry.fullPath); - } else { - this.clearDropTarget_(); - } - }, - - /** - * @this {FileTransferController} - * @param {DirectoryTree} tree Drop target tree. - * @param {Event} event A dragenter event of DOM. - */ - onDragEnterTree_: function(tree, event) { - event.preventDefault(); // Required to prevent the cursor flicker. - this.lastEnteredTarget_ = event.target; - var item = event.target; - while (item && !(item instanceof DirectoryItem)) { - item = item.parentNode; - } - - if (item == this.dropTarget_) - return; - - var entry = item && item.entry; - if (entry) { - this.setDropTarget_(item, entry.isDirectory, event.dataTransfer, - entry.fullPath); - } else { - this.clearDropTarget_(); - } - }, - - /** - * @this {FileTransferController} - * @param {NavigationList} list Drop target list. - * @param {Event} event A dragenter event of DOM. - */ - onDragEnterVolumesList_: function(list, event) { - event.preventDefault(); // Required to prevent the cursor flicker. - this.lastEnteredTarget_ = event.target; - var item = list.getListItemAncestor(event.target); - item = item && list.isItem(item) ? item : null; - if (item == this.dropTarget_) - return; - - var path = item && list.dataModel.item(item.listIndex).path; - if (path) - this.setDropTarget_(item, true /* directory */, event.dataTransfer, path); - else - this.clearDropTarget_(); - }, - - /** - * @this {FileTransferController} - * @param {cr.ui.List} list Drop target list. - * @param {Event} event A dragleave event of DOM. - */ - onDragLeave_: function(list, event) { - // If mouse moves from one element to another the 'dragenter' - // event for the new element comes before the 'dragleave' event for - // the old one. In this case event.target != this.lastEnteredTarget_ - // and handler of the 'dragenter' event has already caried of - // drop target. So event.target == this.lastEnteredTarget_ - // could only be if mouse goes out of listened element. - if (event.target == this.lastEnteredTarget_) { - this.clearDropTarget_(); - this.lastEnteredTarget_ = null; - } - }, - - /** - * @this {FileTransferController} - * @param {boolean} onlyIntoDirectories True if the drag is only into - * directories. - * @param {Event} event A dragleave event of DOM. - */ - onDrop_: function(onlyIntoDirectories, event) { - if (onlyIntoDirectories && !this.dropTarget_) - return; - var destinationPath = this.destinationPath_ || - this.currentDirectoryContentPath; - if (!this.canPasteOrDrop_(event.dataTransfer, destinationPath)) - return; - event.preventDefault(); - this.paste(event.dataTransfer, destinationPath, - this.selectDropEffect_(event, destinationPath)); - this.clearDropTarget_(); - }, - - /** - * Sets the drop target. - * @this {FileTransferController} - * @param {Element} domElement Target of the drop. - * @param {boolean} isDirectory If the target is a directory. - * @param {DataTransfer} dataTransfer Data transfer object. - * @param {string} destinationPath Destination path. - */ - setDropTarget_: function(domElement, isDirectory, dataTransfer, - destinationPath) { - if (this.dropTarget_ == domElement) - return; - - // Remove the old drop target. - this.clearDropTarget_(); - - // Set the new drop target. - this.dropTarget_ = domElement; - - if (!domElement || - !isDirectory || - !this.canPasteOrDrop_(dataTransfer, destinationPath)) { - return; - } - - // Add accept class if the domElement can accept the drag. - domElement.classList.add('accepts'); - this.destinationPath_ = destinationPath; - - // Start timer changing the directory. - this.navigateTimer_ = setTimeout(function() { - if (domElement instanceof DirectoryItem) - // Do custom action. - (/** @type {DirectoryItem} */ domElement).doDropTargetAction(); - this.directoryModel_.changeDirectory(destinationPath); - }.bind(this), 2000); - }, - - /** - * Handles touch start. - */ - onTouchStart_: function() { - this.touching_ = true; - }, - - /** - * Handles touch end. - */ - onTouchEnd_: function(event) { - if (event.touches.length === 0) - this.touching_ = false; - }, - - /** - * Clears the drop target. - * @this {FileTransferController} - */ - clearDropTarget_: function() { - if (this.dropTarget_ && this.dropTarget_.classList.contains('accepts')) - this.dropTarget_.classList.remove('accepts'); - this.dropTarget_ = null; - this.destinationPath_ = null; - if (this.navigateTimer_ !== undefined) { - clearTimeout(this.navigateTimer_); - this.navigateTimer_ = undefined; - } - }, - - /** - * @this {FileTransferController} - * @return {boolean} Returns false if {@code <input type="text">} element is - * currently active. Otherwise, returns true. - */ - isDocumentWideEvent_: function() { - return this.document_.activeElement.nodeName.toLowerCase() != 'input' || - this.document_.activeElement.type.toLowerCase() != 'text'; - }, - - /** - * @this {FileTransferController} - */ - onCopy_: function(event) { - if (!this.isDocumentWideEvent_() || - !this.canCopyOrDrag_()) { - return; - } - event.preventDefault(); - this.cutOrCopy_(event.clipboardData, 'copy'); - this.notify_('selection-copied'); - }, - - /** - * @this {FileTransferController} - */ - onBeforeCopy_: function(event) { - if (!this.isDocumentWideEvent_()) - return; - - // queryCommandEnabled returns true if event.defaultPrevented is true. - if (this.canCopyOrDrag_()) - event.preventDefault(); - }, - - /** - * @this {FileTransferController} - * @return {boolean} Returns true if some files are selected and all the file - * on drive is available to be copied. Otherwise, returns false. - */ - canCopyOrDrag_: function() { - if (this.isOnDrive && - this.directoryModel_.isDriveOffline() && - !this.allDriveFilesAvailable) - return false; - return this.selectedEntries_.length > 0; - }, - - /** - * @this {FileTransferController} - */ - onCut_: function(event) { - if (!this.isDocumentWideEvent_() || - !this.canCutOrDrag_()) { - return; - } - event.preventDefault(); - this.cutOrCopy_(event.clipboardData, 'move'); - this.notify_('selection-cut'); - }, - - /** - * @this {FileTransferController} - */ - onBeforeCut_: function(event) { - if (!this.isDocumentWideEvent_()) - return; - // queryCommandEnabled returns true if event.defaultPrevented is true. - if (this.canCutOrDrag_()) - event.preventDefault(); - }, - - /** - * @this {FileTransferController} - * @return {boolean} Returns true if some files are selected and all the file - * on drive is available to be cut. Otherwise, returns false. - */ - canCutOrDrag_: function() { - return !this.readonly && this.canCopyOrDrag_(); - }, - - /** - * @this {FileTransferController} - */ - onPaste_: function(event) { - // Need to update here since 'beforepaste' doesn't fire. - if (!this.isDocumentWideEvent_() || - !this.canPasteOrDrop_(event.clipboardData, - this.currentDirectoryContentPath)) { - return; - } - event.preventDefault(); - var effect = this.paste(event.clipboardData); - - // On cut, we clear the clipboard after the file is pasted/moved so we don't - // try to move/delete the original file again. - if (effect == 'move') { - this.simulateCommand_('cut', function(event) { - event.preventDefault(); - event.clipboardData.setData('fs/clear', ''); - }); - } - }, - - /** - * @this {FileTransferController} - */ - onBeforePaste_: function(event) { - if (!this.isDocumentWideEvent_()) - return; - // queryCommandEnabled returns true if event.defaultPrevented is true. - if (this.canPasteOrDrop_(event.clipboardData, - this.currentDirectoryContentPath)) { - event.preventDefault(); - } - }, - - /** - * @this {FileTransferController} - * @param {DataTransfer} dataTransfer Data transfer object. - * @param {string?} destinationPath Destination path. - * @return {boolean} Returns true if items stored in {@code dataTransfer} can - * be pasted to {@code destinationPath}. Otherwise, returns false. - */ - canPasteOrDrop_: function(dataTransfer, destinationPath) { - if (!destinationPath) { - return false; - } - if (this.directoryModel_.isPathReadOnly(destinationPath)) { - return false; - } - if (!dataTransfer.types || dataTransfer.types.indexOf('fs/tag') == -1) { - return false; // Unsupported type of content. - } - if (dataTransfer.getData('fs/tag') == '') { - // Data protected. Other checks are not possible but it makes sense to - // let the user try. - return true; - } - - var directories = dataTransfer.getData('fs/directories').split('\n'). - filter(function(d) { return d != ''; }); - - for (var i = 0; i < directories.length; i++) { - if (destinationPath.substr(0, directories[i].length) == directories[i]) - return false; // recursive paste. - } - - return true; - }, - - /** - * Execute paste command. - * - * @this {FileTransferController} - * @return {boolean} Returns true, the paste is success. Otherwise, returns - * false. - */ - queryPasteCommandEnabled: function() { - if (!this.isDocumentWideEvent_()) { - return false; - } - - // HACK(serya): return this.document_.queryCommandEnabled('paste') - // should be used. - var result; - this.simulateCommand_('paste', function(event) { - result = this.canPasteOrDrop_(event.clipboardData, - this.currentDirectoryContentPath); - }.bind(this)); - return result; - }, - - /** - * Allows to simulate commands to get access to clipboard. - * - * @this {FileTransferController} - * @param {string} command 'copy', 'cut' or 'paste'. - * @param {function} handler Event handler. - */ - simulateCommand_: function(command, handler) { - var iframe = this.document_.querySelector('#command-dispatcher'); - var doc = iframe.contentDocument; - doc.addEventListener(command, handler); - doc.execCommand(command); - doc.removeEventListener(command, handler); - }, - - /** - * @this {FileTransferController} - */ - onSelectionChanged_: function(event) { - var entries = this.selectedEntries_; - var files = this.selectedFileObjects_ = []; - this.preloadedThumbnailImageNode_ = null; - - var fileEntries = []; - for (var i = 0; i < entries.length; i++) { - if (entries[i].isFile) - fileEntries.push(entries[i]); - } - - if (entries.length == 1) { - // For single selection, the dragged element is created in advance, - // otherwise an image may not be loaded at the time the 'dragstart' event - // comes. - this.preloadThumbnailImage_(entries[0]); - } - - // File object must be prepeared in advance for clipboard operations - // (copy, paste and drag). DataTransfer object closes for write after - // returning control from that handlers so they may not have - // asynchronous operations. - var prepareFileObjects = function() { - for (var i = 0; i < fileEntries.length; i++) { - fileEntries[i].file(function(file) { files.push(file); }); - } - }; - - if (this.isOnDrive) { - this.allDriveFilesAvailable = false; - this.metadataCache_.get( - entries, 'drive', function(props) { - // We consider directories not available offline for the purposes of - // file transfer since we cannot afford to recursive traversal. - this.allDriveFilesAvailable = - entries.filter(function(e) {return e.isDirectory}).length == 0 && - props.filter(function(p) {return !p.availableOffline}).length == 0; - // |Copy| is the only menu item affected by allDriveFilesAvailable. - // It could be open right now, update its UI. - this.copyCommand_.disabled = !this.canCopyOrDrag_(); - - if (this.allDriveFilesAvailable) - prepareFileObjects(); - }.bind(this)); - } else { - prepareFileObjects(); - } - }, - - /** - * Path of directory that is displaying now. - * If search result is displaying now, this is null. - * @this {FileTransferController} - * @return {string} Path of directry that is displaying now. - */ - get currentDirectoryContentPath() { - return this.directoryModel_.isSearching() ? - null : this.directoryModel_.getCurrentDirPath(); - }, - - /** - * @this {FileTransferController} - * @return {boolean} True if the current directory is read only. - */ - get readonly() { - return this.directoryModel_.isReadOnly(); - }, - - /** - * @this {FileTransferController} - * @return {boolean} True if the current directory is on Drive. - */ - get isOnDrive() { - return PathUtil.isDriveBasedPath(this.directoryModel_.getCurrentRootPath()); - }, - - /** - * @this {FileTransferController} - */ - notify_: function(eventName) { - var self = this; - // Set timeout to avoid recursive events. - setTimeout(function() { - cr.dispatchSimpleEvent(self, eventName); - }, 0); - }, - - /** - * @this {FileTransferController} - * @return {Array.<Entry>} Array of the selected entries. - */ - get selectedEntries_() { - var list = this.directoryModel_.getFileList(); - var selectedIndexes = this.directoryModel_.getFileListSelection(). - selectedIndexes; - var entries = selectedIndexes.map(function(index) { - return list.item(index); - }); - - // TODO(serya): Diagnostics for http://crbug/129642 - if (entries.indexOf(undefined) != -1) { - var index = entries.indexOf(undefined); - entries = entries.filter(function(e) { return !!e; }); - console.error('Invalid selection found: list items: ', list.length, - 'wrong indexe value: ', selectedIndexes[index], - 'Stack trace: ', new Error().stack); - } - return entries; - }, - - /** - * @this {FileTransferController} - * @return {string} Returns the appropriate drop query type ('none', 'move' - * or copy') to the current modifiers status and the destination. - */ - selectDropEffect_: function(event, destinationPath) { - if (!destinationPath || - this.directoryModel_.isPathReadOnly(destinationPath)) - return 'none'; - if (event.dataTransfer.effectAllowed == 'copyMove' && - this.getSourceRoot_(event.dataTransfer) == - PathUtil.getRootPath(destinationPath) && - !event.ctrlKey) { - return 'move'; - } - if (event.dataTransfer.effectAllowed == 'copyMove' && - event.shiftKey) { - return 'move'; - } - return 'copy'; - }, -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/file_type.js b/chromium/chrome/browser/resources/file_manager/foreground/js/file_type.js deleted file mode 100644 index ea0ae9278ee..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/file_type.js +++ /dev/null @@ -1,294 +0,0 @@ -// 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. - -'use strict'; - -/** - * Namespace object for file type utility functions. - */ -var FileType = {}; - -/** - * Description of known file types. - * Pair type-subtype defines order when sorted by file type. - */ -FileType.types = [ - // Images - {type: 'image', name: 'IMAGE_FILE_TYPE', subtype: 'JPEG', - pattern: /\.jpe?g$/i}, - {type: 'image', name: 'IMAGE_FILE_TYPE', subtype: 'BMP', - pattern: /\.bmp$/i}, - {type: 'image', name: 'IMAGE_FILE_TYPE', subtype: 'GIF', - pattern: /\.gif$/i}, - {type: 'image', name: 'IMAGE_FILE_TYPE', subtype: 'ICO', - pattern: /\.ico$/i}, - {type: 'image', name: 'IMAGE_FILE_TYPE', subtype: 'PNG', - pattern: /\.png$/i}, - {type: 'image', name: 'IMAGE_FILE_TYPE', subtype: 'WebP', - pattern: /\.webp$/i}, - {type: 'image', name: 'IMAGE_FILE_TYPE', subtype: 'TIFF', - pattern: /\.tiff?$/i}, - - // Video - {type: 'video', name: 'VIDEO_FILE_TYPE', subtype: '3GP', - pattern: /\.3gp$/i}, - {type: 'video', name: 'VIDEO_FILE_TYPE', subtype: 'AVI', - pattern: /\.avi$/i}, - {type: 'video', name: 'VIDEO_FILE_TYPE', subtype: 'QuickTime', - pattern: /\.mov$/i}, - {type: 'video', name: 'VIDEO_FILE_TYPE', subtype: 'MKV', - pattern: /\.mkv$/i}, - {type: 'video', name: 'VIDEO_FILE_TYPE', subtype: 'MPEG', - pattern: /\.m(p4|4v|pg|peg|pg4|peg4)$/i}, - {type: 'video', name: 'VIDEO_FILE_TYPE', subtype: 'OGG', - pattern: /\.og(m|v|x)$/i}, - {type: 'video', name: 'VIDEO_FILE_TYPE', subtype: 'WebM', - pattern: /\.webm$/i}, - - // Audio - {type: 'audio', name: 'AUDIO_FILE_TYPE', subtype: 'AMR', - pattern: /\.amr$/i}, - {type: 'audio', name: 'AUDIO_FILE_TYPE', subtype: 'FLAC', - pattern: /\.flac$/i}, - {type: 'audio', name: 'AUDIO_FILE_TYPE', subtype: 'MP3', - pattern: /\.mp3$/i}, - {type: 'audio', name: 'AUDIO_FILE_TYPE', subtype: 'MPEG', - pattern: /\.m4a$/i}, - {type: 'audio', name: 'AUDIO_FILE_TYPE', subtype: 'OGG', - pattern: /\.og(a|g)$/i}, - {type: 'audio', name: 'AUDIO_FILE_TYPE', subtype: 'WAV', - pattern: /\.wav$/i}, - - // Text - {type: 'text', name: 'PLAIN_TEXT_FILE_TYPE', subtype: 'TXT', - pattern: /\.txt$/i}, - - // Archive - {type: 'archive', name: 'ZIP_ARCHIVE_FILE_TYPE', subtype: 'ZIP', - pattern: /\.zip$/i}, - {type: 'archive', name: 'RAR_ARCHIVE_FILE_TYPE', subtype: 'RAR', - pattern: /\.rar$/i}, - {type: 'archive', name: 'TAR_ARCHIVE_FILE_TYPE', subtype: 'TAR', - pattern: /\.tar$/i}, - {type: 'archive', name: 'TAR_BZIP2_ARCHIVE_FILE_TYPE', subtype: 'TBZ2', - pattern: /\.(tar\.bz2|tbz|tbz2)$/i}, - {type: 'archive', name: 'TAR_GZIP_ARCHIVE_FILE_TYPE', subtype: 'TGZ', - pattern: /\.(tar\.|t)gz$/i}, - - // Hosted docs. - {type: 'hosted', icon: 'gdoc', name: 'GDOC_DOCUMENT_FILE_TYPE', - subtype: 'doc', pattern: /\.gdoc$/i}, - {type: 'hosted', icon: 'gsheet', name: 'GSHEET_DOCUMENT_FILE_TYPE', - subtype: 'sheet', pattern: /\.gsheet$/i}, - {type: 'hosted', icon: 'gslides', name: 'GSLIDES_DOCUMENT_FILE_TYPE', - subtype: 'slides', pattern: /\.gslides$/i}, - {type: 'hosted', icon: 'gdraw', name: 'GDRAW_DOCUMENT_FILE_TYPE', - subtype: 'draw', pattern: /\.gdraw$/i}, - {type: 'hosted', icon: 'gtable', name: 'GTABLE_DOCUMENT_FILE_TYPE', - subtype: 'table', pattern: /\.gtable$/i}, - {type: 'hosted', icon: 'glink', name: 'GLINK_DOCUMENT_FILE_TYPE', - subtype: 'glink', pattern: /\.glink$/i}, - {type: 'hosted', icon: 'gform', name: 'GFORM_DOCUMENT_FILE_TYPE', - subtype: 'form', pattern: /\.gform$/i}, - - // Others - {type: 'document', icon: 'pdf', name: 'PDF_DOCUMENT_FILE_TYPE', - subtype: 'PDF', pattern: /\.pdf$/i}, - {type: 'document', name: 'HTML_DOCUMENT_FILE_TYPE', - subtype: 'HTML', pattern: /\.(html?|mht|mhtml)$/i}, - {type: 'document', icon: 'word', name: 'WORD_DOCUMENT_FILE_TYPE', - subtype: 'Word', pattern: /\.(doc|docx)$/i}, - {type: 'document', icon: 'ppt', name: 'POWERPOINT_PRESENTATION_FILE_TYPE', - subtype: 'PPT', pattern: /\.(ppt|pptx)$/i}, - {type: 'document', icon: 'excel', name: 'EXCEL_FILE_TYPE', - subtype: 'Excel', pattern: /\.(xls|xlsx)$/i} -]; - -/** - * A special type for directory. - */ -FileType.DIRECTORY = {name: 'FOLDER', type: '.folder', icon: 'folder'}; - -/** - * Returns the file path extension for a given file. - * - * @param {string|Entry} file Reference to the file. - * Can be a name, a path, a url or a File API Entry. - * @return {string} The extension including a leading '.', or empty string if - * not found. - */ -FileType.getExtension = function(file) { - var fileName; - if (typeof file == 'object') { - if (file.isDirectory) { - // No extension for a directory. - return ''; - } else { - fileName = file.name; - } - } else { - fileName = file; - } - - var extensionStartIndex = fileName.lastIndexOf('.'); - if (extensionStartIndex == -1 || extensionStartIndex == fileName.length - 1) { - return ''; - } - return fileName.substr(extensionStartIndex); -}; - -/** - * Get the file type object for a given file. - * - * @param {string|Entry} file Reference to the file. - * Can be a name, a path, a url or a File API Entry. - * @return {Object} The matching file type object or an empty object. - */ -FileType.getType = function(file) { - if (typeof file == 'object') { - if (file.isDirectory) - return FileType.DIRECTORY; - else - file = file.name; - } - var types = FileType.types; - for (var i = 0; i < types.length; i++) { - if (types[i].pattern.test(file)) { - return types[i]; - } - } - - // Unknown file type. - var extension = FileType.getExtension(file); - if (extension == '') { - return { name: 'NO_EXTENSION_FILE_TYPE', type: 'UNKNOWN', icon: '' }; - } - // subtype is the extension excluding the first dot. - return { name: 'GENERIC_FILE_TYPE', type: 'UNKNOWN', - subtype: extension.substr(1).toUpperCase(), icon: '' }; -}; - -/** - * @param {string|Entry} file Reference to the file. - * Can be a name, a path, a url or a File API Entry. - * @return {string} Localized string representation of file type. - */ -FileType.getTypeString = function(file) { - var fileType = FileType.getType(file); - if (fileType.subtype) - return strf(fileType.name, fileType.subtype); - else - return str(fileType.name); -}; - -/** - * Pattern for urls pointing to Google Drive files. - */ -FileType.DRIVE_URL_PATTERN = - new RegExp('^filesystem:[^/]*://[^/]*/[^/]*/drive/(.*)'); - -/** - * Pattern for file paths pointing to Google Drive files. - */ -FileType.DRIVE_PATH_PATTERN = - new RegExp('^/drive/'); - -/** - * @param {string|Entry} file The url string or entry. - * @return {boolean} Whether this provider supports the url. - */ -FileType.isOnDrive = function(file) { - return typeof file == 'string' ? - FileType.DRIVE_URL_PATTERN.test(file) : - FileType.DRIVE_PATH_PATTERN.test(file.fullPath); -}; - - -/** - * Get the media type for a given file. - * - * @param {string|Entry} file Reference to the file. - * @return {string} The value of 'type' property from one of the elements in - * FileType.types or undefined. - */ -FileType.getMediaType = function(file) { - return FileType.getType(file).type; -}; - -/** - * @param {string|Entry} file Reference to the file. - * @return {boolean} True if audio file. - */ -FileType.isAudio = function(file) { - return FileType.getMediaType(file) == 'audio'; -}; - -/** - * @param {string|Entry} file Reference to the file. - * @return {boolean} True if image file. - */ -FileType.isImage = function(file) { - return FileType.getMediaType(file) == 'image'; -}; - -/** - * @param {string|Entry} file Reference to the file. - * @return {boolean} True if video file. - */ -FileType.isVideo = function(file) { - return FileType.getMediaType(file) == 'video'; -}; - - -/** - * Files with more pixels won't have preview. - * @param {string|Entry} file Reference to the file. - * @return {boolean} True if image or video. - */ -FileType.isImageOrVideo = function(file) { - var type = FileType.getMediaType(file); - return type == 'image' || type == 'video'; -}; - -/** - * @param {string|Entry} file Reference to the file. - * @return {boolean} Returns true if the file is hosted. - */ -FileType.isHosted = function(file) { - return FileType.getType(file).type === 'hosted'; -}; - -/** - * @param {string|Entry} file Reference to the file. - * @return {boolean} Returns true if the file is not hidden, and we should - * display it. - */ -FileType.isVisible = function(file) { - if (typeof file == 'object') { - file = file.name; - } - - var path = util.extractFilePath(file); - if (path) file = path; - - file = file.split('/').pop(); - return file.indexOf('.') != 0 && !(file in FileType.HIDDEN_NAMES); -}; - -/** - * File/directory names that we know are usually hidden. - */ -FileType.HIDDEN_NAMES = { - 'RECYCLED': true -}; - -/** - * @param {string|Entry} file Reference to the file. - * @return {string} Returns string that represents the file icon. - * It refers to a file 'images/filetype_' + icon + '.png'. - */ -FileType.getIcon = function(file) { - var fileType = FileType.getType(file); - return fileType.icon || fileType.type || 'unknown'; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/file_watcher.js b/chromium/chrome/browser/resources/file_manager/foreground/js/file_watcher.js deleted file mode 100644 index a6414e61f4a..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/file_watcher.js +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * Watches for changes in the tracked directory, including local metadata - * changes. - * - * @param {MetadataCache} metadataCache Instance of MetadataCache. - * @extends {cr.EventTarget} - * @constructor - */ -function FileWatcher(metadataCache) { - this.queue_ = new AsyncUtil.Queue(); - this.metadataCache_ = metadataCache; - this.watchedDirectoryEntry_ = null; - - this.onDirectoryChangedBound_ = this.onDirectoryChanged_.bind(this); - chrome.fileBrowserPrivate.onDirectoryChanged.addListener( - this.onDirectoryChangedBound_); - - this.filesystemMetadataObserverId_ = null; - this.thumbnailMetadataObserverId_ = null; - this.driveMetadataObserverId_ = null; -} - -/** - * FileWatcher extends cr.EventTarget. - */ -FileWatcher.prototype.__proto__ = cr.EventTarget.prototype; - -/** - * Stops watching (must be called before page unload). - */ -FileWatcher.prototype.dispose = function() { - chrome.fileBrowserPrivate.onDirectoryChanged.removeListener( - this.onDirectoryChangedBound_); - if (this.watchedDirectoryEntry_) - this.resetWatchedEntry_(function() {}, function() {}); -}; - -/** - * Called when a file in the watched directory is changed. - * @param {Event} event Change event. - * @private - */ -FileWatcher.prototype.onDirectoryChanged_ = function(event) { - if (this.watchedDirectoryEntry_ && - event.entry.toURL() === this.watchedDirectoryEntry_.toURL()) { - var e = new Event('watcher-directory-changed'); - this.dispatchEvent(e); - } -}; - -/** - * Called when general metadata in the watched directory has been changed. - * - * @param {Array.<Entry>} entries Array of entries. - * @param {Object.<string, Object>} properties Map from entry URLs to metadata - * properties. - * @private - */ -FileWatcher.prototype.onFilesystemMetadataChanged_ = function( - entries, properties) { - this.dispatchMetadataEvent_('filesystem', entries, properties); -}; - -/** - * Called when thumbnail metadata in the watched directory has been changed. - * - * @param {Array.<Entry>} entries Arrray of entries. - * @param {Object.<string, Object>} properties Map from entry URLs to metadata - * properties. - * @private - */ -FileWatcher.prototype.onThumbnailMetadataChanged_ = function( - entries, properties) { - this.dispatchMetadataEvent_('thumbnail', entries, properties); -}; - -/** - * Called when drive metadata in the watched directory has been changed. - * - * @param {Array.<Entry>} entries Array of entries. - * @param {Object.<string, Object>} properties Map from entry URLs to metadata - * properties. - * @private - */ -FileWatcher.prototype.onDriveMetadataChanged_ = function( - entries, properties) { - this.dispatchMetadataEvent_('drive', entries, properties); -}; - -/** - * Dispatches an event about detected change in metadata within the tracked - * directory. - * - * @param {string} type Type of the metadata change. - * @param {Array.<Entry>} entries Array of entries. - * @param {Object.<string, Object>} properties Map from entry URLs to metadata - * properties. - * @private - */ -FileWatcher.prototype.dispatchMetadataEvent_ = function( - type, entries, properties) { - var e = new Event('watcher-metadata-changed'); - e.metadataType = type; - e.entries = entries; - e.properties = properties; - this.dispatchEvent(e); -}; - -/** - * Changes the watched directory. In case of a fake entry, the watch is - * just released, since there is no reason to track a fake directory. - * - * @param {!DirectoryEntry|!Object} entry Directory entry to be tracked, or the - * fake entry. - * @param {function()} callback Completion callback. - */ -FileWatcher.prototype.changeWatchedDirectory = function(entry, callback) { - if (entry && entry.toURL) { - this.changeWatchedEntry_( - entry, - callback, - function() { - console.error( - 'Unable to change the watched directory to: ' + entry.toURL()); - callback(); - }); - } else { - this.resetWatchedEntry_( - callback, - function() { - console.error('Unable to reset the watched directory.'); - callback(); - }); - } -}; - -/** - * Resets the watched entry to the passed directory. - * - * @param {function()} onSuccess Success callback. - * @param {function()} onError Error callback. - * @private - */ -FileWatcher.prototype.resetWatchedEntry_ = function(onSuccess, onError) { - // Run the tasks in the queue to avoid races. - this.queue_.run(function(callback) { - // Release the watched directory. - if (this.watchedDirectoryEntry_) { - chrome.fileBrowserPrivate.removeFileWatch( - this.watchedDirectoryEntry_.toURL(), - function(result) { - this.watchedDirectoryEntry_ = null; - if (result) - onSuccess(); - else - onError(); - callback(); - }.bind(this)); - this.metadataCache_.removeObserver(this.filesystemMetadataObserverId_); - this.metadataCache_.removeObserver(this.thumbnailMetadataObserverId_); - this.metadataCache_.removeObserver(this.driveMetadataObserverId_); - } else { - onSuccess(); - callback(); - } - }.bind(this)); -}; - -/** - * Sets the watched entry to the passed directory. - * - * @param {!DirectoryEntry} entry Directory to be watched. - * @param {function()} onSuccess Success callback. - * @param {function()} onError Error callback. - * @private - */ -FileWatcher.prototype.changeWatchedEntry_ = function( - entry, onSuccess, onError) { - var setEntryClosure = function() { - // Run the tasks in the queue to avoid races. - this.queue_.run(function(callback) { - chrome.fileBrowserPrivate.addFileWatch( - entry.toURL(), - function(result) { - if (!result) { - this.watchedDirectoryEntry_ = null; - onError(); - } else { - this.watchedDirectoryEntry_ = entry; - onSuccess(); - } - callback(); - }.bind(this)); - this.filesystemMetadataObserverId_ = this.metadataCache_.addObserver( - entry, - MetadataCache.CHILDREN, - 'filesystem', - this.onFilesystemMetadataChanged_.bind(this)); - this.thumbnailMetadataObserverId_ = this.metadataCache_.addObserver( - entry, - MetadataCache.CHILDREN, - 'thumbnail', - this.onThumbnailMetadataChanged_.bind(this)); - this.driveMetadataObserverId_ = this.metadataCache_.addObserver( - entry, - MetadataCache.CHILDREN, - 'drive', - this.onDriveMetadataChanged_.bind(this)); - }.bind(this)); - }.bind(this); - - // Reset the watched directory first, then set the new watched directory. - this.resetWatchedEntry_(setEntryClosure, onError); -}; - -/** - * @return {DirectoryEntry} Current watched directory entry. - */ -FileWatcher.prototype.getWatchedDirectoryEntry = function() { - return this.watchedDirectoryEntry_; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/folder_shortcuts_data_model.js b/chromium/chrome/browser/resources/file_manager/foreground/js/folder_shortcuts_data_model.js deleted file mode 100644 index 9467f5eec07..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/folder_shortcuts_data_model.js +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright (c) 2013 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. - -/** - * Model for the folder shortcuts. This object is cr.ui.ArrayDataModel-like - * object with additional methods for the folder shortcut feature. - * This uses chrome.storage as backend. Items are always sorted by file path. - * - * @constructor - * @extends {cr.EventTarget} - */ -function FolderShortcutsDataModel() { - this.array_ = []; - - /** - * Eliminate unsupported folders from the list. - * - * @param {Array.<string>} array Folder array which may contain the - * unsupported folders. - * @return {Array.<string>} Folder list without unsupported folder. - */ - var filter = function(array) { - return array.filter(PathUtil.isEligibleForFolderShortcut); - }; - - // Loads the contents from the storage to initialize the array. - chrome.storage.sync.get(FolderShortcutsDataModel.NAME, function(value) { - if (!(FolderShortcutsDataModel.NAME in value)) - return; - - // Since the value comes from outer resource, we have to check it just in - // case. - var list = value[FolderShortcutsDataModel.NAME]; - if (list instanceof Array) { - list = filter(list); - - // Record metrics. - metrics.recordSmallCount('FolderShortcut.Count', list.length); - - var permutation = this.calculatePermutation_(this.array_, list); - this.array_ = list; - this.firePermutedEvent_(permutation); - } - }.bind(this)); - - // Listening for changes in the storage. - chrome.storage.onChanged.addListener(function(changes, namespace) { - if (!(FolderShortcutsDataModel.NAME in changes) || namespace != 'sync') - return; - - var list = changes[FolderShortcutsDataModel.NAME].newValue; - // Since the value comes from outer resource, we have to check it just in - // case. - if (list instanceof Array) { - list = filter(list); - - // If the list is not changed, do nothing and just return. - if (this.array_.length == list.length) { - var changed = false; - for (var i = 0; i < this.array_.length; i++) { - // Same item check: must be exact match. - if (this.array_[i] != list[i]) { - changed = true; - break; - } - } - if (!changed) - return; - } - - var permutation = this.calculatePermutation_(this.array_, list); - this.array_ = list; - this.firePermutedEvent_(permutation); - } - }.bind(this)); -} - -/** - * Key name in chrome.storage. The array are stored with this name. - * @type {string} - * @const - */ -FolderShortcutsDataModel.NAME = 'folder-shortcuts-list'; - -FolderShortcutsDataModel.prototype = { - __proto__: cr.EventTarget.prototype, - - /** - * @return {number} Number of elements in the array. - */ - get length() { - return this.array_.length; - }, - - /** - * Returns the paths in the given range as a new array instance. The - * arguments and return value are compatible with Array.slice(). - * - * @param {number} start Where to start the selection. - * @param {number=} opt_end Where to end the selection. - * @return {Array.<string>} Paths in the selected range. - */ - slice: function(begin, opt_end) { - return this.array_.slice(begin, opt_end); - }, - - /** - * @param {number} index Index of the element to be retrieved. - * @return {string} The value of the |index|-th element. - */ - item: function(index) { - return this.array_[index]; - }, - - /** - * @param {string} value Value of the element to be retrieved. - * @return {number} Index of the element with the specified |value|. - */ - getIndex: function(value) { - for (var i = 0; i < this.length; i++) { - // Same item check: must be exact match. - if (this.array_[i] == value) { - return i; - } - } - return -1; - }, - - /** - * Compares 2 strings and returns a number indicating one string comes before - * or after or is the same as the other string in sort order. - * - * @param {string} a String1. - * @param {string} b String2. - * @return {boolean} Return -1, if String1 < String2. Return 0, if String1 == - * String2. Otherwise, return 1. - */ - compare: function(a, b) { - return a.localeCompare(b, - undefined, // locale parameter, use default locale. - {usage: 'sort', numeric: true}); - }, - - /** - * Adds the given item to the array. If there were already same item in the - * list, return the index of the existing item without adding a duplicate - * item. - * - * @param {string} value Value to be added into the array. - * @return {number} Index in the list which the element added to. - */ - add: function(value) { - var oldArray = this.array_.slice(0); // Shallow copy. - var addedIndex = -1; - for (var i = 0; i < this.length; i++) { - // Same item check: must be exact match. - if (this.array_[i] == value) - return i; - - // Since the array is sorted, new item will be added just before the first - // larger item. - if (this.compare(this.array_[i], value) >= 0) { - this.array_.splice(i, 0, value); - addedIndex = i; - break; - } - } - // If value is not added yet, add it at the last. - if (addedIndex == -1) { - this.array_.push(value); - addedIndex = this.length; - } - - this.firePermutedEvent_( - this.calculatePermutation_(oldArray, this.array_)); - this.save_(); - metrics.recordUserAction('FolderShortcut.Add'); - return addedIndex; - }, - - /** - * Removes the given item from the array. - * @param {string} value Value to be removed from the array. - * @return {number} Index in the list which the element removed from. - */ - remove: function(value) { - var removedIndex = -1; - var oldArray = this.array_.slice(0); // Shallow copy. - for (var i = 0; i < this.length; i++) { - // Same item check: must be exact match. - if (this.array_[i] == value) { - this.array_.splice(i, 1); - removedIndex = i; - break; - } - } - - if (removedIndex != -1) { - this.firePermutedEvent_( - this.calculatePermutation_(oldArray, this.array_)); - this.save_(); - metrics.recordUserAction('FolderShortcut.Remove'); - return removedIndex; - } - - // No item is removed. - return -1; - }, - - /** - * @param {string} path Path to be checked. - * @return {boolean} True if the given |path| exists in the array. False - * otherwise. - */ - exists: function(path) { - var index = this.getIndex(path); - return (index >= 0); - }, - - /** - * Saves the current array to chrome.storage. - * @private - */ - save_: function() { - var obj = {}; - obj[FolderShortcutsDataModel.NAME] = this.array_; - chrome.storage.sync.set(obj, function() {}); - }, - - /** - * Creates a permutation array for 'permuted' event, which is compatible with - * a permutation array used in cr/ui/array_data_model.js. - * - * @param {array} oldArray Previous array before changing. - * @param {array} newArray New array after changing. - * @return {Array.<number>} Created permutation array. - * @private - */ - calculatePermutation_: function(oldArray, newArray) { - var oldIndex = 0; // Index of oldArray. - var newIndex = 0; // Index of newArray. - - // Note that both new and old arrays are sorted. - var permutation = []; - for (; oldIndex < oldArray.length; oldIndex++) { - if (newIndex >= newArray.length) { - // oldArray[oldIndex] is deleted, which is not in the new array. - permutation[oldIndex] = -1; - continue; - } - - while (newIndex < newArray.length) { - // Unchanged item, which exists in both new and old array. But the - // index may be changed. - if (oldArray[oldIndex] == newArray[newIndex]) { - permutation[oldIndex] = newIndex; - newIndex++; - break; - } - - // oldArray[oldIndex] is deleted, which is not in the new array. - if (this.compare(oldArray[oldIndex], newArray[newIndex]) < 0) { - permutation[oldIndex] = -1; - break; - } - - // In the case of this.compare(oldArray[oldIndex]) > 0: - // newArray[newIndex] is added, which is not in the old array. - newIndex++; - } - } - return permutation; - }, - - /** - * Fires a 'permuted' event, which is compatible with cr.ui.ArrayDataModel. - * @param {Array.<number>} Permutation array. - */ - firePermutedEvent_: function(permutation) { - var permutedEvent = new Event('permuted'); - permutedEvent.newLength = this.length; - permutedEvent.permutation = permutation; - this.dispatchEvent(permutedEvent); - - // Note: This model only fires 'permuted' event, because: - // 1) 'change' event is not necessary to fire since it is covered by - // 'permuted' event. - // 2) 'splice' and 'sorted' events are not implemented. These events are - // not used in NavigationListModel. We have to implement them when - // necessary. - } -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/commands.js b/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/commands.js deleted file mode 100644 index f05f0f227d6..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/commands.js +++ /dev/null @@ -1,455 +0,0 @@ -// 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. - -'use strict'; - -/** - * Command queue is the only way to modify images. - * Supports undo/redo. - * Command execution is asynchronous (callback-based). - * - * @param {Document} document Document to create canvases in. - * @param {HTMLCanvasElement} canvas The canvas with the original image. - * @param {function(callback)} saveFunction Function to save the image. - * @constructor - */ -function CommandQueue(document, canvas, saveFunction) { - this.document_ = document; - this.undo_ = []; - this.redo_ = []; - this.subscribers_ = []; - this.currentImage_ = canvas; - - // Current image may be null or not-null but with width = height = 0. - // Copying an image with zero dimensions causes js errors. - if (this.currentImage_) { - this.baselineImage_ = document.createElement('canvas'); - this.baselineImage_.width = this.currentImage_.width; - this.baselineImage_.height = this.currentImage_.height; - if (this.currentImage_.width > 0 && this.currentImage_.height > 0) { - var context = this.baselineImage_.getContext('2d'); - context.drawImage(this.currentImage_, 0, 0); - } - } else { - this.baselineImage_ = null; - } - - this.previousImage_ = document.createElement('canvas'); - this.previousImageAvailable_ = false; - - this.saveFunction_ = saveFunction; - this.busy_ = false; - this.UIContext_ = {}; -} - -/** - * Attach the UI elements to the command queue. - * Once the UI is attached the results of image manipulations are displayed. - * - * @param {ImageView} imageView The ImageView object to display the results. - * @param {ImageEditor.Prompt} prompt Prompt to use with this CommandQueue. - * @param {function(boolean)} lock Function to enable/disable buttons etc. - */ -CommandQueue.prototype.attachUI = function(imageView, prompt, lock) { - this.UIContext_ = { - imageView: imageView, - prompt: prompt, - lock: lock - }; -}; - -/** - * Execute the action when the queue is not busy. - * @param {function} callback Callback. - */ -CommandQueue.prototype.executeWhenReady = function(callback) { - if (this.isBusy()) - this.subscribers_.push(callback); - else - setTimeout(callback, 0); -}; - -/** - * @return {boolean} True if the command queue is busy. - */ -CommandQueue.prototype.isBusy = function() { return this.busy_ }; - -/** - * Set the queue state to busy. Lock the UI. - * @private - */ -CommandQueue.prototype.setBusy_ = function() { - if (this.busy_) - throw new Error('CommandQueue already busy'); - - this.busy_ = true; - - if (this.UIContext_.lock) - this.UIContext_.lock(true); - - ImageUtil.trace.resetTimer('command-busy'); -}; - -/** - * Set the queue state to not busy. Unlock the UI and execute pending actions. - * @private - */ -CommandQueue.prototype.clearBusy_ = function() { - if (!this.busy_) - throw new Error('Inconsistent CommandQueue already not busy'); - - this.busy_ = false; - - // Execute the actions requested while the queue was busy. - while (this.subscribers_.length) - this.subscribers_.shift()(); - - if (this.UIContext_.lock) - this.UIContext_.lock(false); - - ImageUtil.trace.reportTimer('command-busy'); -}; - -/** - * Commit the image change: save and unlock the UI. - * @param {number=} opt_delay Delay in ms (to avoid disrupting the animation). - * @private - */ -CommandQueue.prototype.commit_ = function(opt_delay) { - setTimeout(this.saveFunction_.bind(null, this.clearBusy_.bind(this)), - opt_delay || 0); -}; - -/** - * Internal function to execute the command in a given context. - * - * @param {Command} command The command to execute. - * @param {Object} uiContext The UI context. - * @param {function} callback Completion callback. - * @private - */ -CommandQueue.prototype.doExecute_ = function(command, uiContext, callback) { - if (!this.currentImage_) - throw new Error('Cannot operate on null image'); - - // Remember one previous image so that the first undo is as fast as possible. - this.previousImage_.width = this.currentImage_.width; - this.previousImage_.height = this.currentImage_.height; - this.previousImageAvailable_ = true; - var context = this.previousImage_.getContext('2d'); - context.drawImage(this.currentImage_, 0, 0); - - command.execute( - this.document_, - this.currentImage_, - function(result, opt_delay) { - this.currentImage_ = result; - callback(opt_delay); - }.bind(this), - uiContext); -}; - -/** - * Executes the command. - * - * @param {Command} command Command to execute. - * @param {boolean=} opt_keep_redo True if redo stack should not be cleared. - */ -CommandQueue.prototype.execute = function(command, opt_keep_redo) { - this.setBusy_(); - - if (!opt_keep_redo) - this.redo_ = []; - - this.undo_.push(command); - - this.doExecute_(command, this.UIContext_, this.commit_.bind(this)); -}; - -/** - * @return {boolean} True if Undo is applicable. - */ -CommandQueue.prototype.canUndo = function() { - return this.undo_.length != 0; -}; - -/** - * Undo the most recent command. - */ -CommandQueue.prototype.undo = function() { - if (!this.canUndo()) - throw new Error('Cannot undo'); - - this.setBusy_(); - - var command = this.undo_.pop(); - this.redo_.push(command); - - var self = this; - - function complete() { - var delay = command.revertView( - self.currentImage_, self.UIContext_.imageView); - self.commit_(delay); - } - - if (this.previousImageAvailable_) { - // First undo after an execute call. - this.currentImage_.width = this.previousImage_.width; - this.currentImage_.height = this.previousImage_.height; - var context = this.currentImage_.getContext('2d'); - context.drawImage(this.previousImage_, 0, 0); - - // Free memory. - this.previousImage_.width = 0; - this.previousImage_.height = 0; - this.previousImageAvailable_ = false; - - complete(); - // TODO(kaznacheev) Consider recalculating previousImage_ right here - // by replaying the commands in the background. - } else { - this.currentImage_.width = this.baselineImage_.width; - this.currentImage_.height = this.baselineImage_.height; - var context = this.currentImage_.getContext('2d'); - context.drawImage(this.baselineImage_, 0, 0); - - var replay = function(index) { - if (index < self.undo_.length) - self.doExecute_(self.undo_[index], {}, replay.bind(null, index + 1)); - else { - complete(); - } - }; - - replay(0); - } -}; - -/** - * @return {boolean} True if Redo is applicable. - */ -CommandQueue.prototype.canRedo = function() { - return this.redo_.length != 0; -}; - -/** - * Repeat the command that was recently un-done. - */ -CommandQueue.prototype.redo = function() { - if (!this.canRedo()) - throw new Error('Cannot redo'); - - this.execute(this.redo_.pop(), true); -}; - -/** - * Closes internal buffers. Call to ensure, that internal buffers are freed - * as soon as possible. - */ -CommandQueue.prototype.close = function() { - // Free memory used by the undo buffer. - this.previousImage_.width = 0; - this.previousImage_.height = 0; - this.previousImageAvailable_ = false; - - if (this.baselineImage_) { - this.baselineImage_.width = 0; - this.baselineImage_.height = 0; - } -}; - -/** - * Command object encapsulates an operation on an image and a way to visualize - * its result. - * - * @param {string} name Command name. - * @constructor - */ -function Command(name) { - this.name_ = name; -} - -/** - * @return {string} String representation of the command. - */ -Command.prototype.toString = function() { - return 'Command ' + this.name_; -}; - -/** - * Execute the command and visualize its results. - * - * The two actions are combined into one method because sometimes it is nice - * to be able to show partial results for slower operations. - * - * @param {Document} document Document on which to execute command. - * @param {HTMLCanvasElement} srcCanvas Canvas to execute on. - * @param {function(HTMLCanvasElement, number)} callback Callback to call on - * completion. - * @param {Object} uiContext Context to work in. - */ -Command.prototype.execute = function(document, srcCanvas, callback, uiContext) { - console.error('Command.prototype.execute not implemented'); -}; - -/** - * Visualize reversion of the operation. - * - * @param {HTMLCanvasElement} canvas Image data to use. - * @param {ImageView} imageView ImageView to revert. - * @return {number} Animation duration in ms. - */ -Command.prototype.revertView = function(canvas, imageView) { - imageView.replace(canvas); - return 0; -}; - -/** - * Creates canvas to render on. - * - * @param {Document} document Document to create canvas in. - * @param {HTMLCanvasElement} srcCanvas to copy optional dimensions from. - * @param {number=} opt_width new canvas width. - * @param {number=} opt_height new canvas height. - * @return {HTMLCanvasElement} Newly created canvas. - * @private - */ -Command.prototype.createCanvas_ = function( - document, srcCanvas, opt_width, opt_height) { - var result = document.createElement('canvas'); - result.width = opt_width || srcCanvas.width; - result.height = opt_height || srcCanvas.height; - return result; -}; - - -/** - * Rotate command - * @param {number} rotate90 Rotation angle in 90 degree increments (signed). - * @constructor - * @extends {Command} - */ -Command.Rotate = function(rotate90) { - Command.call(this, 'rotate(' + rotate90 * 90 + 'deg)'); - this.rotate90_ = rotate90; -}; - -Command.Rotate.prototype = { __proto__: Command.prototype }; - -/** @override */ -Command.Rotate.prototype.execute = function( - document, srcCanvas, callback, uiContext) { - var result = this.createCanvas_( - document, - srcCanvas, - (this.rotate90_ & 1) ? srcCanvas.height : srcCanvas.width, - (this.rotate90_ & 1) ? srcCanvas.width : srcCanvas.height); - ImageUtil.drawImageTransformed( - result, srcCanvas, 1, 1, this.rotate90_ * Math.PI / 2); - var delay; - if (uiContext.imageView) { - delay = uiContext.imageView.replaceAndAnimate(result, null, this.rotate90_); - } - setTimeout(callback, 0, result, delay); -}; - -/** @override */ -Command.Rotate.prototype.revertView = function(canvas, imageView) { - return imageView.replaceAndAnimate(canvas, null, -this.rotate90_); -}; - - -/** - * Crop command. - * - * @param {Rect} imageRect Crop rectangle in image coordinates. - * @constructor - * @extends {Command} - */ -Command.Crop = function(imageRect) { - Command.call(this, 'crop' + imageRect.toString()); - this.imageRect_ = imageRect; -}; - -Command.Crop.prototype = { __proto__: Command.prototype }; - -/** @override */ -Command.Crop.prototype.execute = function( - document, srcCanvas, callback, uiContext) { - var result = this.createCanvas_( - document, srcCanvas, this.imageRect_.width, this.imageRect_.height); - Rect.drawImage(result.getContext('2d'), srcCanvas, null, this.imageRect_); - var delay; - if (uiContext.imageView) { - delay = uiContext.imageView.replaceAndAnimate(result, this.imageRect_, 0); - } - setTimeout(callback, 0, result, delay); -}; - -/** @override */ -Command.Crop.prototype.revertView = function(canvas, imageView) { - return imageView.animateAndReplace(canvas, this.imageRect_); -}; - - -/** - * Filter command. - * - * @param {string} name Command name. - * @param {function(ImageData,ImageData,number,number)} filter Filter function. - * @param {string} message Message to display when done. - * @constructor - * @extends {Command} - */ -Command.Filter = function(name, filter, message) { - Command.call(this, name); - this.filter_ = filter; - this.message_ = message; -}; - -Command.Filter.prototype = { __proto__: Command.prototype }; - -/** @override */ -Command.Filter.prototype.execute = function( - document, srcCanvas, callback, uiContext) { - var result = this.createCanvas_(document, srcCanvas); - - var self = this; - - var previousRow = 0; - - function onProgressVisible(updatedRow, rowCount) { - if (updatedRow == rowCount) { - uiContext.imageView.replace(result); - if (self.message_) - uiContext.prompt.show(self.message_, 2000); - callback(result); - } else { - var viewport = uiContext.imageView.viewport_; - - var imageStrip = new Rect(viewport.getImageBounds()); - imageStrip.top = previousRow; - imageStrip.height = updatedRow - previousRow; - - var screenStrip = new Rect(viewport.getImageBoundsOnScreen()); - screenStrip.top = Math.round(viewport.imageToScreenY(previousRow)); - screenStrip.height = - Math.round(viewport.imageToScreenY(updatedRow)) - screenStrip.top; - - uiContext.imageView.paintDeviceRect( - viewport.screenToDeviceRect(screenStrip), result, imageStrip); - previousRow = updatedRow; - } - } - - function onProgressInvisible(updatedRow, rowCount) { - if (updatedRow == rowCount) { - callback(result); - } - } - - filter.applyByStrips(result, srcCanvas, this.filter_, - uiContext.imageView ? onProgressVisible : onProgressInvisible); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/exif_encoder.js b/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/exif_encoder.js deleted file mode 100644 index e81b8fba899..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/exif_encoder.js +++ /dev/null @@ -1,569 +0,0 @@ -// 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. - -'use strict'; - -// TODO:(kaznacheev) Share the EXIF constants with exif_parser.js -var EXIF_MARK_SOS = 0xffda; // Start of "stream" (the actual image data). -var EXIF_MARK_SOI = 0xffd8; // Start of image data. -var EXIF_MARK_EOI = 0xffd9; // End of image data. - -var EXIF_MARK_APP0 = 0xffe0; // APP0 block, most commonly JFIF data. -var EXIF_MARK_EXIF = 0xffe1; // Start of exif block. - -var EXIF_ALIGN_LITTLE = 0x4949; // Indicates little endian exif data. -var EXIF_ALIGN_BIG = 0x4d4d; // Indicates big endian exif data. - -var EXIF_TAG_TIFF = 0x002a; // First directory containing TIFF data. -var EXIF_TAG_GPSDATA = 0x8825; // Pointer from TIFF to the GPS directory. -var EXIF_TAG_EXIFDATA = 0x8769; // Pointer from TIFF to the EXIF IFD. - -var EXIF_TAG_JPG_THUMB_OFFSET = 0x0201; // Pointer from TIFF to thumbnail. -var EXIF_TAG_JPG_THUMB_LENGTH = 0x0202; // Length of thumbnail data. - -var EXIF_TAG_IMAGE_WIDTH = 0x0100; -var EXIF_TAG_IMAGE_HEIGHT = 0x0101; - -var EXIF_TAG_ORIENTATION = 0x0112; -var EXIF_TAG_X_DIMENSION = 0xA002; -var EXIF_TAG_Y_DIMENSION = 0xA003; - -/** - * The Exif metadata encoder. - * Uses the metadata format as defined by ExifParser. - * @param {Object} original_metadata Metadata to encode. - * @constructor - * @extends {ImageEncoder.MetadataEncoder} - */ -function ExifEncoder(original_metadata) { - ImageEncoder.MetadataEncoder.apply(this, arguments); - - this.ifd_ = this.metadata_.ifd; - if (!this.ifd_) - this.ifd_ = this.metadata_.ifd = {}; -} - -ExifEncoder.prototype = {__proto__: ImageEncoder.MetadataEncoder.prototype}; - -ImageEncoder.registerMetadataEncoder(ExifEncoder, 'image/jpeg'); - -/** - * @param {HTMLCanvasElement|Object} canvas Canvas or anything with - * width and height properties. - */ -ExifEncoder.prototype.setImageData = function(canvas) { - var image = this.ifd_.image; - if (!image) - image = this.ifd_.image = {}; - - // Only update width/height in this directory if they are present. - if (image[EXIF_TAG_IMAGE_WIDTH] && image[EXIF_TAG_IMAGE_HEIGHT]) { - image[EXIF_TAG_IMAGE_WIDTH].value = canvas.width; - image[EXIF_TAG_IMAGE_HEIGHT].value = canvas.height; - } - - var exif = this.ifd_.exif; - if (!exif) - exif = this.ifd_.exif = {}; - ExifEncoder.findOrCreateTag(image, EXIF_TAG_EXIFDATA); - ExifEncoder.findOrCreateTag(exif, EXIF_TAG_X_DIMENSION).value = canvas.width; - ExifEncoder.findOrCreateTag(exif, EXIF_TAG_Y_DIMENSION).value = canvas.height; - - this.metadata_.width = canvas.width; - this.metadata_.height = canvas.height; - - // Always save in default orientation. - delete this.metadata_.imageTransform; - ExifEncoder.findOrCreateTag(image, EXIF_TAG_ORIENTATION).value = 1; -}; - - -/** - * @param {HTMLCanvasElement} canvas Thumbnail canvas. - * @param {number} quality (0..1] Thumbnail encoding quality. - */ -ExifEncoder.prototype.setThumbnailData = function(canvas, quality) { - // Empirical formula with reasonable behavior: - // 10K for 1Mpix, 30K for 5Mpix, 50K for 9Mpix and up. - var pixelCount = this.metadata_.width * this.metadata_.height; - var maxEncodedSize = 5000 * Math.min(10, 1 + pixelCount / 1000000); - - var DATA_URL_PREFIX = 'data:' + this.mimeType + ';base64,'; - var BASE64_BLOAT = 4 / 3; - var maxDataURLLength = - DATA_URL_PREFIX.length + Math.ceil(maxEncodedSize * BASE64_BLOAT); - - for (;; quality *= 0.8) { - ImageEncoder.MetadataEncoder.prototype.setThumbnailData.call( - this, canvas, quality); - if (this.metadata_.thumbnailURL.length <= maxDataURLLength || quality < 0.2) - break; - } - - if (this.metadata_.thumbnailURL.length <= maxDataURLLength) { - var thumbnail = this.ifd_.thumbnail; - if (!thumbnail) - thumbnail = this.ifd_.thumbnail = {}; - - ExifEncoder.findOrCreateTag(thumbnail, EXIF_TAG_IMAGE_WIDTH).value = - canvas.width; - - ExifEncoder.findOrCreateTag(thumbnail, EXIF_TAG_IMAGE_HEIGHT).value = - canvas.height; - - // The values for these tags will be set in ExifWriter.encode. - ExifEncoder.findOrCreateTag(thumbnail, EXIF_TAG_JPG_THUMB_OFFSET); - ExifEncoder.findOrCreateTag(thumbnail, EXIF_TAG_JPG_THUMB_LENGTH); - - // Always save in default orientation. - ExifEncoder.findOrCreateTag(thumbnail, EXIF_TAG_ORIENTATION).value = 1; - } else { - console.warn( - 'Thumbnail URL too long: ' + this.metadata_.thumbnailURL.length); - // Delete thumbnail ifd so that it is not written out to a file, but - // keep thumbnailURL for display purposes. - if (this.ifd_.thumbnail) { - delete this.ifd_.thumbnail; - } - } - delete this.metadata_.thumbnailTransform; -}; - -/** - * Return a range where the metadata is (or should be) located. - * @param {string} encodedImage Raw image data to look for metadata. - * @return {Object} An object with from and to properties. - */ -ExifEncoder.prototype.findInsertionRange = function(encodedImage) { - function getWord(pos) { - if (pos + 2 > encodedImage.length) - throw 'Reading past the buffer end @' + pos; - return encodedImage.charCodeAt(pos) << 8 | encodedImage.charCodeAt(pos + 1); - } - - if (getWord(0) != EXIF_MARK_SOI) - throw new Error('Jpeg data starts from 0x' + getWord(0).toString(16)); - - var sectionStart = 2; - - // Default: an empty range right after SOI. - // Will be returned in absence of APP0 or Exif sections. - var range = {from: sectionStart, to: sectionStart}; - - for (;;) { - var tag = getWord(sectionStart); - - if (tag == EXIF_MARK_SOS) - break; - - var nextSectionStart = sectionStart + 2 + getWord(sectionStart + 2); - if (nextSectionStart <= sectionStart || - nextSectionStart > encodedImage.length) - throw new Error('Invalid section size in jpeg data'); - - if (tag == EXIF_MARK_APP0) { - // Assert that we have not seen the Exif section yet. - if (range.from != range.to) - throw new Error('APP0 section found after EXIF section'); - // An empty range right after the APP0 segment. - range.from = range.to = nextSectionStart; - } else if (tag == EXIF_MARK_EXIF) { - // A range containing the existing EXIF section. - range.from = sectionStart; - range.to = nextSectionStart; - } - sectionStart = nextSectionStart; - } - - return range; -}; - -/** - * @return {ArrayBuffer} serialized metadata ready to write to an image file. - */ -ExifEncoder.prototype.encode = function() { - var HEADER_SIZE = 10; - - // Allocate the largest theoretically possible size. - var bytes = new Uint8Array(0x10000); - - // Serialize header - var hw = new ByteWriter(bytes.buffer, 0, HEADER_SIZE); - hw.writeScalar(EXIF_MARK_EXIF, 2); - hw.forward('size', 2); - hw.writeString('Exif\0\0'); // Magic string. - - // First serialize the content of the exif section. - // Use a ByteWriter starting at HEADER_SIZE offset so that tell() positions - // can be directly mapped to offsets as encoded in the dictionaries. - var bw = new ByteWriter(bytes.buffer, HEADER_SIZE); - - if (this.metadata_.littleEndian) { - bw.setByteOrder(ByteWriter.LITTLE_ENDIAN); - bw.writeScalar(EXIF_ALIGN_LITTLE, 2); - } else { - bw.setByteOrder(ByteWriter.BIG_ENDIAN); - bw.writeScalar(EXIF_ALIGN_BIG, 2); - } - - bw.writeScalar(EXIF_TAG_TIFF, 2); - - bw.forward('image-dir', 4); // The pointer should point right after itself. - bw.resolveOffset('image-dir'); - - ExifEncoder.encodeDirectory(bw, this.ifd_.image, - [EXIF_TAG_EXIFDATA, EXIF_TAG_GPSDATA], 'thumb-dir'); - - if (this.ifd_.exif) { - bw.resolveOffset(EXIF_TAG_EXIFDATA); - ExifEncoder.encodeDirectory(bw, this.ifd_.exif); - } else { - if (EXIF_TAG_EXIFDATA in this.ifd_.image) - throw new Error('Corrupt exif dictionary reference'); - } - - if (this.ifd_.gps) { - bw.resolveOffset(EXIF_TAG_GPSDATA); - ExifEncoder.encodeDirectory(bw, this.ifd_.gps); - } else { - if (EXIF_TAG_GPSDATA in this.ifd_.image) - throw new Error('Missing gps dictionary reference'); - } - - if (this.ifd_.thumbnail) { - bw.resolveOffset('thumb-dir'); - ExifEncoder.encodeDirectory( - bw, - this.ifd_.thumbnail, - [EXIF_TAG_JPG_THUMB_OFFSET, EXIF_TAG_JPG_THUMB_LENGTH]); - - var thumbnailDecoded = - ImageEncoder.decodeDataURL(this.metadata_.thumbnailURL); - bw.resolveOffset(EXIF_TAG_JPG_THUMB_OFFSET); - bw.resolve(EXIF_TAG_JPG_THUMB_LENGTH, thumbnailDecoded.length); - bw.writeString(thumbnailDecoded); - } else { - bw.resolve('thumb-dir', 0); - } - - bw.checkResolved(); - - var totalSize = HEADER_SIZE + bw.tell(); - hw.resolve('size', totalSize - 2); // The marker is excluded. - hw.checkResolved(); - - var subarray = new Uint8Array(totalSize); - for (var i = 0; i != totalSize; i++) { - subarray[i] = bytes[i]; - } - return subarray.buffer; -}; - -/* - * Static methods. - */ - -/** - * Write the contents of an IFD directory. - * @param {ByteWriter} bw ByteWriter to use. - * @param {Object} directory A directory map as created by ExifParser. - * @param {Array} resolveLater An array of tag ids for which the values will be - * resolved later. - * @param {string} nextDirPointer A forward key for the pointer to the next - * directory. If omitted the pointer is set to 0. - */ -ExifEncoder.encodeDirectory = function( - bw, directory, resolveLater, nextDirPointer) { - - var longValues = []; - - bw.forward('dir-count', 2); - var count = 0; - - for (var key in directory) { - var tag = directory[key]; - bw.writeScalar(tag.id, 2); - bw.writeScalar(tag.format, 2); - bw.writeScalar(tag.componentCount, 4); - - var width = ExifEncoder.getComponentWidth(tag) * tag.componentCount; - - if (resolveLater && (resolveLater.indexOf(tag.id) >= 0)) { - // The actual value depends on further computations. - if (tag.componentCount != 1 || width > 4) - throw new Error('Cannot forward the pointer for ' + tag.id); - bw.forward(tag.id, width); - } else if (width <= 4) { - // The value fits into 4 bytes, write it immediately. - ExifEncoder.writeValue(bw, tag); - } else { - // The value does not fit, forward the 4 byte offset to the actual value. - width = 4; - bw.forward(tag.id, width); - longValues.push(tag); - } - bw.skip(4 - width); // Align so that the value take up exactly 4 bytes. - count++; - } - - bw.resolve('dir-count', count); - - if (nextDirPointer) { - bw.forward(nextDirPointer, 4); - } else { - bw.writeScalar(0, 4); - } - - // Write out the long values and resolve pointers. - for (var i = 0; i != longValues.length; i++) { - var longValue = longValues[i]; - bw.resolveOffset(longValue.id); - ExifEncoder.writeValue(bw, longValue); - } -}; - -/** - * @param {{format:number, id:number}} tag EXIF tag object. - * @return {number} Width in bytes of the data unit associated with this tag. - * TODO(kaznacheev): Share with ExifParser? - */ -ExifEncoder.getComponentWidth = function(tag) { - switch (tag.format) { - case 1: // Byte - case 2: // String - case 7: // Undefined - return 1; - - case 3: // Short - return 2; - - case 4: // Long - case 9: // Signed Long - return 4; - - case 5: // Rational - case 10: // Signed Rational - return 8; - - default: // ??? - console.warn('Unknown tag format 0x' + - Number(tag.id).toString(16) + ': ' + tag.format); - return 4; - } -}; - -/** - * Writes out the tag value. - * @param {ByteWriter} bw Writer to use. - * @param {Object} tag Tag, which value to write. - */ -ExifEncoder.writeValue = function(bw, tag) { - if (tag.format == 2) { // String - if (tag.componentCount != tag.value.length) { - throw new Error( - 'String size mismatch for 0x' + Number(tag.id).toString(16)); - } - bw.writeString(tag.value); - } else { // Scalar or rational - var width = ExifEncoder.getComponentWidth(tag); - - var writeComponent = function(value, signed) { - if (width == 8) { - bw.writeScalar(value[0], 4, signed); - bw.writeScalar(value[1], 4, signed); - } else { - bw.writeScalar(value, width, signed); - } - }; - - var signed = (tag.format == 9 || tag.format == 10); - if (tag.componentCount == 1) { - writeComponent(tag.value, signed); - } else { - for (var i = 0; i != tag.componentCount; i++) { - writeComponent(tag.value[i], signed); - } - } - } -}; - -/** - * @param {{Object.<number,Object>}} directory EXIF directory. - * @param {number} id Tag id. - * @param {number} format Tag format - * (used in {@link ExifEncoder#getComponentWidth}). - * @param {number} componentCount Number of components in this tag. - * @return {{id:number, format:number, componentCount:number}} - * Tag found or created. - */ -ExifEncoder.findOrCreateTag = function(directory, id, format, componentCount) { - if (!(id in directory)) { - directory[id] = { - id: id, - format: format || 3, // Short - componentCount: componentCount || 1 - }; - } - return directory[id]; -}; - -/** - * ByteWriter class. - * @param {ArrayBuffer} arrayBuffer Underlying buffer to use. - * @param {number} offset Offset at which to start writing. - * @param {number} length Maximum length to use. - * @class - * @constructor - */ -function ByteWriter(arrayBuffer, offset, length) { - length = length || (arrayBuffer.byteLength - offset); - this.view_ = new DataView(arrayBuffer, offset, length); - this.littleEndian_ = false; - this.pos_ = 0; - this.forwards_ = {}; -} - -/** - * Little endian byte order. - * @type {number} - */ -ByteWriter.LITTLE_ENDIAN = 0; - -/** - * Bug endian byte order. - * @type {number} - */ -ByteWriter.BIG_ENDIAN = 1; - -/** - * Set the byte ordering for future writes. - * @param {number} order ByteOrder to use {ByteWriter.LITTLE_ENDIAN} - * or {ByteWriter.BIG_ENDIAN}. - */ -ByteWriter.prototype.setByteOrder = function(order) { - this.littleEndian_ = (order == ByteWriter.LITTLE_ENDIAN); -}; - -/** - * @return {number} the current write position. - */ -ByteWriter.prototype.tell = function() { return this.pos_ }; - -/** - * Skips desired amount of bytes in output stream. - * @param {number} count Byte count to skip. - */ -ByteWriter.prototype.skip = function(count) { - this.validateWrite(count); - this.pos_ += count; -}; - -/** - * Check if the buffer has enough room to read 'width' bytes. Throws an error - * if it has not. - * @param {number} width Amount of bytes to check. - */ -ByteWriter.prototype.validateWrite = function(width) { - if (this.pos_ + width > this.view_.byteLength) - throw new Error('Writing past the end of the buffer'); -}; - -/** - * Writes scalar value to output stream. - * @param {number} value Value to write. - * @param {number} width Desired width of written value. - * @param {boolean=} opt_signed True if value represents signed number. - */ -ByteWriter.prototype.writeScalar = function(value, width, opt_signed) { - var method; -// The below switch is so verbose for two reasons: -// 1. V8 is faster on method names which are 'symbols'. -// 2. Method names are discoverable by full text search. - switch (width) { - case 1: - method = opt_signed ? 'setInt8' : 'setUint8'; - break; - - case 2: - method = opt_signed ? 'setInt16' : 'setUint16'; - break; - - case 4: - method = opt_signed ? 'setInt32' : 'setUint32'; - break; - - case 8: - method = opt_signed ? 'setInt64' : 'setUint64'; - break; - - default: - throw new Error('Invalid width: ' + width); - break; - } - - this.validateWrite(width); - this.view_[method](this.pos_, value, this.littleEndian_); - this.pos_ += width; -}; - -/** - * Writes string. - * @param {string} str String to write. - */ -ByteWriter.prototype.writeString = function(str) { - this.validateWrite(str.length); - for (var i = 0; i != str.length; i++) { - this.view_.setUint8(this.pos_++, str.charCodeAt(i)); - } -}; - -/** - * Allocate the space for 'width' bytes for the value that will be set later. - * To be followed by a 'resolve' call with the same key. - * @param {string} key A key to identify the value. - * @param {number} width Width of the value in bytes. - */ -ByteWriter.prototype.forward = function(key, width) { - if (key in this.forwards_) - throw new Error('Duplicate forward key ' + key); - this.validateWrite(width); - this.forwards_[key] = { - pos: this.pos_, - width: width - }; - this.pos_ += width; -}; - -/** - * Set the value previously allocated with a 'forward' call. - * @param {string} key A key to identify the value. - * @param {number} value value to write in pre-allocated space. - */ -ByteWriter.prototype.resolve = function(key, value) { - if (!(key in this.forwards_)) - throw new Error('Undeclared forward key ' + key.toString(16)); - var forward = this.forwards_[key]; - var curPos = this.pos_; - this.pos_ = forward.pos; - this.writeScalar(value, forward.width); - this.pos_ = curPos; - delete this.forwards_[key]; -}; - -/** - * A shortcut to resolve the value to the current write position. - * @param {string} key A key to identify pre-allocated position. - */ -ByteWriter.prototype.resolveOffset = function(key) { - this.resolve(key, this.tell()); -}; - -/** - * Check if every forward has been resolved, throw and error if not. - */ -ByteWriter.prototype.checkResolved = function() { - for (var key in this.forwards_) { - throw new Error('Unresolved forward pointer ' + key.toString(16)); - } -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/filter.js b/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/filter.js deleted file mode 100644 index e06d4ef2dd8..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/filter.js +++ /dev/null @@ -1,612 +0,0 @@ -// 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. - -'use strict'; - -/** - * A namespace for image filter utilities. - */ -var filter = {}; - -/** - * Create a filter from name and options. - * - * @param {string} name Maps to a filter method name. - * @param {Object} options A map of filter-specific options. - * @return {function(ImageData,ImageData,number,number)} created function. - */ -filter.create = function(name, options) { - var filterFunc = filter[name](options); - return function() { - var time = Date.now(); - filterFunc.apply(null, arguments); - var dst = arguments[0]; - var mPixPerSec = dst.width * dst.height / 1000 / (Date.now() - time); - ImageUtil.trace.report(name, Math.round(mPixPerSec * 10) / 10 + 'Mps'); - } -}; - -/** - * Apply a filter to a image by splitting it into strips. - * - * To be used with large images to avoid freezing up the UI. - * - * @param {HTMLCanvasElement} dstCanvas Destination canvas. - * @param {HTMLCanvasElement} srcCanvas Source canvas. - * @param {function(ImageData,ImageData,number,number)} filterFunc Filter. - * @param {function(number, number)} progressCallback Progress callback. - * @param {number} maxPixelsPerStrip Pixel number to process at once. - */ -filter.applyByStrips = function( - dstCanvas, srcCanvas, filterFunc, progressCallback, maxPixelsPerStrip) { - var dstContext = dstCanvas.getContext('2d'); - var srcContext = srcCanvas.getContext('2d'); - var source = srcContext.getImageData(0, 0, srcCanvas.width, srcCanvas.height); - - var stripCount = Math.ceil(srcCanvas.width * srcCanvas.height / - (maxPixelsPerStrip || 1000000)); // 1 Mpix is a reasonable default. - - var strip = srcContext.getImageData(0, 0, - srcCanvas.width, Math.ceil(srcCanvas.height / stripCount)); - - var offset = 0; - - function filterStrip() { - // If the strip overlaps the bottom of the source image we cannot shrink it - // and we cannot fill it partially (since canvas.putImageData always draws - // the entire buffer). - // Instead we move the strip up several lines (converting those lines - // twice is a small price to pay). - if (offset > source.height - strip.height) { - offset = source.height - strip.height; - } - - filterFunc(strip, source, 0, offset); - dstContext.putImageData(strip, 0, offset); - - offset += strip.height; - - if (offset < source.height) { - setTimeout(filterStrip, 0); - } else { - ImageUtil.trace.reportTimer('filter-commit'); - } - - progressCallback(offset, source.height); - } - - ImageUtil.trace.resetTimer('filter-commit'); - filterStrip(); -}; - -/** - * Return a color histogram for an image. - * - * @param {HTMLCanvasElement|ImageData} source Image data to analyze. - * @return {{r: Array.<number>, g: Array.<number>, b: Array.<number>}} - * histogram. - */ -filter.getHistogram = function(source) { - var imageData; - if (source.constructor.name == 'HTMLCanvasElement') { - imageData = source.getContext('2d'). - getImageData(0, 0, source.width, source.height); - } else { - imageData = source; - } - - var r = []; - var g = []; - var b = []; - - for (var i = 0; i != 256; i++) { - r.push(0); - g.push(0); - b.push(0); - } - - var data = imageData.data; - var maxIndex = 4 * imageData.width * imageData.height; - for (var index = 0; index != maxIndex;) { - r[data[index++]]++; - g[data[index++]]++; - b[data[index++]]++; - index++; - } - - return { r: r, g: g, b: b }; -}; - -/** - * Compute the function for every integer value from 0 up to maxArg. - * - * Rounds and clips the results to fit the [0..255] range. - * Useful to speed up pixel manipulations. - * - * @param {number} maxArg Maximum argument value (inclusive). - * @param {function(number): number} func Function to precompute. - * @return {Uint8Array} Computed results. - */ -filter.precompute = function(maxArg, func) { - var results = new Uint8Array(maxArg + 1); - for (var arg = 0; arg <= maxArg; arg++) { - results[arg] = Math.max(0, Math.min(0xFF, Math.round(func(arg)))); - } - return results; -}; - -/** - * Convert pixels by applying conversion tables to each channel individually. - * - * @param {Array.<number>} rMap Red channel conversion table. - * @param {Array.<number>} gMap Green channel conversion table. - * @param {Array.<number>} bMap Blue channel conversion table. - * @param {ImageData} dst Destination image data. Can be smaller than the - * source, must completely fit inside the source. - * @param {ImageData} src Source image data. - * @param {number} offsetX Horizontal offset of dst relative to src. - * @param {number} offsetY Vertical offset of dst relative to src. - */ -filter.mapPixels = function(rMap, gMap, bMap, dst, src, offsetX, offsetY) { - var dstData = dst.data; - var dstWidth = dst.width; - var dstHeight = dst.height; - - var srcData = src.data; - var srcWidth = src.width; - var srcHeight = src.height; - - if (offsetX < 0 || offsetX + dstWidth > srcWidth || - offsetY < 0 || offsetY + dstHeight > srcHeight) - throw new Error('Invalid offset'); - - var dstIndex = 0; - for (var y = 0; y != dstHeight; y++) { - var srcIndex = (offsetX + (offsetY + y) * srcWidth) * 4; - for (var x = 0; x != dstWidth; x++) { - dstData[dstIndex++] = rMap[srcData[srcIndex++]]; - dstData[dstIndex++] = gMap[srcData[srcIndex++]]; - dstData[dstIndex++] = bMap[srcData[srcIndex++]]; - dstIndex++; - srcIndex++; - } - } -}; - -/** - * Number of digits after period(in binary form) to preserve. - * @type {number} - */ -filter.FIXED_POINT_SHIFT = 16; - -/** - * Maximum value that can be represented in fixed point without overflow. - * @type {number} - */ -filter.MAX_FLOAT_VALUE = 0x7FFFFFFF >> filter.FIXED_POINT_SHIFT; - -/** - * Converts floating point to fixed. - * @param {number} x Number to convert. - * @return {number} Converted number. - */ -filter.floatToFixedPoint = function(x) { - // Math.round on negative arguments causes V8 to deoptimize the calling - // function, so we are using >> 0 instead. - return (x * (1 << filter.FIXED_POINT_SHIFT)) >> 0; -}; - -/** - * Perform an image convolution with a symmetrical 5x5 matrix: - * - * 0 0 w3 0 0 - * 0 w2 w1 w2 0 - * w3 w1 w0 w1 w3 - * 0 w2 w1 w2 0 - * 0 0 w3 0 0 - * - * @param {Array.<number>} weights See the picture above. - * @param {ImageData} dst Destination image data. Can be smaller than the - * source, must completely fit inside the source. - * @param {ImageData} src Source image data. - * @param {number} offsetX Horizontal offset of dst relative to src. - * @param {number} offsetY Vertical offset of dst relative to src. - */ -filter.convolve5x5 = function(weights, dst, src, offsetX, offsetY) { - var w0 = filter.floatToFixedPoint(weights[0]); - var w1 = filter.floatToFixedPoint(weights[1]); - var w2 = filter.floatToFixedPoint(weights[2]); - var w3 = filter.floatToFixedPoint(weights[3]); - - var dstData = dst.data; - var dstWidth = dst.width; - var dstHeight = dst.height; - var dstStride = dstWidth * 4; - - var srcData = src.data; - var srcWidth = src.width; - var srcHeight = src.height; - var srcStride = srcWidth * 4; - var srcStride2 = srcStride * 2; - - if (offsetX < 0 || offsetX + dstWidth > srcWidth || - offsetY < 0 || offsetY + dstHeight > srcHeight) - throw new Error('Invalid offset'); - - // Javascript is not very good at inlining constants. - // We inline manually and assert that the constant is equal to the variable. - if (filter.FIXED_POINT_SHIFT != 16) - throw new Error('Wrong fixed point shift'); - - var margin = 2; - - var startX = Math.max(0, margin - offsetX); - var endX = Math.min(dstWidth, srcWidth - margin - offsetX); - - var startY = Math.max(0, margin - offsetY); - var endY = Math.min(dstHeight, srcHeight - margin - offsetY); - - for (var y = startY; y != endY; y++) { - var dstIndex = y * dstStride + startX * 4; - var srcIndex = (y + offsetY) * srcStride + (startX + offsetX) * 4; - - for (var x = startX; x != endX; x++) { - for (var c = 0; c != 3; c++) { - var sum = w0 * srcData[srcIndex] + - w1 * (srcData[srcIndex - 4] + - srcData[srcIndex + 4] + - srcData[srcIndex - srcStride] + - srcData[srcIndex + srcStride]) + - w2 * (srcData[srcIndex - srcStride - 4] + - srcData[srcIndex + srcStride - 4] + - srcData[srcIndex - srcStride + 4] + - srcData[srcIndex + srcStride + 4]) + - w3 * (srcData[srcIndex - 8] + - srcData[srcIndex + 8] + - srcData[srcIndex - srcStride2] + - srcData[srcIndex + srcStride2]); - if (sum < 0) - dstData[dstIndex++] = 0; - else if (sum > 0xFF0000) - dstData[dstIndex++] = 0xFF; - else - dstData[dstIndex++] = sum >> 16; - srcIndex++; - } - srcIndex++; - dstIndex++; - } - } -}; - -/** - * Compute the average color for the image. - * - * @param {ImageData} imageData Image data to analyze. - * @return {{r: number, g: number, b: number}} average color. - */ -filter.getAverageColor = function(imageData) { - var data = imageData.data; - var width = imageData.width; - var height = imageData.height; - - var total = 0; - var r = 0; - var g = 0; - var b = 0; - - var maxIndex = 4 * width * height; - for (var i = 0; i != maxIndex;) { - total++; - r += data[i++]; - g += data[i++]; - b += data[i++]; - i++; - } - if (total == 0) return { r: 0, g: 0, b: 0 }; - return { r: r / total, g: g / total, b: b / total }; -}; - -/** - * Compute the average color with more weight given to pixes at the center. - * - * @param {ImageData} imageData Image data to analyze. - * @return {{r: number, g: number, b: number}} weighted average color. - */ -filter.getWeightedAverageColor = function(imageData) { - var data = imageData.data; - var width = imageData.width; - var height = imageData.height; - - var total = 0; - var r = 0; - var g = 0; - var b = 0; - - var center = Math.floor(width / 2); - var maxDist = center * Math.sqrt(2); - maxDist *= 2; // Weaken the effect of distance - - var i = 0; - for (var x = 0; x != width; x++) { - for (var y = 0; y != height; y++) { - var dist = Math.sqrt( - (x - center) * (x - center) + (y - center) * (y - center)); - var weight = (maxDist - dist) / maxDist; - - total += weight; - r += data[i++] * weight; - g += data[i++] * weight; - b += data[i++] * weight; - i++; - } - } - if (total == 0) return { r: 0, g: 0, b: 0 }; - return { r: r / total, g: g / total, b: b / total }; -}; - -/** - * Copy part of src image to dst, applying matrix color filter on-the-fly. - * - * The copied part of src should completely fit into dst (there is no clipping - * on either side). - * - * @param {Array.<number>} matrix 3x3 color matrix. - * @param {ImageData} dst Destination image data. - * @param {ImageData} src Source image data. - * @param {number} offsetX X offset in source to start processing. - * @param {number} offsetY Y offset in source to start processing. - */ -filter.colorMatrix3x3 = function(matrix, dst, src, offsetX, offsetY) { - var c11 = filter.floatToFixedPoint(matrix[0]); - var c12 = filter.floatToFixedPoint(matrix[1]); - var c13 = filter.floatToFixedPoint(matrix[2]); - var c21 = filter.floatToFixedPoint(matrix[3]); - var c22 = filter.floatToFixedPoint(matrix[4]); - var c23 = filter.floatToFixedPoint(matrix[5]); - var c31 = filter.floatToFixedPoint(matrix[6]); - var c32 = filter.floatToFixedPoint(matrix[7]); - var c33 = filter.floatToFixedPoint(matrix[8]); - - var dstData = dst.data; - var dstWidth = dst.width; - var dstHeight = dst.height; - - var srcData = src.data; - var srcWidth = src.width; - var srcHeight = src.height; - - if (offsetX < 0 || offsetX + dstWidth > srcWidth || - offsetY < 0 || offsetY + dstHeight > srcHeight) - throw new Error('Invalid offset'); - - // Javascript is not very good at inlining constants. - // We inline manually and assert that the constant is equal to the variable. - if (filter.FIXED_POINT_SHIFT != 16) - throw new Error('Wrong fixed point shift'); - - var dstIndex = 0; - for (var y = 0; y != dstHeight; y++) { - var srcIndex = (offsetX + (offsetY + y) * srcWidth) * 4; - for (var x = 0; x != dstWidth; x++) { - var r = srcData[srcIndex++]; - var g = srcData[srcIndex++]; - var b = srcData[srcIndex++]; - srcIndex++; - - var rNew = r * c11 + g * c12 + b * c13; - var gNew = r * c21 + g * c22 + b * c23; - var bNew = r * c31 + g * c32 + b * c33; - - if (rNew < 0) { - dstData[dstIndex++] = 0; - } else if (rNew > 0xFF0000) { - dstData[dstIndex++] = 0xFF; - } else { - dstData[dstIndex++] = rNew >> 16; - } - - if (gNew < 0) { - dstData[dstIndex++] = 0; - } else if (gNew > 0xFF0000) { - dstData[dstIndex++] = 0xFF; - } else { - dstData[dstIndex++] = gNew >> 16; - } - - if (bNew < 0) { - dstData[dstIndex++] = 0; - } else if (bNew > 0xFF0000) { - dstData[dstIndex++] = 0xFF; - } else { - dstData[dstIndex++] = bNew >> 16; - } - - dstIndex++; - } - } -}; - -/** - * Return a convolution filter function bound to specific weights. - * - * @param {Array.<number>} weights Weights for the convolution matrix - * (not normalized). - * @return {function(ImageData,ImageData,number,number)} Convolution filter. - */ -filter.createConvolutionFilter = function(weights) { - // Normalize the weights to sum to 1. - var total = 0; - for (var i = 0; i != weights.length; i++) { - total += weights[i] * (i ? 4 : 1); - } - - var normalized = []; - for (i = 0; i != weights.length; i++) { - normalized.push(weights[i] / total); - } - for (; i < 4; i++) { - normalized.push(0); - } - - var maxWeightedSum = 0xFF * - Math.abs(normalized[0]) + - Math.abs(normalized[1]) * 4 + - Math.abs(normalized[2]) * 4 + - Math.abs(normalized[3]) * 4; - if (maxWeightedSum > filter.MAX_FLOAT_VALUE) - throw new Error('convolve5x5 cannot convert the weights to fixed point'); - - return filter.convolve5x5.bind(null, normalized); -}; - -/** - * Creates matrix filter. - * @param {Array.<number>} matrix Color transformation matrix. - * @return {function(ImageData,ImageData,number,number)} Matrix filter. - */ -filter.createColorMatrixFilter = function(matrix) { - for (var r = 0; r != 3; r++) { - var maxRowSum = 0; - for (var c = 0; c != 3; c++) { - maxRowSum += 0xFF * Math.abs(matrix[r * 3 + c]); - } - if (maxRowSum > filter.MAX_FLOAT_VALUE) - throw new Error( - 'colorMatrix3x3 cannot convert the matrix to fixed point'); - } - return filter.colorMatrix3x3.bind(null, matrix); -}; - -/** - * Return a blur filter. - * @param {Object} options Blur options. - * @return {function(ImageData,ImageData,number,number)} Blur filter. - */ -filter.blur = function(options) { - if (options.radius == 1) - return filter.createConvolutionFilter( - [1, options.strength]); - else if (options.radius == 2) - return filter.createConvolutionFilter( - [1, options.strength, options.strength]); - else - return filter.createConvolutionFilter( - [1, options.strength, options.strength, options.strength]); -}; - -/** - * Return a sharpen filter. - * @param {Object} options Sharpen options. - * @return {function(ImageData,ImageData,number,number)} Sharpen filter. - */ -filter.sharpen = function(options) { - if (options.radius == 1) - return filter.createConvolutionFilter( - [5, -options.strength]); - else if (options.radius == 2) - return filter.createConvolutionFilter( - [10, -options.strength, -options.strength]); - else - return filter.createConvolutionFilter( - [15, -options.strength, -options.strength, -options.strength]); -}; - -/** - * Return an exposure filter. - * @param {Object} options exposure options. - * @return {function(ImageData,ImageData,number,number)} Exposure filter. - */ -filter.exposure = function(options) { - var pixelMap = filter.precompute( - 255, - function(value) { - if (options.brightness > 0) { - value *= (1 + options.brightness); - } else { - value += (0xFF - value) * options.brightness; - } - return 0x80 + - (value - 0x80) * Math.tan((options.contrast + 1) * Math.PI / 4); - }); - - return filter.mapPixels.bind(null, pixelMap, pixelMap, pixelMap); -}; - -/** - * Return a color autofix filter. - * @param {Object} options Histogram for autofix. - * @return {function(ImageData,ImageData,number,number)} Autofix filter. - */ -filter.autofix = function(options) { - return filter.mapPixels.bind(null, - filter.autofix.stretchColors(options.histogram.r), - filter.autofix.stretchColors(options.histogram.g), - filter.autofix.stretchColors(options.histogram.b)); -}; - -/** - * Return a conversion table that stretches the range of colors used - * in the image to 0..255. - * @param {Array.<number>} channelHistogram Histogram to calculate range. - * @return {Uint8Array} Color mapping array. - */ -filter.autofix.stretchColors = function(channelHistogram) { - var range = filter.autofix.getRange(channelHistogram); - return filter.precompute( - 255, - function(x) { - return (x - range.first) / (range.last - range.first) * 255; - } - ); -}; - -/** - * Return a range that encloses non-zero elements values in a histogram array. - * @param {Array.<number>} channelHistogram Histogram to analyze. - * @return {{first: number, last: number}} Channel range in histogram. - */ -filter.autofix.getRange = function(channelHistogram) { - var first = 0; - while (first < channelHistogram.length && channelHistogram[first] == 0) - first++; - - var last = channelHistogram.length - 1; - while (last >= 0 && channelHistogram[last] == 0) - last--; - - if (first >= last) // Stretching does not make sense - return {first: 0, last: channelHistogram.length - 1}; - else - return {first: first, last: last}; -}; - -/** - * Minimum channel offset that makes visual difference. If autofix calculated - * offset is less than SENSITIVITY, probably autofix is not needed. - * Reasonable empirical value. - * @type {number} - */ -filter.autofix.SENSITIVITY = 8; - -/** - * @param {Array.<number>} channelHistogram Histogram to analyze. - * @return {boolean} True if stretching this range to 0..255 would make - * a visible difference. - */ -filter.autofix.needsStretching = function(channelHistogram) { - var range = filter.autofix.getRange(channelHistogram); - return (range.first >= filter.autofix.SENSITIVITY || - range.last <= 255 - filter.autofix.SENSITIVITY); -}; - -/** - * @param {{r: Array.<number>, g: Array.<number>, b: Array.<number>}} histogram - * @return {boolean} True if the autofix would make a visible difference. - */ -filter.autofix.isApplicable = function(histogram) { - return filter.autofix.needsStretching(histogram.r) || - filter.autofix.needsStretching(histogram.g) || - filter.autofix.needsStretching(histogram.b); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_adjust.js b/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_adjust.js deleted file mode 100644 index 2abb10ed2f5..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_adjust.js +++ /dev/null @@ -1,248 +0,0 @@ -// 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. - -'use strict'; - -/** - * The base class for simple filters that only modify the image content - * but do not modify the image dimensions. - * @constructor - * @extends ImageEditor.Mode - */ -ImageEditor.Mode.Adjust = function() { - ImageEditor.Mode.apply(this, arguments); - this.implicitCommit = true; - this.doneMessage_ = null; - this.viewportGeneration_ = 0; -}; - -ImageEditor.Mode.Adjust.prototype = {__proto__: ImageEditor.Mode.prototype}; - -/** @override */ -ImageEditor.Mode.Adjust.prototype.getCommand = function() { - if (!this.filter_) return null; - - return new Command.Filter(this.name, this.filter_, this.doneMessage_); -}; - -/** @override */ -ImageEditor.Mode.Adjust.prototype.cleanUpUI = function() { - ImageEditor.Mode.prototype.cleanUpUI.apply(this, arguments); - this.hidePreview(); -}; - -/** - * TODO(JSDOC) - */ -ImageEditor.Mode.Adjust.prototype.hidePreview = function() { - if (this.canvas_) { - this.canvas_.parentNode.removeChild(this.canvas_); - this.canvas_ = null; - } -}; - -/** - * TODO(JSDOC) - */ -ImageEditor.Mode.Adjust.prototype.cleanUpCaches = function() { - this.filter_ = null; - this.previewImageData_ = null; -}; - -/** - * TODO(JSDOC) - */ -ImageEditor.Mode.Adjust.prototype.reset = function() { - ImageEditor.Mode.prototype.reset.call(this); - this.hidePreview(); - this.cleanUpCaches(); -}; - -/** - * TODO(JSDOC) - * @param {Object} options // TODO(JSDOC). - */ -ImageEditor.Mode.Adjust.prototype.update = function(options) { - ImageEditor.Mode.prototype.update.apply(this, arguments); - - // We assume filter names are used in the UI directly. - // This will have to change with i18n. - this.filter_ = this.createFilter(options); - this.updatePreviewImage(); - ImageUtil.trace.resetTimer('preview'); - this.filter_(this.previewImageData_, this.originalImageData, 0, 0); - ImageUtil.trace.reportTimer('preview'); - this.canvas_.getContext('2d').putImageData( - this.previewImageData_, 0, 0); -}; - -/** - * Copy the source image data for the preview. - * Use the cached copy if the viewport has not changed. - */ -ImageEditor.Mode.Adjust.prototype.updatePreviewImage = function() { - if (!this.previewImageData_ || - this.viewportGeneration_ != this.getViewport().getCacheGeneration()) { - this.viewportGeneration_ = this.getViewport().getCacheGeneration(); - - if (!this.canvas_) { - this.canvas_ = this.getImageView().createOverlayCanvas(); - } - - this.getImageView().setupDeviceBuffer(this.canvas_); - - this.originalImageData = this.getImageView().copyScreenImageData(); - this.previewImageData_ = this.getImageView().copyScreenImageData(); - } -}; - -/* - * Own methods - */ - -/** - * TODO(JSDOC) - * @param {Object} options // TODO(JSDOC). - * @return {function(ImageData,ImageData,number,number)} Created function. - */ -ImageEditor.Mode.Adjust.prototype.createFilter = function(options) { - return filter.create(this.name, options); -}; - -/** - * A base class for color filters that are scale independent. - * @constructor - */ -ImageEditor.Mode.ColorFilter = function() { - ImageEditor.Mode.Adjust.apply(this, arguments); -}; - -ImageEditor.Mode.ColorFilter.prototype = - {__proto__: ImageEditor.Mode.Adjust.prototype}; - -/** - * TODO(JSDOC) - * @return {{r: Array.<number>, g: Array.<number>, b: Array.<number>}} - * histogram. - */ -ImageEditor.Mode.ColorFilter.prototype.getHistogram = function() { - return filter.getHistogram(this.getImageView().getThumbnail()); -}; - -/** - * Exposure/contrast filter. - * @constructor - */ -ImageEditor.Mode.Exposure = function() { - ImageEditor.Mode.ColorFilter.call(this, 'exposure', 'GALLERY_EXPOSURE'); -}; - -ImageEditor.Mode.Exposure.prototype = - {__proto__: ImageEditor.Mode.ColorFilter.prototype}; - -/** - * TODO(JSDOC) - * @param {ImageEditor.Toolbar} toolbar The toolbar to populate. - */ -ImageEditor.Mode.Exposure.prototype.createTools = function(toolbar) { - toolbar.addRange('brightness', 'GALLERY_BRIGHTNESS', -1, 0, 1, 100); - toolbar.addRange('contrast', 'GALLERY_CONTRAST', -1, 0, 1, 100); -}; - -/** - * Autofix. - * @constructor - */ -ImageEditor.Mode.Autofix = function() { - ImageEditor.Mode.ColorFilter.call(this, 'autofix', 'GALLERY_AUTOFIX'); - this.doneMessage_ = 'GALLERY_FIXED'; -}; - -ImageEditor.Mode.Autofix.prototype = - {__proto__: ImageEditor.Mode.ColorFilter.prototype}; - -/** - * TODO(JSDOC) - * @param {ImageEditor.Toolbar} toolbar The toolbar to populate. - */ -ImageEditor.Mode.Autofix.prototype.createTools = function(toolbar) { - var self = this; - toolbar.addButton('Apply', this.apply.bind(this)); -}; - -/** - * TODO(JSDOC) - * @return {boolean} // TODO(JSDOC). - */ -ImageEditor.Mode.Autofix.prototype.isApplicable = function() { - return this.getImageView().hasValidImage() && - filter.autofix.isApplicable(this.getHistogram()); -}; - -/** - * TODO(JSDOC) - */ -ImageEditor.Mode.Autofix.prototype.apply = function() { - this.update({histogram: this.getHistogram()}); -}; - -/** - * Instant Autofix. - * @constructor - */ -ImageEditor.Mode.InstantAutofix = function() { - ImageEditor.Mode.Autofix.apply(this, arguments); - this.instant = true; -}; - -ImageEditor.Mode.InstantAutofix.prototype = - {__proto__: ImageEditor.Mode.Autofix.prototype}; - -/** - * TODO(JSDOC) - */ -ImageEditor.Mode.InstantAutofix.prototype.setUp = function() { - ImageEditor.Mode.Autofix.prototype.setUp.apply(this, arguments); - this.apply(); -}; - -/** - * Blur filter. - * @constructor - */ -ImageEditor.Mode.Blur = function() { - ImageEditor.Mode.Adjust.call(this, 'blur'); -}; - -ImageEditor.Mode.Blur.prototype = - {__proto__: ImageEditor.Mode.Adjust.prototype}; - -/** - * TODO(JSDOC) - * @param {ImageEditor.Toolbar} toolbar The toolbar to populate. - */ -ImageEditor.Mode.Blur.prototype.createTools = function(toolbar) { - toolbar.addRange('strength', 'GALLERY_STRENGTH', 0, 0, 1, 100); - toolbar.addRange('radius', 'GALLERY_RADIUS', 1, 1, 3); -}; - -/** - * Sharpen filter. - * @constructor - */ -ImageEditor.Mode.Sharpen = function() { - ImageEditor.Mode.Adjust.call(this, 'sharpen'); -}; - -ImageEditor.Mode.Sharpen.prototype = - {__proto__: ImageEditor.Mode.Adjust.prototype}; - -/** - * TODO(JSDOC) - * @param {ImageEditor.Toolbar} toolbar The toolbar to populate. - */ -ImageEditor.Mode.Sharpen.prototype.createTools = function(toolbar) { - toolbar.addRange('strength', 'GALLERY_STRENGTH', 0, 0, 1, 100); - toolbar.addRange('radius', 'GALLERY_RADIUS', 1, 1, 3); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_buffer.js b/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_buffer.js deleted file mode 100644 index 8e894a8a0f2..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_buffer.js +++ /dev/null @@ -1,184 +0,0 @@ -// 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. - -'use strict'; - -/** - * A stack of overlays that display itself and handle mouse events. - * TODO(kaznacheev) Consider disbanding this class and moving - * the functionality to individual objects that display anything or handle - * mouse events. - * @constructor - */ -function ImageBuffer() { - this.overlays_ = []; -} - -/** - * TODO(JSDOC). - * @param {ImageBuffer.Overlay} overlay // TODO(JSDOC). - */ -ImageBuffer.prototype.addOverlay = function(overlay) { - var zIndex = overlay.getZIndex(); - // Store the overlays in the ascending Z-order. - var i; - for (i = 0; i != this.overlays_.length; i++) { - if (zIndex < this.overlays_[i].getZIndex()) break; - } - this.overlays_.splice(i, 0, overlay); -}; - -/** - * TODO(JSDOC). - * @param {ImageBuffer.Overlay} overlay // TODO(JSDOC). - */ -ImageBuffer.prototype.removeOverlay = function(overlay) { - for (var i = 0; i != this.overlays_.length; i++) { - if (this.overlays_[i] == overlay) { - this.overlays_.splice(i, 1); - return; - } - } - throw new Error('Cannot remove overlay ' + overlay); -}; - -/** - * Draws overlays in the ascending Z-order. - */ -ImageBuffer.prototype.draw = function() { - for (var i = 0; i != this.overlays_.length; i++) { - this.overlays_[i].draw(); - } -}; - -/** - * Searches for a cursor style in the descending Z-order. - * @param {number} x X coordinate for cursor. - * @param {number} y Y coordinate for cursor. - * @param {boolean} mouseDown If mouse button is down. - * @return {string} A value for style.cursor CSS property. - */ -ImageBuffer.prototype.getCursorStyle = function(x, y, mouseDown) { - for (var i = this.overlays_.length - 1; i >= 0; i--) { - var style = this.overlays_[i].getCursorStyle(x, y, mouseDown); - if (style) return style; - } - return 'default'; -}; - -/** - * Searches for a click handler in the descending Z-order. - * @param {number} x X coordinate for click event. - * @param {number} y Y coordinate for click event. - * @return {boolean} True if handled. - */ -ImageBuffer.prototype.onClick = function(x, y) { - for (var i = this.overlays_.length - 1; i >= 0; i--) { - if (this.overlays_[i].onClick(x, y)) return true; - } - return false; -}; - -/** - * Searches for a drag handler in the descending Z-order. - * @param {number} x Event X coordinate. - * @param {number} y Event Y coordinate. - * @param {boolean} touch True if it's a touch event, false if mouse. - * @return {function(number,number)} A function to be called on mouse drag. - */ -ImageBuffer.prototype.getDragHandler = function(x, y, touch) { - for (var i = this.overlays_.length - 1; i >= 0; i--) { - var handler = this.overlays_[i].getDragHandler(x, y, touch); - if (handler) - return handler; - } - return null; -}; - -/** - * Searches for an action for the double tap enumerating - * layers in the descending Z-order. - * @param {number} x X coordinate of the event. - * @param {number} y Y coordinate of the event. - * @return {ImageBuffer.DoubleTapAction} Action to perform as result. - */ -ImageBuffer.prototype.getDoubleTapAction = function(x, y) { - for (var i = this.overlays_.length - 1; i >= 0; i--) { - var action = this.overlays_[i].getDoubleTapAction(x, y); - if (action != ImageBuffer.DoubleTapAction.NOTHING) - return action; - } - return ImageBuffer.DoubleTapAction.NOTHING; -}; - -/** - * Possible double tap actions. - * @enum - */ -ImageBuffer.DoubleTapAction = { - NOTHING: 0, - COMMIT: 1, - CANCEL: 2 -}; - -/** - * ImageBuffer.Overlay is a pluggable extension that modifies the outlook - * and the behavior of the ImageBuffer instance. - * @class - */ -ImageBuffer.Overlay = function() {}; - -/** - * TODO(JSDOC). - * @return {number} // TODO(JSDOC). - */ -ImageBuffer.Overlay.prototype.getZIndex = function() { return 0 }; - -/** - * TODO(JSDOC). - */ -ImageBuffer.Overlay.prototype.draw = function() {}; - -/** - * TODO(JSDOC). - * @param {number} x X coordinate for cursor. - * @param {number} y Y coordinate for cursor. - * @param {boolean} mouseDown If mouse button is down. - * @return {?string} A value for style.cursor CSS property or null for - * default. - */ -ImageBuffer.Overlay.prototype.getCursorStyle = function(x, y, mouseDown) { - return null; -}; - -/** - * TODO(JSDOC). - * @param {number} x // TODO(JSDOC). - * @param {number} y // TODO(JSDOC). - * @return {boolean} // TODO(JSDOC). - */ -ImageBuffer.Overlay.prototype.onClick = function(x, y) { - return false; -}; - -/** - * TODO(JSDOC). - * @param {number} x Event X coordinate. - * @param {number} y Event Y coordinate. - * @param {boolean} touch True if it's a touch event, false if mouse. - * @return {function(number,number)} A function to be called on mouse drag. - */ -ImageBuffer.Overlay.prototype.getDragHandler = function(x, y, touch) { - return null; -}; - -/** - * TODO(JSDOC). - * @param {number} x // TODO(JSDOC). - * @param {number} y // TODO(JSDOC). - * @return {ImageBuffer.DoubleTapAction} // TODO(JSDOC). - */ -ImageBuffer.Overlay.prototype.getDoubleTapAction = function(x, y) { - return ImageBuffer.DoubleTapAction.NOTHING; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_editor.js b/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_editor.js deleted file mode 100644 index 090155494bd..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_editor.js +++ /dev/null @@ -1,1177 +0,0 @@ -// 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. - -'use strict'; - -/** - * ImageEditor is the top level object that holds together and connects - * everything needed for image editing. - * - * @param {Viewport} viewport The viewport. - * @param {ImageView} imageView The ImageView containing the images to edit. - * @param {ImageEditor.Prompt} prompt Prompt instance. - * @param {Object} DOMContainers Various DOM containers required for the editor. - * @param {Array.<ImageEditor.Mode>} modes Available editor modes. - * @param {function} displayStringFunction String formatting function. - * @param {function()} onToolsVisibilityChanged Callback to be called, when - * some of the UI elements have been dimmed or revealed. - * @constructor - */ -function ImageEditor( - viewport, imageView, prompt, DOMContainers, modes, displayStringFunction, - onToolsVisibilityChanged) { - this.rootContainer_ = DOMContainers.root; - this.container_ = DOMContainers.image; - this.modes_ = modes; - this.displayStringFunction_ = displayStringFunction; - this.onToolsVisibilityChanged_ = onToolsVisibilityChanged; - - ImageUtil.removeChildren(this.container_); - - var document = this.container_.ownerDocument; - - this.viewport_ = viewport; - this.viewport_.sizeByFrame(this.container_); - - this.buffer_ = new ImageBuffer(); - this.viewport_.addRepaintCallback(this.buffer_.draw.bind(this.buffer_)); - - this.imageView_ = imageView; - this.imageView_.addContentCallback(this.onContentUpdate_.bind(this)); - this.buffer_.addOverlay(this.imageView_); - - this.panControl_ = new ImageEditor.MouseControl( - this.rootContainer_, this.container_, this.getBuffer()); - - this.panControl_.setDoubleTapCallback(this.onDoubleTap_.bind(this)); - - this.mainToolbar_ = new ImageEditor.Toolbar( - DOMContainers.toolbar, displayStringFunction); - - this.modeToolbar_ = new ImageEditor.Toolbar( - DOMContainers.mode, displayStringFunction, - this.onOptionsChange.bind(this)); - - this.prompt_ = prompt; - - this.createToolButtons(); - - this.commandQueue_ = null; -} - -/** - * @return {boolean} True if no user commands are to be accepted. - */ -ImageEditor.prototype.isLocked = function() { - return !this.commandQueue_ || this.commandQueue_.isBusy(); -}; - -/** - * @return {boolean} True if the command queue is busy. - */ -ImageEditor.prototype.isBusy = function() { - return this.commandQueue_ && this.commandQueue_.isBusy(); -}; - -/** - * Reflect the locked state of the editor in the UI. - * @param {boolean} on True if locked. - */ -ImageEditor.prototype.lockUI = function(on) { - ImageUtil.setAttribute(this.rootContainer_, 'locked', on); -}; - -/** - * Report the tool use to the metrics subsystem. - * @param {string} name Action name. - */ -ImageEditor.prototype.recordToolUse = function(name) { - ImageUtil.metrics.recordEnum( - ImageUtil.getMetricName('Tool'), name, this.actionNames_); -}; - -/** - * Content update handler. - * @private - */ -ImageEditor.prototype.onContentUpdate_ = function() { - for (var i = 0; i != this.modes_.length; i++) { - var mode = this.modes_[i]; - ImageUtil.setAttribute(mode.button_, 'disabled', !mode.isApplicable()); - } -}; - -/** - * Open the editing session for a new image. - * - * @param {string} url Image url. - * @param {Object} metadata Metadata. - * @param {Object} effect Transition effect object. - * @param {function(function)} saveFunction Image save function. - * @param {function} displayCallback Display callback. - * @param {function} loadCallback Load callback. - */ -ImageEditor.prototype.openSession = function( - url, metadata, effect, saveFunction, displayCallback, loadCallback) { - if (this.commandQueue_) - throw new Error('Session not closed'); - - this.lockUI(true); - - var self = this; - this.imageView_.load( - url, metadata, effect, displayCallback, function(loadType, delay, error) { - self.lockUI(false); - self.commandQueue_ = new CommandQueue( - self.container_.ownerDocument, - self.imageView_.getCanvas(), - saveFunction); - self.commandQueue_.attachUI( - self.getImageView(), self.getPrompt(), self.lockUI.bind(self)); - self.updateUndoRedo(); - loadCallback(loadType, delay, error); - }); -}; - -/** - * Close the current image editing session. - * @param {function} callback Callback. - */ -ImageEditor.prototype.closeSession = function(callback) { - this.getPrompt().hide(); - if (this.imageView_.isLoading()) { - if (this.commandQueue_) { - console.warn('Inconsistent image editor state'); - this.commandQueue_ = null; - } - this.imageView_.cancelLoad(); - this.lockUI(false); - callback(); - return; - } - if (!this.commandQueue_) { - // Session is already closed. - callback(); - return; - } - - this.executeWhenReady(callback); - this.commandQueue_.close(); - this.commandQueue_ = null; -}; - -/** - * Commit the current operation and execute the action. - * - * @param {function} callback Callback. - */ -ImageEditor.prototype.executeWhenReady = function(callback) { - if (this.commandQueue_) { - this.leaveModeGently(); - this.commandQueue_.executeWhenReady(callback); - } else { - if (!this.imageView_.isLoading()) - console.warn('Inconsistent image editor state'); - callback(); - } -}; - -/** - * @return {boolean} True if undo queue is not empty. - */ -ImageEditor.prototype.canUndo = function() { - return this.commandQueue_ && this.commandQueue_.canUndo(); -}; - -/** - * Undo the recently executed command. - */ -ImageEditor.prototype.undo = function() { - if (this.isLocked()) return; - this.recordToolUse('undo'); - - // First undo click should dismiss the uncommitted modifications. - if (this.currentMode_ && this.currentMode_.isUpdated()) { - this.currentMode_.reset(); - return; - } - - this.getPrompt().hide(); - this.leaveMode(false); - this.commandQueue_.undo(); - this.updateUndoRedo(); -}; - -/** - * Redo the recently un-done command. - */ -ImageEditor.prototype.redo = function() { - if (this.isLocked()) return; - this.recordToolUse('redo'); - this.getPrompt().hide(); - this.leaveMode(false); - this.commandQueue_.redo(); - this.updateUndoRedo(); -}; - -/** - * Update Undo/Redo buttons state. - */ -ImageEditor.prototype.updateUndoRedo = function() { - var canUndo = this.commandQueue_ && this.commandQueue_.canUndo(); - var canRedo = this.commandQueue_ && this.commandQueue_.canRedo(); - ImageUtil.setAttribute(this.undoButton_, 'disabled', !canUndo); - this.redoButton_.hidden = !canRedo; -}; - -/** - * @return {HTMLCanvasElement} The current image canvas. - */ -ImageEditor.prototype.getCanvas = function() { - return this.getImageView().getCanvas(); -}; - -/** - * @return {ImageBuffer} ImageBuffer instance. - */ -ImageEditor.prototype.getBuffer = function() { return this.buffer_ }; - -/** - * @return {ImageView} ImageView instance. - */ -ImageEditor.prototype.getImageView = function() { return this.imageView_ }; - -/** - * @return {Viewport} Viewport instance. - */ -ImageEditor.prototype.getViewport = function() { return this.viewport_ }; - -/** - * @return {ImageEditor.Prompt} Prompt instance. - */ -ImageEditor.prototype.getPrompt = function() { return this.prompt_ }; - -/** - * Handle the toolbar controls update. - * @param {Object} options A map of options. - */ -ImageEditor.prototype.onOptionsChange = function(options) { - ImageUtil.trace.resetTimer('update'); - if (this.currentMode_) { - this.currentMode_.update(options); - } - ImageUtil.trace.reportTimer('update'); -}; - -/** - * ImageEditor.Mode represents a modal state dedicated to a specific operation. - * Inherits from ImageBuffer. Overlay to simplify the drawing of mode-specific - * tools. - * - * @param {string} name The mode name. - * @param {string} title The mode title. - * @constructor - */ - -ImageEditor.Mode = function(name, title) { - this.name = name; - this.title = title; - this.message_ = 'GALLERY_ENTER_WHEN_DONE'; -}; - -ImageEditor.Mode.prototype = {__proto__: ImageBuffer.Overlay.prototype }; - -/** - * @return {Viewport} Viewport instance. - */ -ImageEditor.Mode.prototype.getViewport = function() { return this.viewport_ }; - -/** - * @return {ImageView} ImageView instance. - */ -ImageEditor.Mode.prototype.getImageView = function() { return this.imageView_ }; - -/** - * @return {string} The mode-specific message to be displayed when entering. - */ -ImageEditor.Mode.prototype.getMessage = function() { return this.message_ }; - -/** - * @return {boolean} True if the mode is applicable in the current context. - */ -ImageEditor.Mode.prototype.isApplicable = function() { return true }; - -/** - * Called once after creating the mode button. - * - * @param {ImageEditor} editor The editor instance. - * @param {HTMLElement} button The mode button. - */ - -ImageEditor.Mode.prototype.bind = function(editor, button) { - this.editor_ = editor; - this.editor_.registerAction_(this.name); - this.button_ = button; - this.viewport_ = editor.getViewport(); - this.imageView_ = editor.getImageView(); -}; - -/** - * Called before entering the mode. - */ -ImageEditor.Mode.prototype.setUp = function() { - this.editor_.getBuffer().addOverlay(this); - this.updated_ = false; -}; - -/** - * Create mode-specific controls here. - * @param {ImageEditor.Toolbar} toolbar The toolbar to populate. - */ -ImageEditor.Mode.prototype.createTools = function(toolbar) {}; - -/** - * Called before exiting the mode. - */ -ImageEditor.Mode.prototype.cleanUpUI = function() { - this.editor_.getBuffer().removeOverlay(this); -}; - -/** - * Called after exiting the mode. - */ -ImageEditor.Mode.prototype.cleanUpCaches = function() {}; - -/** - * Called when any of the controls changed its value. - * @param {Object} options A map of options. - */ -ImageEditor.Mode.prototype.update = function(options) { - this.markUpdated(); -}; - -/** - * Mark the editor mode as updated. - */ -ImageEditor.Mode.prototype.markUpdated = function() { - this.updated_ = true; -}; - -/** - * @return {boolean} True if the mode controls changed. - */ -ImageEditor.Mode.prototype.isUpdated = function() { return this.updated_ }; - -/** - * Resets the mode to a clean state. - */ -ImageEditor.Mode.prototype.reset = function() { - this.editor_.modeToolbar_.reset(); - this.updated_ = false; -}; - -/** - * One-click editor tool, requires no interaction, just executes the command. - * - * @param {string} name The mode name. - * @param {string} title The mode title. - * @param {Command} command The command to execute on click. - * @constructor - */ -ImageEditor.Mode.OneClick = function(name, title, command) { - ImageEditor.Mode.call(this, name, title); - this.instant = true; - this.command_ = command; -}; - -ImageEditor.Mode.OneClick.prototype = {__proto__: ImageEditor.Mode.prototype}; - -/** - * @return {Command} command. - */ -ImageEditor.Mode.OneClick.prototype.getCommand = function() { - return this.command_; -}; - -/** - * Register the action name. Required for metrics reporting. - * @param {string} name Button name. - * @private - */ -ImageEditor.prototype.registerAction_ = function(name) { - this.actionNames_.push(name); -}; - -/** - * Populate the toolbar. - */ -ImageEditor.prototype.createToolButtons = function() { - this.mainToolbar_.clear(); - this.actionNames_ = []; - - var self = this; - function createButton(name, title, handler) { - return self.mainToolbar_.addButton(name, - title, - handler, - name /* opt_className */); - } - - for (var i = 0; i != this.modes_.length; i++) { - var mode = this.modes_[i]; - mode.bind(this, createButton(mode.name, - mode.title, - this.enterMode.bind(this, mode))); - } - - this.undoButton_ = createButton('undo', - 'GALLERY_UNDO', - this.undo.bind(this)); - this.registerAction_('undo'); - - this.redoButton_ = createButton('redo', - 'GALLERY_REDO', - this.redo.bind(this)); - this.registerAction_('redo'); -}; - -/** - * @return {ImageEditor.Mode} The current mode. - */ -ImageEditor.prototype.getMode = function() { return this.currentMode_ }; - -/** - * The user clicked on the mode button. - * - * @param {ImageEditor.Mode} mode The new mode. - */ -ImageEditor.prototype.enterMode = function(mode) { - if (this.isLocked()) return; - - if (this.currentMode_ == mode) { - // Currently active editor tool clicked, commit if modified. - this.leaveMode(this.currentMode_.updated_); - return; - } - - this.recordToolUse(mode.name); - - this.leaveModeGently(); - // The above call could have caused a commit which might have initiated - // an asynchronous command execution. Wait for it to complete, then proceed - // with the mode set up. - this.commandQueue_.executeWhenReady(this.setUpMode_.bind(this, mode)); -}; - -/** - * Set up the new editing mode. - * - * @param {ImageEditor.Mode} mode The mode. - * @private - */ -ImageEditor.prototype.setUpMode_ = function(mode) { - this.currentTool_ = mode.button_; - - ImageUtil.setAttribute(this.currentTool_, 'pressed', true); - - this.currentMode_ = mode; - this.currentMode_.setUp(); - - if (this.currentMode_.instant) { // Instant tool. - this.leaveMode(true); - return; - } - - this.getPrompt().show(this.currentMode_.getMessage()); - - this.modeToolbar_.clear(); - this.currentMode_.createTools(this.modeToolbar_); - this.modeToolbar_.show(true); -}; - -/** - * The user clicked on 'OK' or 'Cancel' or on a different mode button. - * @param {boolean} commit True if commit is required. - */ -ImageEditor.prototype.leaveMode = function(commit) { - if (!this.currentMode_) return; - - if (!this.currentMode_.instant) { - this.getPrompt().hide(); - } - - this.modeToolbar_.show(false); - - this.currentMode_.cleanUpUI(); - if (commit) { - var self = this; - var command = this.currentMode_.getCommand(); - if (command) { // Could be null if the user did not do anything. - this.commandQueue_.execute(command); - this.updateUndoRedo(); - } - } - this.currentMode_.cleanUpCaches(); - this.currentMode_ = null; - - ImageUtil.setAttribute(this.currentTool_, 'pressed', false); - this.currentTool_ = null; -}; - -/** - * Leave the mode, commit only if required by the current mode. - */ -ImageEditor.prototype.leaveModeGently = function() { - this.leaveMode(this.currentMode_ && - this.currentMode_.updated_ && - this.currentMode_.implicitCommit); -}; - -/** - * Enter the editor mode with the given name. - * - * @param {string} name Mode name. - * @private - */ -ImageEditor.prototype.enterModeByName_ = function(name) { - for (var i = 0; i != this.modes_.length; i++) { - var mode = this.modes_[i]; - if (mode.name == name) { - if (!mode.button_.hasAttribute('disabled')) - this.enterMode(mode); - return; - } - } - console.error('Mode "' + name + '" not found.'); -}; - -/** - * Key down handler. - * @param {Event} event The keydown event. - * @return {boolean} True if handled. - */ -ImageEditor.prototype.onKeyDown = function(event) { - switch (util.getKeyModifiers(event) + event.keyIdentifier) { - case 'U+001B': // Escape - case 'Enter': - if (this.getMode()) { - this.leaveMode(event.keyIdentifier == 'Enter'); - return true; - } - break; - - case 'Ctrl-U+005A': // Ctrl+Z - if (this.commandQueue_.canUndo()) { - this.undo(); - return true; - } - break; - - case 'Ctrl-U+0059': // Ctrl+Y - if (this.commandQueue_.canRedo()) { - this.redo(); - return true; - } - break; - - case 'U+0041': // 'a' - this.enterModeByName_('autofix'); - return true; - - case 'U+0042': // 'b' - this.enterModeByName_('exposure'); - return true; - - case 'U+0043': // 'c' - this.enterModeByName_('crop'); - return true; - - case 'U+004C': // 'l' - this.enterModeByName_('rotate_left'); - return true; - - case 'U+0052': // 'r' - this.enterModeByName_('rotate_right'); - return true; - } - return false; -}; - -/** - * Double tap handler. - * @param {number} x X coordinate of the event. - * @param {number} y Y coordinate of the event. - * @private - */ -ImageEditor.prototype.onDoubleTap_ = function(x, y) { - if (this.getMode()) { - var action = this.buffer_.getDoubleTapAction(x, y); - if (action == ImageBuffer.DoubleTapAction.COMMIT) - this.leaveMode(true); - else if (action == ImageBuffer.DoubleTapAction.CANCEL) - this.leaveMode(false); - } -}; - -/** - * Hide the tools that overlap the given rectangular frame. - * - * @param {Rect} frame Hide the tool that overlaps this rect. - * @param {Rect} transparent But do not hide the tool that is completely inside - * this rect. - */ -ImageEditor.prototype.hideOverlappingTools = function(frame, transparent) { - var tools = this.rootContainer_.ownerDocument.querySelectorAll('.dimmable'); - var changed = false; - for (var i = 0; i != tools.length; i++) { - var tool = tools[i]; - var toolRect = tool.getBoundingClientRect(); - var overlapping = - (frame && frame.intersects(toolRect)) && - !(transparent && transparent.contains(toolRect)); - if (overlapping && !tool.hasAttribute('dimmed') || - !overlapping && tool.hasAttribute('dimmed')) { - ImageUtil.setAttribute(tool, 'dimmed', overlapping); - changed = true; - } - } - if (changed) - this.onToolsVisibilityChanged_(); -}; - -/** - * A helper object for panning the ImageBuffer. - * - * @param {HTMLElement} rootContainer The top-level container. - * @param {HTMLElement} container The container for mouse events. - * @param {ImageBuffer} buffer Image buffer. - * @constructor - */ -ImageEditor.MouseControl = function(rootContainer, container, buffer) { - this.rootContainer_ = rootContainer; - this.container_ = container; - this.buffer_ = buffer; - - var handlers = { - 'touchstart': this.onTouchStart, - 'touchend': this.onTouchEnd, - 'touchcancel': this.onTouchCancel, - 'touchmove': this.onTouchMove, - 'mousedown': this.onMouseDown, - 'mouseup': this.onMouseUp - }; - - for (var eventName in handlers) { - container.addEventListener( - eventName, handlers[eventName].bind(this), false); - } - - // Mouse move handler has to be attached to the window to receive events - // from outside of the window. See: http://crbug.com/155705 - window.addEventListener('mousemove', this.onMouseMove.bind(this), false); -}; - -/** - * Maximum movement for touch to be detected as a tap (in pixels). - * @private - */ -ImageEditor.MouseControl.MAX_MOVEMENT_FOR_TAP_ = 8; - -/** - * Maximum time for touch to be detected as a tap (in milliseconds). - * @private - */ -ImageEditor.MouseControl.MAX_TAP_DURATION_ = 500; - -/** - * Maximum distance from the first tap to the second tap to be considered - * as a double tap. - * @private - */ -ImageEditor.MouseControl.MAX_DISTANCE_FOR_DOUBLE_TAP_ = 32; - -/** - * Maximum time for touch to be detected as a double tap (in milliseconds). - * @private - */ -ImageEditor.MouseControl.MAX_DOUBLE_TAP_DURATION_ = 1000; - -/** - * Returns an event's position. - * - * @param {MouseEvent|Touch} e Pointer position. - * @return {Object} A pair of x,y in page coordinates. - * @private - */ -ImageEditor.MouseControl.getPosition_ = function(e) { - return { - x: e.pageX, - y: e.pageY - }; -}; - -/** - * Returns touch position or null if there is more than one touch position. - * - * @param {TouchEvent} e Event. - * @return {object?} A pair of x,y in page coordinates. - * @private - */ -ImageEditor.MouseControl.prototype.getTouchPosition_ = function(e) { - if (e.targetTouches.length == 1) - return ImageEditor.MouseControl.getPosition_(e.targetTouches[0]); - else - return null; -}; - -/** - * Touch start handler. - * @param {TouchEvent} e Event. - */ -ImageEditor.MouseControl.prototype.onTouchStart = function(e) { - var position = this.getTouchPosition_(e); - if (position) { - this.touchStartInfo_ = { - x: position.x, - y: position.y, - time: Date.now() - }; - this.dragHandler_ = this.buffer_.getDragHandler(position.x, position.y, - true /* touch */); - this.dragHappened_ = false; - } -}; - -/** - * Touch end handler. - * @param {TouchEvent} e Event. - */ -ImageEditor.MouseControl.prototype.onTouchEnd = function(e) { - if (!this.dragHappened_ && Date.now() - this.touchStartInfo_.time <= - ImageEditor.MouseControl.MAX_TAP_DURATION_) { - this.buffer_.onClick(this.touchStartInfo_.x, this.touchStartInfo_.y); - if (this.previousTouchStartInfo_ && - Date.now() - this.previousTouchStartInfo_.time < - ImageEditor.MouseControl.MAX_DOUBLE_TAP_DURATION_) { - var prevTouchCircle = new Circle( - this.previousTouchStartInfo_.x, - this.previousTouchStartInfo_.y, - ImageEditor.MouseControl.MAX_DISTANCE_FOR_DOUBLE_TAP_); - if (prevTouchCircle.inside(this.touchStartInfo_.x, - this.touchStartInfo_.y)) { - this.doubleTapCallback_(this.touchStartInfo_.x, this.touchStartInfo_.y); - } - } - this.previousTouchStartInfo_ = this.touchStartInfo_; - } else { - this.previousTouchStartInfo_ = null; - } - this.onTouchCancel(e); -}; - -/** - * Default double tap handler. - * @param {number} x X coordinate of the event. - * @param {number} y Y coordinate of the event. - * @private - */ -ImageEditor.MouseControl.prototype.doubleTapCallback_ = function(x, y) {}; - -/** - * Sets callback to be called when double tap detected. - * @param {function(number, number)} callback New double tap callback. - */ -ImageEditor.MouseControl.prototype.setDoubleTapCallback = function(callback) { - this.doubleTapCallback_ = callback; -}; - -/** - * Touch chancel handler. - */ -ImageEditor.MouseControl.prototype.onTouchCancel = function() { - this.dragHandler_ = null; - this.dragHappened_ = false; - this.touchStartInfo_ = null; - this.lockMouse_(false); -}; - -/** - * Touch move handler. - * @param {TouchEvent} e Event. - */ -ImageEditor.MouseControl.prototype.onTouchMove = function(e) { - var position = this.getTouchPosition_(e); - if (!position) - return; - - if (this.touchStartInfo_ && !this.dragHappened_) { - var tapCircle = new Circle(this.touchStartInfo_.x, this.touchStartInfo_.y, - ImageEditor.MouseControl.MAX_MOVEMENT_FOR_TAP_); - this.dragHappened_ = !tapCircle.inside(position.x, position.y); - } - if (this.dragHandler_ && this.dragHappened_) { - this.dragHandler_(position.x, position.y); - this.lockMouse_(true); - } -}; - -/** - * Mouse down handler. - * @param {MouseEvent} e Event. - */ -ImageEditor.MouseControl.prototype.onMouseDown = function(e) { - var position = ImageEditor.MouseControl.getPosition_(e); - - this.dragHandler_ = this.buffer_.getDragHandler(position.x, position.y, - false /* mouse */); - this.dragHappened_ = false; - this.updateCursor_(position); -}; - -/** - * Mouse up handler. - * @param {MouseEvent} e Event. - */ -ImageEditor.MouseControl.prototype.onMouseUp = function(e) { - var position = ImageEditor.MouseControl.getPosition_(e); - - if (!this.dragHappened_) { - this.buffer_.onClick(position.x, position.y); - } - this.dragHandler_ = null; - this.dragHappened_ = false; - this.lockMouse_(false); -}; - -/** - * Mouse move handler. - * @param {MouseEvent} e Event. - */ -ImageEditor.MouseControl.prototype.onMouseMove = function(e) { - var position = ImageEditor.MouseControl.getPosition_(e); - - if (this.dragHandler_ && !e.which) { - // mouseup must have happened while the mouse was outside our window. - this.dragHandler_ = null; - this.lockMouse_(false); - } - - this.updateCursor_(position); - if (this.dragHandler_) { - this.dragHandler_(position.x, position.y); - this.dragHappened_ = true; - this.lockMouse_(true); - } -}; - -/** - * Update the UI to reflect mouse drag state. - * @param {boolean} on True if dragging. - * @private - */ -ImageEditor.MouseControl.prototype.lockMouse_ = function(on) { - ImageUtil.setAttribute(this.rootContainer_, 'mousedrag', on); -}; - -/** - * Update the cursor. - * - * @param {Object} position An object holding x and y properties. - * @private - */ -ImageEditor.MouseControl.prototype.updateCursor_ = function(position) { - var oldCursor = this.container_.getAttribute('cursor'); - var newCursor = this.buffer_.getCursorStyle( - position.x, position.y, !!this.dragHandler_); - if (newCursor != oldCursor) // Avoid flicker. - this.container_.setAttribute('cursor', newCursor); -}; - -/** - * A toolbar for the ImageEditor. - * @param {HTMLElement} parent The parent element. - * @param {function} displayStringFunction A string formatting function. - * @param {function} updateCallback The callback called when controls change. - * @constructor - */ -ImageEditor.Toolbar = function(parent, displayStringFunction, updateCallback) { - this.wrapper_ = parent; - this.displayStringFunction_ = displayStringFunction; - this.updateCallback_ = updateCallback; -}; - -/** - * Clear the toolbar. - */ -ImageEditor.Toolbar.prototype.clear = function() { - ImageUtil.removeChildren(this.wrapper_); -}; - -/** - * Create a control. - * @param {string} tagName The element tag name. - * @return {HTMLElement} The created control element. - * @private - */ -ImageEditor.Toolbar.prototype.create_ = function(tagName) { - return this.wrapper_.ownerDocument.createElement(tagName); -}; - -/** - * Add a control. - * @param {HTMLElement} element The control to add. - * @return {HTMLElement} The added element. - */ -ImageEditor.Toolbar.prototype.add = function(element) { - this.wrapper_.appendChild(element); - return element; -}; - -/** - * Add a text label. - * @param {string} name Label name. - * @return {HTMLElement} The added label. - */ -ImageEditor.Toolbar.prototype.addLabel = function(name) { - var label = this.create_('span'); - label.textContent = this.displayStringFunction_(name); - return this.add(label); -}; - -/** - * Add a button. - * - * @param {string} name Button name. - * @param {string} title Button title. - * @param {function} handler onClick handler. - * @param {string=} opt_class Extra class name. - * @return {HTMLElement} The added button. - */ -ImageEditor.Toolbar.prototype.addButton = function( - name, title, handler, opt_class) { - var button = this.create_('button'); - if (opt_class) button.classList.add(opt_class); - var label = this.create_('span'); - label.textContent = this.displayStringFunction_(title); - button.appendChild(label); - button.label = this.displayStringFunction_(title); - button.addEventListener('click', handler, false); - return this.add(button); -}; - -/** - * Add a range control (scalar value picker). - * - * @param {string} name An option name. - * @param {string} title An option title. - * @param {number} min Min value of the option. - * @param {number} value Default value of the option. - * @param {number} max Max value of the options. - * @param {number} scale A number to multiply by when setting - * min/value/max in DOM. - * @param {boolean=} opt_showNumeric True if numeric value should be displayed. - * @return {HTMLElement} Range element. - */ -ImageEditor.Toolbar.prototype.addRange = function( - name, title, min, value, max, scale, opt_showNumeric) { - var self = this; - - scale = scale || 1; - - var range = this.create_('input'); - - range.className = 'range'; - range.type = 'range'; - range.name = name; - range.min = Math.ceil(min * scale); - range.max = Math.floor(max * scale); - - var numeric = this.create_('div'); - numeric.className = 'numeric'; - function mirror() { - numeric.textContent = Math.round(range.getValue() * scale) / scale; - } - - range.setValue = function(newValue) { - range.value = Math.round(newValue * scale); - mirror(); - }; - - range.getValue = function() { - return Number(range.value) / scale; - }; - - range.reset = function() { - range.setValue(value); - }; - - range.addEventListener('change', - function() { - mirror(); - self.updateCallback_(self.getOptions()); - }, - false); - - range.setValue(value); - - var label = this.create_('div'); - label.textContent = this.displayStringFunction_(title); - label.className = 'label ' + name; - this.add(label); - this.add(range); - - if (opt_showNumeric) - this.add(numeric); - - // Swallow the left and right keys, so they are not handled by other - // listeners. - range.addEventListener('keydown', function(e) { - if (e.keyIdentifier === 'Left' || e.keyIdentifier === 'Right') - e.stopPropagation(); - }); - - return range; -}; - -/** - * @return {Object} options A map of options. - */ -ImageEditor.Toolbar.prototype.getOptions = function() { - var values = {}; - for (var child = this.wrapper_.firstChild; child; child = child.nextSibling) { - if (child.name) - values[child.name] = child.getValue(); - } - return values; -}; - -/** - * Reset the toolbar. - */ -ImageEditor.Toolbar.prototype.reset = function() { - for (var child = this.wrapper_.firstChild; child; child = child.nextSibling) { - if (child.reset) child.reset(); - } -}; - -/** - * Show/hide the toolbar. - * @param {boolean} on True if show. - */ -ImageEditor.Toolbar.prototype.show = function(on) { - if (!this.wrapper_.firstChild) - return; // Do not show empty toolbar; - - this.wrapper_.hidden = !on; -}; - -/** A prompt panel for the editor. - * - * @param {HTMLElement} container Container element. - * @param {function} displayStringFunction A formatting function. - * @constructor - */ -ImageEditor.Prompt = function(container, displayStringFunction) { - this.container_ = container; - this.displayStringFunction_ = displayStringFunction; -}; - -/** - * Reset the prompt. - */ -ImageEditor.Prompt.prototype.reset = function() { - this.cancelTimer(); - if (this.wrapper_) { - this.container_.removeChild(this.wrapper_); - this.wrapper_ = null; - this.prompt_ = null; - } -}; - -/** - * Cancel the delayed action. - */ -ImageEditor.Prompt.prototype.cancelTimer = function() { - if (this.timer_) { - clearTimeout(this.timer_); - this.timer_ = null; - } -}; - -/** - * Schedule the delayed action. - * @param {function} callback Callback. - * @param {number} timeout Timeout. - */ -ImageEditor.Prompt.prototype.setTimer = function(callback, timeout) { - this.cancelTimer(); - var self = this; - this.timer_ = setTimeout(function() { - self.timer_ = null; - callback(); - }, timeout); -}; - -/** - * Show the prompt. - * - * @param {string} text The prompt text. - * @param {number} timeout Timeout in ms. - * @param {Object} formatArgs varArgs for the formatting fuction. - */ -ImageEditor.Prompt.prototype.show = function(text, timeout, formatArgs) { - this.showAt.apply(this, - ['center'].concat(Array.prototype.slice.call(arguments))); -}; - -/** - * - * @param {string} pos The 'pos' attribute value. - * @param {string} text The prompt text. - * @param {number} timeout Timeout in ms. - * @param {Object} formatArgs varArgs for the formatting function. - */ -ImageEditor.Prompt.prototype.showAt = function(pos, text, timeout, formatArgs) { - this.reset(); - if (!text) return; - - var document = this.container_.ownerDocument; - this.wrapper_ = document.createElement('div'); - this.wrapper_.className = 'prompt-wrapper'; - this.wrapper_.setAttribute('pos', pos); - this.container_.appendChild(this.wrapper_); - - this.prompt_ = document.createElement('div'); - this.prompt_.className = 'prompt'; - - // Create an extra wrapper which opacity can be manipulated separately. - var tool = document.createElement('div'); - tool.className = 'dimmable'; - this.wrapper_.appendChild(tool); - tool.appendChild(this.prompt_); - - var args = [text].concat(Array.prototype.slice.call(arguments, 3)); - this.prompt_.textContent = this.displayStringFunction_.apply(null, args); - - var close = document.createElement('div'); - close.className = 'close'; - close.addEventListener('click', this.hide.bind(this)); - this.prompt_.appendChild(close); - - setTimeout( - this.prompt_.setAttribute.bind(this.prompt_, 'state', 'fadein'), 0); - - if (timeout) - this.setTimer(this.hide.bind(this), timeout); -}; - -/** - * Hide the prompt. - */ -ImageEditor.Prompt.prototype.hide = function() { - if (!this.prompt_) return; - this.prompt_.setAttribute('state', 'fadeout'); - // Allow some time for the animation to play out. - this.setTimer(this.reset.bind(this), 500); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_encoder.js b/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_encoder.js deleted file mode 100644 index 1c96b1fe326..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_encoder.js +++ /dev/null @@ -1,228 +0,0 @@ -// 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. - -'use strict'; - -/** - * A namespace class for image encoding functions. All methods are static. - */ -function ImageEncoder() {} - -/** - * @type {Array.<Object>} - */ -ImageEncoder.metadataEncoders = {}; - -/** - * @param {function(new:ImageEncoder.MetadataEncoder)} constructor - * // TODO(JSDOC). - * @param {string} mimeType // TODO(JSDOC). - */ -ImageEncoder.registerMetadataEncoder = function(constructor, mimeType) { - ImageEncoder.metadataEncoders[mimeType] = constructor; -}; - -/** - * Create a metadata encoder. - * - * The encoder will own and modify a copy of the original metadata. - * - * @param {Object} metadata Original metadata. - * @return {ImageEncoder.MetadataEncoder} Created metadata encoder. - */ -ImageEncoder.createMetadataEncoder = function(metadata) { - var constructor = ImageEncoder.metadataEncoders[metadata.mimeType] || - ImageEncoder.MetadataEncoder; - return new constructor(metadata); -}; - - -/** - * Create a metadata encoder object holding a copy of metadata - * modified according to the properties of the supplied image. - * - * @param {Object} metadata Original metadata. - * @param {HTMLCanvasElement} canvas Canvas to use for metadata. - * @param {number} quality Encoding quality (defaults to 1). - * @return {ImageEncoder.MetadataEncoder} Encoder with encoded metadata. - */ -ImageEncoder.encodeMetadata = function(metadata, canvas, quality) { - var encoder = ImageEncoder.createMetadataEncoder(metadata); - encoder.setImageData(canvas); - encoder.setThumbnailData(ImageEncoder.createThumbnail(canvas), quality || 1); - return encoder; -}; - - -/** - * Return a blob with the encoded image with metadata inserted. - * @param {HTMLCanvasElement} canvas The canvas with the image to be encoded. - * @param {ImageEncoder.MetadataEncoder} metadataEncoder Encoder to use. - * @param {number} quality (0..1], Encoding quality, defaults to 0.9. - * @return {Blob} encoded data. - */ -ImageEncoder.getBlob = function(canvas, metadataEncoder, quality) { - // Contrary to what one might think 1.0 is not a good default. Opening and - // saving an typical photo taken with consumer camera increases its file size - // by 50-100%. - // Experiments show that 0.9 is much better. It shrinks some photos a bit, - // keeps others about the same size, but does not visibly lower the quality. - quality = quality || 0.9; - - ImageUtil.trace.resetTimer('dataurl'); - // WebKit does not support canvas.toBlob yet so canvas.toDataURL is - // the only way to use the Chrome built-in image encoder. - var dataURL = - canvas.toDataURL(metadataEncoder.getMetadata().mimeType, quality); - ImageUtil.trace.reportTimer('dataurl'); - - var encodedImage = ImageEncoder.decodeDataURL(dataURL); - - var encodedMetadata = metadataEncoder.encode(); - - var slices = []; - - // TODO(kaznacheev): refactor |stringToArrayBuffer| and |encode| to return - // arrays instead of array buffers. - function appendSlice(arrayBuffer) { - slices.push(new DataView(arrayBuffer)); - } - - ImageUtil.trace.resetTimer('blob'); - if (encodedMetadata.byteLength != 0) { - var metadataRange = metadataEncoder.findInsertionRange(encodedImage); - appendSlice(ImageEncoder.stringToArrayBuffer( - encodedImage, 0, metadataRange.from)); - - appendSlice(metadataEncoder.encode()); - - appendSlice(ImageEncoder.stringToArrayBuffer( - encodedImage, metadataRange.to, encodedImage.length)); - } else { - appendSlice(ImageEncoder.stringToArrayBuffer( - encodedImage, 0, encodedImage.length)); - } - var blob = new Blob(slices, {type: metadataEncoder.getMetadata().mimeType}); - ImageUtil.trace.reportTimer('blob'); - return blob; -}; - -/** - * Decode a dataURL into a binary string containing the encoded image. - * - * Why return a string? Calling atob and having the rest of the code deal - * with a string is several times faster than decoding base64 in Javascript. - * - * @param {string} dataURL Data URL to decode. - * @return {string} A binary string (char codes are the actual byte values). - */ -ImageEncoder.decodeDataURL = function(dataURL) { - // Skip the prefix ('data:image/<type>;base64,') - var base64string = dataURL.substring(dataURL.indexOf(',') + 1); - return atob(base64string); -}; - -/** - * Return a thumbnail for an image. - * @param {HTMLCanvasElement} canvas Original image. - * @param {number=} opt_shrinkage Thumbnail should be at least this much smaller - * than the original image (in each dimension). - * @return {HTMLCanvasElement} Thumbnail canvas. - */ -ImageEncoder.createThumbnail = function(canvas, opt_shrinkage) { - var MAX_THUMBNAIL_DIMENSION = 320; - - opt_shrinkage = Math.max(opt_shrinkage || 4, - canvas.width / MAX_THUMBNAIL_DIMENSION, - canvas.height / MAX_THUMBNAIL_DIMENSION); - - var thumbnailCanvas = canvas.ownerDocument.createElement('canvas'); - thumbnailCanvas.width = Math.round(canvas.width / opt_shrinkage); - thumbnailCanvas.height = Math.round(canvas.height / opt_shrinkage); - - var context = thumbnailCanvas.getContext('2d'); - context.drawImage(canvas, - 0, 0, canvas.width, canvas.height, - 0, 0, thumbnailCanvas.width, thumbnailCanvas.height); - - return thumbnailCanvas; -}; - -/** - * TODO(JSDOC) - * @param {string} string // TODO(JSDOC). - * @param {number} from // TODO(JSDOC). - * @param {number} to // TODO(JSDOC). - * @return {ArrayBuffer} // TODO(JSDOC). - */ -ImageEncoder.stringToArrayBuffer = function(string, from, to) { - var size = to - from; - var array = new Uint8Array(size); - for (var i = 0; i != size; i++) { - array[i] = string.charCodeAt(from + i); - } - return array.buffer; -}; - -/** - * A base class for a metadata encoder. - * - * Serves as a default metadata encoder for images that none of the metadata - * parsers recognized. - * - * @param {Object} original_metadata Starting metadata. - * @constructor - */ -ImageEncoder.MetadataEncoder = function(original_metadata) { - this.metadata_ = MetadataCache.cloneMetadata(original_metadata) || {}; - if (this.metadata_.mimeType != 'image/jpeg') { - // Chrome can only encode JPEG and PNG. Force PNG mime type so that we - // can save to file and generate a thumbnail. - this.metadata_.mimeType = 'image/png'; - } -}; - -/** - * TODO(JSDOC) - * @return {Object} // TODO(JSDOC). - */ -ImageEncoder.MetadataEncoder.prototype.getMetadata = function() { - return this.metadata_; -}; - -/** - * @param {HTMLCanvasElement|Object} canvas Canvas or or anything with - * width and height properties. - */ -ImageEncoder.MetadataEncoder.prototype.setImageData = function(canvas) { - this.metadata_.width = canvas.width; - this.metadata_.height = canvas.height; -}; - -/** - * @param {HTMLCanvasElement} canvas Canvas to use as thumbnail. - * @param {number} quality Thumbnail quality. - */ -ImageEncoder.MetadataEncoder.prototype.setThumbnailData = - function(canvas, quality) { - this.metadata_.thumbnailURL = - canvas.toDataURL(this.metadata_.mimeType, quality); -}; - -/** - * Return a range where the metadata is (or should be) located. - * @param {string} encodedImage // TODO(JSDOC). - * @return {Object} An object with from and to properties. - */ -ImageEncoder.MetadataEncoder.prototype. - findInsertionRange = function(encodedImage) { return {from: 0, to: 0} }; - -/** - * Return serialized metadata ready to write to an image file. - * The return type is optimized for passing to Blob.append. - * @return {ArrayBuffer} // TODO(JSDOC). - */ -ImageEncoder.MetadataEncoder.prototype.encode = function() { - return new Uint8Array(0).buffer; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_transform.js b/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_transform.js deleted file mode 100644 index 6b194baf0fc..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_transform.js +++ /dev/null @@ -1,493 +0,0 @@ -// 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. - -'use strict'; - -/** - * Crop mode. - * @constructor - */ -ImageEditor.Mode.Crop = function() { - ImageEditor.Mode.call(this, 'crop', 'GALLERY_CROP'); -}; - -ImageEditor.Mode.Crop.prototype = {__proto__: ImageEditor.Mode.prototype}; - -/** - * TODO(JSDOC). - */ -ImageEditor.Mode.Crop.prototype.setUp = function() { - ImageEditor.Mode.prototype.setUp.apply(this, arguments); - - var container = this.getImageView().container_; - var doc = container.ownerDocument; - - this.domOverlay_ = doc.createElement('div'); - this.domOverlay_.className = 'crop-overlay'; - container.appendChild(this.domOverlay_); - - this.shadowTop_ = doc.createElement('div'); - this.shadowTop_.className = 'shadow'; - this.domOverlay_.appendChild(this.shadowTop_); - - this.middleBox_ = doc.createElement('div'); - this.middleBox_.className = 'middle-box'; - this.domOverlay_.appendChild(this.middleBox_); - - this.shadowLeft_ = doc.createElement('div'); - this.shadowLeft_.className = 'shadow'; - this.middleBox_.appendChild(this.shadowLeft_); - - this.cropFrame_ = doc.createElement('div'); - this.cropFrame_.className = 'crop-frame'; - this.middleBox_.appendChild(this.cropFrame_); - - this.shadowRight_ = doc.createElement('div'); - this.shadowRight_.className = 'shadow'; - this.middleBox_.appendChild(this.shadowRight_); - - this.shadowBottom_ = doc.createElement('div'); - this.shadowBottom_.className = 'shadow'; - this.domOverlay_.appendChild(this.shadowBottom_); - - var cropFrame = this.cropFrame_; - function addCropFrame(className) { - var div = doc.createElement('div'); - div.className = className; - cropFrame.appendChild(div); - } - - addCropFrame('left top corner'); - addCropFrame('top horizontal'); - addCropFrame('right top corner'); - addCropFrame('left vertical'); - addCropFrame('right vertical'); - addCropFrame('left bottom corner'); - addCropFrame('bottom horizontal'); - addCropFrame('right bottom corner'); - - this.onResizedBound_ = this.onResized_.bind(this); - window.addEventListener('resize', this.onResizedBound_); - - this.createDefaultCrop(); -}; - -/** - * Handles resizing of the window and updates the crop rectangle. - * @private - */ -ImageEditor.Mode.Crop.prototype.onResized_ = function() { - this.positionDOM(); -}; - -/** - * TODO(JSDOC). - */ -ImageEditor.Mode.Crop.prototype.reset = function() { - ImageEditor.Mode.prototype.reset.call(this); - this.createDefaultCrop(); -}; - -/** - * TODO(JSDOC). - */ -ImageEditor.Mode.Crop.prototype.positionDOM = function() { - var screenClipped = this.viewport_.getScreenClipped(); - - var screenCrop = this.viewport_.imageToScreenRect(this.cropRect_.getRect()); - var delta = ImageEditor.Mode.Crop.MOUSE_GRAB_RADIUS; - this.editor_.hideOverlappingTools( - screenCrop.inflate(delta, delta), - screenCrop.inflate(-delta, -delta)); - - this.domOverlay_.style.left = screenClipped.left + 'px'; - this.domOverlay_.style.top = screenClipped.top + 'px'; - this.domOverlay_.style.width = screenClipped.width + 'px'; - this.domOverlay_.style.height = screenClipped.height + 'px'; - - this.shadowLeft_.style.width = screenCrop.left - screenClipped.left + 'px'; - - this.shadowTop_.style.height = screenCrop.top - screenClipped.top + 'px'; - - this.shadowRight_.style.width = screenClipped.left + screenClipped.width - - (screenCrop.left + screenCrop.width) + 'px'; - - this.shadowBottom_.style.height = screenClipped.top + screenClipped.height - - (screenCrop.top + screenCrop.height) + 'px'; -}; - -/** - * TODO(JSDOC). - */ -ImageEditor.Mode.Crop.prototype.cleanUpUI = function() { - ImageEditor.Mode.prototype.cleanUpUI.apply(this, arguments); - this.domOverlay_.parentNode.removeChild(this.domOverlay_); - this.domOverlay_ = null; - this.editor_.hideOverlappingTools(); - window.removeEventListener(this.onResizedBound_); - this.onResizedBound_ = null; -}; - -/** - * @const - * @type {number} - */ -ImageEditor.Mode.Crop.MOUSE_GRAB_RADIUS = 6; -/** - * @const - * @type {number} - */ -ImageEditor.Mode.Crop.TOUCH_GRAB_RADIUS = 20; - -/** - * TODO(JSDOC). - * @return {Command.Crop} // TODO(JSDOC). - */ -ImageEditor.Mode.Crop.prototype.getCommand = function() { - var cropImageRect = this.cropRect_.getRect(); - return new Command.Crop(cropImageRect); -}; - -/** - * TODO(JSDOC). - */ -ImageEditor.Mode.Crop.prototype.createDefaultCrop = function() { - var rect = new Rect(this.getViewport().getImageClipped()); - rect = rect.inflate( - -Math.round(rect.width / 6), -Math.round(rect.height / 6)); - this.cropRect_ = new DraggableRect(rect, this.getViewport()); - this.positionDOM(); -}; - -/** - * TODO(JSDOC). - * @param {number} x X coordinate for cursor. - * @param {number} y Y coordinate for cursor. - * @param {boolean} mouseDown If mouse button is down. - * @return {string} A value for style.cursor CSS property. - */ -ImageEditor.Mode.Crop.prototype.getCursorStyle = function(x, y, mouseDown) { - return this.cropRect_.getCursorStyle(x, y, mouseDown); -}; - -/** - * TODO(JSDOC). - * @param {number} x Event X coordinate. - * @param {number} y Event Y coordinate. - * @param {boolean} touch True if it's a touch event, false if mouse. - * @return {function(number,number)} A function to be called on mouse drag. - */ -ImageEditor.Mode.Crop.prototype.getDragHandler = function(x, y, touch) { - var cropDragHandler = this.cropRect_.getDragHandler(x, y, touch); - if (!cropDragHandler) return null; - - var self = this; - return function(x, y) { - cropDragHandler(x, y); - self.markUpdated(); - self.positionDOM(); - }; -}; - -/** - * TODO(JSDOC). - * @param {number} x X coordinate of the event. - * @param {number} y Y coordinate of the event. - * @return {ImageBuffer.DoubleTapAction} Action to perform as result. - */ -ImageEditor.Mode.Crop.prototype.getDoubleTapAction = function(x, y) { - return this.cropRect_.getDoubleTapAction(x, y); -}; - -/* - * A draggable rectangle over the image. - * @param {Rect} rect // TODO(JSDOC). - * @param {Viewport} viewport // TODO(JSDOC). - * @constructor - */ -function DraggableRect(rect, viewport) { - // The bounds are not held in a regular rectangle (with width/height). - // left/top/right/bottom held instead for convenience. - this.bounds_ = {}; - this.bounds_[DraggableRect.LEFT] = rect.left; - this.bounds_[DraggableRect.RIGHT] = rect.left + rect.width; - this.bounds_[DraggableRect.TOP] = rect.top; - this.bounds_[DraggableRect.BOTTOM] = rect.top + rect.height; - - this.viewport_ = viewport; - - this.oppositeSide_ = {}; - this.oppositeSide_[DraggableRect.LEFT] = DraggableRect.RIGHT; - this.oppositeSide_[DraggableRect.RIGHT] = DraggableRect.LEFT; - this.oppositeSide_[DraggableRect.TOP] = DraggableRect.BOTTOM; - this.oppositeSide_[DraggableRect.BOTTOM] = DraggableRect.TOP; - - // Translation table to form CSS-compatible cursor style. - this.cssSide_ = {}; - this.cssSide_[DraggableRect.LEFT] = 'w'; - this.cssSide_[DraggableRect.TOP] = 'n'; - this.cssSide_[DraggableRect.RIGHT] = 'e'; - this.cssSide_[DraggableRect.BOTTOM] = 's'; - this.cssSide_[DraggableRect.NONE] = ''; -} - -// Static members to simplify reflective access to the bounds. -/** - * @const - * @type {string} - */ -DraggableRect.LEFT = 'left'; -/** - * @const - * @type {string} - */ -DraggableRect.RIGHT = 'right'; -/** - * @const - * @type {string} - */ -DraggableRect.TOP = 'top'; -/** - * @const - * @type {string} - */ -DraggableRect.BOTTOM = 'bottom'; -/** - * @const - * @type {string} - */ -DraggableRect.NONE = 'none'; - -/** - * TODO(JSDOC) - * @return {number} // TODO(JSDOC). - */ -DraggableRect.prototype.getLeft = function() { - return this.bounds_[DraggableRect.LEFT]; -}; - -/** - * TODO(JSDOC) - * @return {number} // TODO(JSDOC). - */ -DraggableRect.prototype.getRight = function() { - return this.bounds_[DraggableRect.RIGHT]; -}; - -/** - * TODO(JSDOC) - * @return {number} // TODO(JSDOC). - */ -DraggableRect.prototype.getTop = function() { - return this.bounds_[DraggableRect.TOP]; -}; - -/** - * TODO(JSDOC) - * @return {number} // TODO(JSDOC). - */ -DraggableRect.prototype.getBottom = function() { - return this.bounds_[DraggableRect.BOTTOM]; -}; - -/** - * TODO(JSDOC) - * @return {Rect} // TODO(JSDOC). - */ -DraggableRect.prototype.getRect = function() { - return new Rect(this.bounds_); -}; - -/** - * TODO(JSDOC) - * @param {number} x X coordinate for cursor. - * @param {number} y Y coordinate for cursor. - * @param {boolean} touch // TODO(JSDOC). - * @return {Object} // TODO(JSDOC). - */ -DraggableRect.prototype.getDragMode = function(x, y, touch) { - var result = { - xSide: DraggableRect.NONE, - ySide: DraggableRect.NONE - }; - - var bounds = this.bounds_; - var R = this.viewport_.screenToImageSize( - touch ? ImageEditor.Mode.Crop.TOUCH_GRAB_RADIUS : - ImageEditor.Mode.Crop.MOUSE_GRAB_RADIUS); - - var circle = new Circle(x, y, R); - - var xBetween = ImageUtil.between(bounds.left, x, bounds.right); - var yBetween = ImageUtil.between(bounds.top, y, bounds.bottom); - - if (circle.inside(bounds.left, bounds.top)) { - result.xSide = DraggableRect.LEFT; - result.ySide = DraggableRect.TOP; - } else if (circle.inside(bounds.left, bounds.bottom)) { - result.xSide = DraggableRect.LEFT; - result.ySide = DraggableRect.BOTTOM; - } else if (circle.inside(bounds.right, bounds.top)) { - result.xSide = DraggableRect.RIGHT; - result.ySide = DraggableRect.TOP; - } else if (circle.inside(bounds.right, bounds.bottom)) { - result.xSide = DraggableRect.RIGHT; - result.ySide = DraggableRect.BOTTOM; - } else if (yBetween && Math.abs(x - bounds.left) <= R) { - result.xSide = DraggableRect.LEFT; - } else if (yBetween && Math.abs(x - bounds.right) <= R) { - result.xSide = DraggableRect.RIGHT; - } else if (xBetween && Math.abs(y - bounds.top) <= R) { - result.ySide = DraggableRect.TOP; - } else if (xBetween && Math.abs(y - bounds.bottom) <= R) { - result.ySide = DraggableRect.BOTTOM; - } else if (xBetween && yBetween) { - result.whole = true; - } else { - result.newcrop = true; - result.xSide = DraggableRect.RIGHT; - result.ySide = DraggableRect.BOTTOM; - } - - return result; -}; - -/** - * TODO(JSDOC) - * @param {number} x X coordinate for cursor. - * @param {number} y Y coordinate for cursor. - * @param {boolean} mouseDown If mouse button is down. - * @return {string} // TODO(JSDOC). - */ -DraggableRect.prototype.getCursorStyle = function(x, y, mouseDown) { - var mode; - if (mouseDown) { - mode = this.dragMode_; - } else { - mode = this.getDragMode( - this.viewport_.screenToImageX(x), this.viewport_.screenToImageY(y)); - } - if (mode.whole) return 'move'; - if (mode.newcrop) return 'crop'; - return this.cssSide_[mode.ySide] + this.cssSide_[mode.xSide] + '-resize'; -}; - -/** - * TODO(JSDOC) - * @param {number} x X coordinate for cursor. - * @param {number} y Y coordinate for cursor. - * @param {boolean} touch // TODO(JSDOC). - * @return {function(number,number)} // TODO(JSDOC). - */ -DraggableRect.prototype.getDragHandler = function(x, y, touch) { - x = this.viewport_.screenToImageX(x); - y = this.viewport_.screenToImageY(y); - - var clipRect = this.viewport_.getImageClipped(); - if (!clipRect.inside(x, y)) return null; - - this.dragMode_ = this.getDragMode(x, y, touch); - - var self = this; - - var mouseBiasX; - var mouseBiasY; - - var fixedWidth = 0; - var fixedHeight = 0; - - var resizeFuncX; - var resizeFuncY; - - if (this.dragMode_.whole) { - mouseBiasX = this.bounds_.left - x; - fixedWidth = this.bounds_.right - this.bounds_.left; - resizeFuncX = function(x) { - self.bounds_.left = x; - self.bounds_.right = self.bounds_.left + fixedWidth; - }; - mouseBiasY = this.bounds_.top - y; - fixedHeight = this.bounds_.bottom - this.bounds_.top; - resizeFuncY = function(y) { - self.bounds_.top = y; - self.bounds_.bottom = self.bounds_.top + fixedHeight; - }; - } else { - var checkNewCrop = function() { - if (self.dragMode_.newcrop) { - self.dragMode_.newcrop = false; - self.bounds_.left = self.bounds_.right = x; - self.bounds_.top = self.bounds_.bottom = y; - mouseBiasX = 0; - mouseBiasY = 0; - } - }; - - var flipSide = function(side) { - var opposite = self.oppositeSide_[side]; - var temp = self.bounds_[side]; - self.bounds_[side] = self.bounds_[opposite]; - self.bounds_[opposite] = temp; - return opposite; - }; - - if (this.dragMode_.xSide != DraggableRect.NONE) { - mouseBiasX = self.bounds_[this.dragMode_.xSide] - x; - resizeFuncX = function(x) { - checkNewCrop(); - self.bounds_[self.dragMode_.xSide] = x; - if (self.bounds_.left > self.bounds_.right) { - self.dragMode_.xSide = flipSide(self.dragMode_.xSide); - } - }; - } - if (this.dragMode_.ySide != DraggableRect.NONE) { - mouseBiasY = self.bounds_[this.dragMode_.ySide] - y; - resizeFuncY = function(y) { - checkNewCrop(); - self.bounds_[self.dragMode_.ySide] = y; - if (self.bounds_.top > self.bounds_.bottom) { - self.dragMode_.ySide = flipSide(self.dragMode_.ySide); - } - }; - } - } - - function convertX(x) { - return ImageUtil.clamp( - clipRect.left, - self.viewport_.screenToImageX(x) + mouseBiasX, - clipRect.left + clipRect.width - fixedWidth); - } - - function convertY(y) { - return ImageUtil.clamp( - clipRect.top, - self.viewport_.screenToImageY(y) + mouseBiasY, - clipRect.top + clipRect.height - fixedHeight); - } - - return function(x, y) { - if (resizeFuncX) resizeFuncX(convertX(x)); - if (resizeFuncY) resizeFuncY(convertY(y)); - }; -}; - -/** - * TODO(JSDOC) - * @param {number} x X coordinate for cursor. - * @param {number} y Y coordinate for cursor. - * @param {boolean} touch // TODO(JSDOC). - * @return {ImageBuffer.DoubleTapAction} // TODO(JSDOC). - */ -DraggableRect.prototype.getDoubleTapAction = function(x, y, touch) { - x = this.viewport_.screenToImageX(x); - y = this.viewport_.screenToImageY(y); - - var clipRect = this.viewport_.getImageClipped(); - if (clipRect.inside(x, y)) - return ImageBuffer.DoubleTapAction.COMMIT; - else - return ImageBuffer.DoubleTapAction.NOTHING; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_util.js b/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_util.js deleted file mode 100644 index f088f7c6c83..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_util.js +++ /dev/null @@ -1,701 +0,0 @@ -// 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. - -'use strict'; - - -// Namespace object for the utilities. -function ImageUtil() {} - -/** - * Performance trace. - */ -ImageUtil.trace = (function() { - function PerformanceTrace() { - this.lines_ = {}; - this.timers_ = {}; - this.container_ = null; - } - - PerformanceTrace.prototype.bindToDOM = function(container) { - this.container_ = container; - }; - - PerformanceTrace.prototype.report = function(key, value) { - if (!(key in this.lines_)) { - if (this.container_) { - var div = this.lines_[key] = document.createElement('div'); - this.container_.appendChild(div); - } else { - this.lines_[key] = {}; - } - } - this.lines_[key].textContent = key + ': ' + value; - if (ImageUtil.trace.log) this.dumpLine(key); - }; - - PerformanceTrace.prototype.resetTimer = function(key) { - this.timers_[key] = Date.now(); - }; - - PerformanceTrace.prototype.reportTimer = function(key) { - this.report(key, (Date.now() - this.timers_[key]) + 'ms'); - }; - - PerformanceTrace.prototype.dump = function() { - for (var key in this.lines_) - this.dumpLine(key); - }; - - PerformanceTrace.prototype.dumpLine = function(key) { - console.log('trace.' + this.lines_[key].textContent); - }; - - return new PerformanceTrace(); -})(); - -/** - * @param {number} min Minimum value. - * @param {number} value Value to adjust. - * @param {number} max Maximum value. - * @return {number} The closest to the |value| number in span [min, max]. - */ -ImageUtil.clamp = function(min, value, max) { - return Math.max(min, Math.min(max, value)); -}; - -/** - * @param {number} min Minimum value. - * @param {number} value Value to check. - * @param {number} max Maximum value. - * @return {boolean} True if value is between. - */ -ImageUtil.between = function(min, value, max) { - return (value - min) * (value - max) <= 0; -}; - -/** - * Rectangle class. - */ - -/** - * Rectangle constructor takes 0, 1, 2 or 4 arguments. - * Supports following variants: - * new Rect(left, top, width, height) - * new Rect(width, height) - * new Rect(rect) // anything with left, top, width, height properties - * new Rect(bounds) // anything with left, top, right, bottom properties - * new Rect(canvas|image) // anything with width and height properties. - * new Rect() // empty rectangle. - * @constructor - */ -function Rect() { - switch (arguments.length) { - case 4: - this.left = arguments[0]; - this.top = arguments[1]; - this.width = arguments[2]; - this.height = arguments[3]; - return; - - case 2: - this.left = 0; - this.top = 0; - this.width = arguments[0]; - this.height = arguments[1]; - return; - - case 1: { - var source = arguments[0]; - if ('left' in source && 'top' in source) { - this.left = source.left; - this.top = source.top; - if ('right' in source && 'bottom' in source) { - this.width = source.right - source.left; - this.height = source.bottom - source.top; - return; - } - } else { - this.left = 0; - this.top = 0; - } - if ('width' in source && 'height' in source) { - this.width = source.width; - this.height = source.height; - return; - } - break; // Fall through to the error message. - } - - case 0: - this.left = 0; - this.top = 0; - this.width = 0; - this.height = 0; - return; - } - console.error('Invalid Rect constructor arguments:', - Array.apply(null, arguments)); -} - -/** - * @param {number} factor Factor to scale. - * @return {Rect} A rectangle with every dimension scaled. - */ -Rect.prototype.scale = function(factor) { - return new Rect( - this.left * factor, - this.top * factor, - this.width * factor, - this.height * factor); -}; - -/** - * @param {number} dx Difference in X. - * @param {number} dy Difference in Y. - * @return {Rect} A rectangle shifted by (dx,dy), same size. - */ -Rect.prototype.shift = function(dx, dy) { - return new Rect(this.left + dx, this.top + dy, this.width, this.height); -}; - -/** - * @param {number} x Coordinate of the left top corner. - * @param {number} y Coordinate of the left top corner. - * @return {Rect} A rectangle with left==x and top==y, same size. - */ -Rect.prototype.moveTo = function(x, y) { - return new Rect(x, y, this.width, this.height); -}; - -/** - * @param {number} dx Difference in X. - * @param {number} dy Difference in Y. - * @return {Rect} A rectangle inflated by (dx, dy), same center. - */ -Rect.prototype.inflate = function(dx, dy) { - return new Rect( - this.left - dx, this.top - dy, this.width + 2 * dx, this.height + 2 * dy); -}; - -/** - * @param {number} x Coordinate of the point. - * @param {number} y Coordinate of the point. - * @return {boolean} True if the point lies inside the rectangle. - */ -Rect.prototype.inside = function(x, y) { - return this.left <= x && x < this.left + this.width && - this.top <= y && y < this.top + this.height; -}; - -/** - * @param {Rect} rect Rectangle to check. - * @return {boolean} True if this rectangle intersects with the |rect|. - */ -Rect.prototype.intersects = function(rect) { - return (this.left + this.width) > rect.left && - (rect.left + rect.width) > this.left && - (this.top + this.height) > rect.top && - (rect.top + rect.height) > this.top; -}; - -/** - * @param {Rect} rect Rectangle to check. - * @return {boolean} True if this rectangle containing the |rect|. - */ -Rect.prototype.contains = function(rect) { - return (this.left <= rect.left) && - (rect.left + rect.width) <= (this.left + this.width) && - (this.top <= rect.top) && - (rect.top + rect.height) <= (this.top + this.height); -}; - -/** - * @return {boolean} True if rectangle is empty. - */ -Rect.prototype.isEmpty = function() { - return this.width === 0 || this.height === 0; -}; - -/** - * Clamp the rectangle to the bounds by moving it. - * Decrease the size only if necessary. - * @param {Rect} bounds Bounds. - * @return {Rect} Calculated rectangle. - */ -Rect.prototype.clamp = function(bounds) { - var rect = new Rect(this); - - if (rect.width > bounds.width) { - rect.left = bounds.left; - rect.width = bounds.width; - } else if (rect.left < bounds.left) { - rect.left = bounds.left; - } else if (rect.left + rect.width > - bounds.left + bounds.width) { - rect.left = bounds.left + bounds.width - rect.width; - } - - if (rect.height > bounds.height) { - rect.top = bounds.top; - rect.height = bounds.height; - } else if (rect.top < bounds.top) { - rect.top = bounds.top; - } else if (rect.top + rect.height > - bounds.top + bounds.height) { - rect.top = bounds.top + bounds.height - rect.height; - } - - return rect; -}; - -/** - * @return {string} String representation. - */ -Rect.prototype.toString = function() { - return '(' + this.left + ',' + this.top + '):' + - '(' + (this.left + this.width) + ',' + (this.top + this.height) + ')'; -}; -/* - * Useful shortcuts for drawing (static functions). - */ - -/** - * Draw the image in context with appropriate scaling. - * @param {CanvasRenderingContext2D} context Context to draw. - * @param {Image} image Image to draw. - * @param {Rect=} opt_dstRect Rectangle in the canvas (whole canvas by default). - * @param {Rect=} opt_srcRect Rectangle in the image (whole image by default). - */ -Rect.drawImage = function(context, image, opt_dstRect, opt_srcRect) { - opt_dstRect = opt_dstRect || new Rect(context.canvas); - opt_srcRect = opt_srcRect || new Rect(image); - if (opt_dstRect.isEmpty() || opt_srcRect.isEmpty()) - return; - context.drawImage(image, - opt_srcRect.left, opt_srcRect.top, opt_srcRect.width, opt_srcRect.height, - opt_dstRect.left, opt_dstRect.top, opt_dstRect.width, opt_dstRect.height); -}; - -/** - * Draw a box around the rectangle. - * @param {CanvasRenderingContext2D} context Context to draw. - * @param {Rect} rect Rectangle. - */ -Rect.outline = function(context, rect) { - context.strokeRect( - rect.left - 0.5, rect.top - 0.5, rect.width + 1, rect.height + 1); -}; - -/** - * Fill the rectangle. - * @param {CanvasRenderingContext2D} context Context to draw. - * @param {Rect} rect Rectangle. - */ -Rect.fill = function(context, rect) { - context.fillRect(rect.left, rect.top, rect.width, rect.height); -}; - -/** - * Fills the space between the two rectangles. - * @param {CanvasRenderingContext2D} context Context to draw. - * @param {Rect} inner Inner rectangle. - * @param {Rect} outer Outer rectangle. - */ -Rect.fillBetween = function(context, inner, outer) { - var innerRight = inner.left + inner.width; - var innerBottom = inner.top + inner.height; - var outerRight = outer.left + outer.width; - var outerBottom = outer.top + outer.height; - if (inner.top > outer.top) { - context.fillRect( - outer.left, outer.top, outer.width, inner.top - outer.top); - } - if (inner.left > outer.left) { - context.fillRect( - outer.left, inner.top, inner.left - outer.left, inner.height); - } - if (inner.width < outerRight) { - context.fillRect( - innerRight, inner.top, outerRight - innerRight, inner.height); - } - if (inner.height < outerBottom) { - context.fillRect( - outer.left, innerBottom, outer.width, outerBottom - innerBottom); - } -}; - -/** - * Circle class. - * @param {number} x X coordinate of circle center. - * @param {number} y Y coordinate of circle center. - * @param {number} r Radius. - * @constructor - */ -function Circle(x, y, r) { - this.x = x; - this.y = y; - this.squaredR = r * r; -} - -/** - * Check if the point is inside the circle. - * @param {number} x X coordinate of the point. - * @param {number} y Y coordinate of the point. - * @return {boolean} True if the point is inside. - */ -Circle.prototype.inside = function(x, y) { - x -= this.x; - y -= this.y; - return x * x + y * y <= this.squaredR; -}; - -/** - * Copy an image applying scaling and rotation. - * - * @param {HTMLCanvasElement} dst Destination. - * @param {HTMLCanvasElement|HTMLImageElement} src Source. - * @param {number} scaleX Y scale transformation. - * @param {number} scaleY X scale transformation. - * @param {number} angle (in radians). - */ -ImageUtil.drawImageTransformed = function(dst, src, scaleX, scaleY, angle) { - var context = dst.getContext('2d'); - context.save(); - context.translate(context.canvas.width / 2, context.canvas.height / 2); - context.rotate(angle); - context.scale(scaleX, scaleY); - context.drawImage(src, -src.width / 2, -src.height / 2); - context.restore(); -}; - -/** - * Adds or removes an attribute to/from an HTML element. - * @param {HTMLElement} element To be applied to. - * @param {string} attribute Name of attribute. - * @param {boolean} on True if add, false if remove. - */ -ImageUtil.setAttribute = function(element, attribute, on) { - if (on) - element.setAttribute(attribute, ''); - else - element.removeAttribute(attribute); -}; - -/** - * Adds or removes CSS class to/from an HTML element. - * @param {HTMLElement} element To be applied to. - * @param {string} className Name of CSS class. - * @param {boolean} on True if add, false if remove. - */ -ImageUtil.setClass = function(element, className, on) { - var cl = element.classList; - if (on) - cl.add(className); - else - cl.remove(className); -}; - -/** - * ImageLoader loads an image from a given Entry into a canvas in two steps: - * 1. Loads the image into an HTMLImageElement. - * 2. Copies pixels from HTMLImageElement to HTMLCanvasElement. This is done - * stripe-by-stripe to avoid freezing up the UI. The transform is taken into - * account. - * - * @param {HTMLDocument} document Owner document. - * @param {MetadataCache=} opt_metadataCache Metadata cache. Required for - * caching. If not passed, caching will be disabled. - * @constructor - */ -ImageUtil.ImageLoader = function(document, opt_metadataCache) { - this.document_ = document; - this.metadataCache_ = opt_metadataCache || null; - this.image_ = new Image(); - this.generation_ = 0; -}; - -/** - * Max size of image to be displayed (in pixels) - */ -ImageUtil.ImageLoader.IMAGE_SIZE_LIMIT = 25 * 1000 * 1000; - -/** - * @param {number} width Width of the image. - * @param {number} height Height of the image. - * @return {boolean} True if the image is too large to be loaded. - */ -ImageUtil.ImageLoader.isTooLarge = function(width, height) { - return width * height > ImageUtil.ImageLoader.IMAGE_SIZE_LIMIT; -}; - -/** - * Loads an image. - * TODO(mtomasz): Simplify, or even get rid of this class and merge with the - * ThumbnaiLoader class. - * - * @param {FileEntry} entry Image entry to be loaded. - * @param {function(function(object))} transformFetcher function to get - * the image transform (which we need for the image orientation). - * @param {function(HTMLCanvasElement, string=)} callback Callback to be - * called when loaded. The second optional argument is an error identifier. - * @param {number=} opt_delay Load delay in milliseconds, useful to let the - * animations play out before the computation heavy image loading starts. - */ -ImageUtil.ImageLoader.prototype.load = function( - entry, transformFetcher, callback, opt_delay) { - this.cancel(); - - this.entry_ = entry; - this.callback_ = callback; - - // The transform fetcher is not cancellable so we need a generation counter. - var generation = ++this.generation_; - var onTransform = function(image, transform) { - if (generation === this.generation_) { - this.convertImage_( - image, transform || { scaleX: 1, scaleY: 1, rotate90: 0}); - } - }; - - var onError = function(opt_error) { - this.image_.onerror = null; - this.image_.onload = null; - var tmpCallback = this.callback_; - this.callback_ = null; - var emptyCanvas = this.document_.createElement('canvas'); - emptyCanvas.width = 0; - emptyCanvas.height = 0; - tmpCallback(emptyCanvas, opt_error); - }.bind(this); - - var loadImage = function(opt_metadata) { - ImageUtil.metrics.startInterval(ImageUtil.getMetricName('LoadTime')); - this.timeout_ = null; - - this.image_.onload = function(e) { - this.image_.onerror = null; - this.image_.onload = null; - if (ImageUtil.ImageLoader.isTooLarge(this.image_.width, - this.image_.height)) { - onError('GALLERY_IMAGE_TOO_BIG_ERROR'); - return; - } - transformFetcher(entry, onTransform.bind(this, e.target)); - }.bind(this); - - // The error callback has an optional error argument, which in case of a - // general error should not be specified - this.image_.onerror = onError.bind(this, 'GALLERY_IMAGE_ERROR'); - - // Extract the last modification date to determine if the cached image - // is outdated. - var modificationTime = opt_metadata && - opt_metadata.modificationTime && - opt_metadata.modificationTime.getTime(); - - // Load the image directly. - this.image_.src = entry.toURL(); - }.bind(this); - - // Loads the image. If already loaded, then forces a reload. - var startLoad = this.resetImage_.bind(this, function() { - // Fetch metadata to detect last modification time for the caching purpose. - if (this.metadataCache_) - this.metadataCache_.get(entry, 'filesystem', loadImage); - else - loadImage(); - }.bind(this), onError); - - if (opt_delay) { - this.timeout_ = setTimeout(startLoad, opt_delay); - } else { - startLoad(); - } -}; - -/** - * Resets the image by forcing the garbage collection and clearing the src - * attribute. - * - * @param {function()} onSuccess Success callback. - * @param {function(opt_string)} onError Failure callback with an optional - * error identifier. - * @private - */ -ImageUtil.ImageLoader.prototype.resetImage_ = function(onSuccess, onError) { - var clearSrc = function() { - this.image_.onload = onSuccess; - this.image_.onerror = onSuccess; - this.image_.src = ''; - }.bind(this); - - var emptyImage = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAA' + - 'AAABAAEAAAICTAEAOw=='; - - if (this.image_.src !== emptyImage) { - // Load an empty image, then clear src. - this.image_.onload = clearSrc; - this.image_.onerror = onError.bind(this, 'GALLERY_IMAGE_ERROR'); - this.image_.src = emptyImage; - } else { - // Empty image already loaded, so clear src immediately. - clearSrc(); - } -}; - -/** - * @return {boolean} True if an image is loading. - */ -ImageUtil.ImageLoader.prototype.isBusy = function() { - return !!this.callback_; -}; - -/** - * @param {Entry} entry Image entry. - * @return {boolean} True if loader loads this image. - */ -ImageUtil.ImageLoader.prototype.isLoading = function(entry) { - return this.isBusy() && util.isSameEntry(this.entry_, entry); -}; - -/** - * @param {function} callback To be called when the image loaded. - */ -ImageUtil.ImageLoader.prototype.setCallback = function(callback) { - this.callback_ = callback; -}; - -/** - * Stops loading image. - */ -ImageUtil.ImageLoader.prototype.cancel = function() { - if (!this.callback_) return; - this.callback_ = null; - if (this.timeout_) { - clearTimeout(this.timeout_); - this.timeout_ = null; - } - if (this.image_) { - this.image_.onload = function() {}; - this.image_.onerror = function() {}; - this.image_.src = ''; - } - this.generation_++; // Silence the transform fetcher if it is in progress. -}; - -/** - * @param {HTMLImageElement} image Image to be transformed. - * @param {Object} transform transformation description to apply to the image. - * @private - */ -ImageUtil.ImageLoader.prototype.convertImage_ = function(image, transform) { - var canvas = this.document_.createElement('canvas'); - - if (transform.rotate90 & 1) { // Rotated +/-90deg, swap the dimensions. - canvas.width = image.height; - canvas.height = image.width; - } else { - canvas.width = image.width; - canvas.height = image.height; - } - - var context = canvas.getContext('2d'); - context.save(); - context.translate(canvas.width / 2, canvas.height / 2); - context.rotate(transform.rotate90 * Math.PI / 2); - context.scale(transform.scaleX, transform.scaleY); - - var stripCount = Math.ceil(image.width * image.height / (1 << 21)); - var step = Math.max(16, Math.ceil(image.height / stripCount)) & 0xFFFFF0; - - this.copyStrip_(context, image, 0, step); -}; - -/** - * @param {CanvasRenderingContext2D} context Context to draw. - * @param {HTMLImageElement} image Image to draw. - * @param {number} firstRow Number of the first pixel row to draw. - * @param {number} rowCount Count of pixel rows to draw. - * @private - */ -ImageUtil.ImageLoader.prototype.copyStrip_ = function( - context, image, firstRow, rowCount) { - var lastRow = Math.min(firstRow + rowCount, image.height); - - context.drawImage( - image, 0, firstRow, image.width, lastRow - firstRow, - -image.width / 2, firstRow - image.height / 2, - image.width, lastRow - firstRow); - - if (lastRow === image.height) { - context.restore(); - if (this.entry_.toURL().substr(0, 5) !== 'data:') { // Ignore data urls. - ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('LoadTime')); - } - try { - setTimeout(this.callback_, 0, context.canvas); - } catch (e) { - console.error(e); - } - this.callback_ = null; - } else { - var self = this; - this.timeout_ = setTimeout( - function() { - self.timeout_ = null; - self.copyStrip_(context, image, lastRow, rowCount); - }, 0); - } -}; - -/** - * @param {HTMLElement} element To remove children from. - */ -ImageUtil.removeChildren = function(element) { - element.textContent = ''; -}; - -/** - * @param {string} name File name (with extension). - * @return {string} File name without extension. - */ -ImageUtil.getDisplayNameFromName = function(name) { - var index = name.lastIndexOf('.'); - if (index !== -1) - return name.substr(0, index); - else - return name; -}; - -/** - * @param {string} name File name. - * @return {string} File extension. - */ -ImageUtil.getExtensionFromFullName = function(name) { - var index = name.lastIndexOf('.'); - if (index !== -1) - return name.substring(index); - else - return ''; -}; - -/** - * Metrics (from metrics.js) itnitialized by the File Manager from owner frame. - * @type {Object?} - */ -ImageUtil.metrics = null; - -/** - * @param {string} name Local name. - * @return {string} Full name. - */ -ImageUtil.getMetricName = function(name) { - return 'PhotoEditor.' + name; -}; - -/** - * Used for metrics reporting, keep in sync with the histogram description. - */ -ImageUtil.FILE_TYPES = ['jpg', 'png', 'gif', 'bmp', 'webp']; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_view.js b/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_view.js deleted file mode 100644 index 24d70045798..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/image_view.js +++ /dev/null @@ -1,1065 +0,0 @@ -// 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. - -'use strict'; - -/** - * The overlay displaying the image. - * - * @param {HTMLElement} container The container element. - * @param {Viewport} viewport The viewport. - * @param {MetadataCache} metadataCache The metadataCache. - * @constructor - */ -function ImageView(container, viewport, metadataCache) { - this.container_ = container; - this.viewport_ = viewport; - this.document_ = container.ownerDocument; - this.contentGeneration_ = 0; - this.displayedContentGeneration_ = 0; - this.displayedViewportGeneration_ = 0; - - this.imageLoader_ = new ImageUtil.ImageLoader(this.document_, metadataCache); - // We have a separate image loader for prefetch which does not get cancelled - // when the selection changes. - this.prefetchLoader_ = new ImageUtil.ImageLoader( - this.document_, metadataCache); - - // The content cache is used for prefetching the next image when going - // through the images sequentially. The real life photos can be large - // (18Mpix = 72Mb pixel array) so we want only the minimum amount of caching. - this.contentCache_ = new ImageView.Cache(2); - - // We reuse previously generated screen-scale images so that going back to - // a recently loaded image looks instant even if the image is not in - // the content cache any more. Screen-scale images are small (~1Mpix) - // so we can afford to cache more of them. - this.screenCache_ = new ImageView.Cache(5); - this.contentCallbacks_ = []; - - /** - * The element displaying the current content. - * - * @type {HTMLCanvasElement|HTMLVideoElement} - * @private - */ - this.screenImage_ = null; - - this.localImageTransformFetcher_ = function(entry, callback) { - metadataCache.get(entry, 'fetchedMedia', function(fetchedMedia) { - callback(fetchedMedia.imageTransform); - }); - }; -} - -/** - * Duration of transition between modes in ms. - */ -ImageView.MODE_TRANSITION_DURATION = 350; - -/** - * If the user flips though images faster than this interval we do not apply - * the slide-in/slide-out transition. - */ -ImageView.FAST_SCROLL_INTERVAL = 300; - -/** - * Image load type: full resolution image loaded from cache. - */ -ImageView.LOAD_TYPE_CACHED_FULL = 0; - -/** - * Image load type: screen resolution preview loaded from cache. - */ -ImageView.LOAD_TYPE_CACHED_SCREEN = 1; - -/** - * Image load type: image read from file. - */ -ImageView.LOAD_TYPE_IMAGE_FILE = 2; - -/** - * Image load type: video loaded. - */ -ImageView.LOAD_TYPE_VIDEO_FILE = 3; - -/** - * Image load type: error occurred. - */ -ImageView.LOAD_TYPE_ERROR = 4; - -/** - * Image load type: the file contents is not available offline. - */ -ImageView.LOAD_TYPE_OFFLINE = 5; - -/** - * The total number of load types. - */ -ImageView.LOAD_TYPE_TOTAL = 6; - -ImageView.prototype = {__proto__: ImageBuffer.Overlay.prototype}; - -/** - * Draws below overlays with the default zIndex. - * @return {number} Z-index. - */ -ImageView.prototype.getZIndex = function() { return -1 }; - -/** - * Draws the image on screen. - */ -ImageView.prototype.draw = function() { - if (!this.contentCanvas_) // Do nothing if the image content is not set. - return; - - var forceRepaint = false; - - if (this.displayedViewportGeneration_ !== - this.viewport_.getCacheGeneration()) { - this.displayedViewportGeneration_ = this.viewport_.getCacheGeneration(); - - this.setupDeviceBuffer(this.screenImage_); - - forceRepaint = true; - } - - if (forceRepaint || - this.displayedContentGeneration_ !== this.contentGeneration_) { - this.displayedContentGeneration_ = this.contentGeneration_; - - ImageUtil.trace.resetTimer('paint'); - this.paintDeviceRect(this.viewport_.getDeviceClipped(), - this.contentCanvas_, this.viewport_.getImageClipped()); - ImageUtil.trace.reportTimer('paint'); - } -}; - -/** - * @param {number} x X pointer position. - * @param {number} y Y pointer position. - * @param {boolean} mouseDown True if mouse is down. - * @return {string} CSS cursor style. - */ -ImageView.prototype.getCursorStyle = function(x, y, mouseDown) { - // Indicate that the image is draggable. - if (this.viewport_.isClipped() && - this.viewport_.getScreenClipped().inside(x, y)) - return 'move'; - - return null; -}; - -/** - * @param {number} x X pointer position. - * @param {number} y Y pointer position. - * @return {function} The closure to call on drag. - */ -ImageView.prototype.getDragHandler = function(x, y) { - var cursor = this.getCursorStyle(x, y); - if (cursor === 'move') { - // Return the handler that drags the entire image. - return this.viewport_.createOffsetSetter(x, y); - } - - return null; -}; - -/** - * @return {number} The cache generation. - */ -ImageView.prototype.getCacheGeneration = function() { - return this.contentGeneration_; -}; - -/** - * Invalidates the caches to force redrawing the screen canvas. - */ -ImageView.prototype.invalidateCaches = function() { - this.contentGeneration_++; -}; - -/** - * @return {HTMLCanvasElement} The content canvas element. - */ -ImageView.prototype.getCanvas = function() { return this.contentCanvas_ }; - -/** - * @return {boolean} True if the a valid image is currently loaded. - */ -ImageView.prototype.hasValidImage = function() { - return !this.preview_ && this.contentCanvas_ && this.contentCanvas_.width; -}; - -/** - * @return {HTMLVideoElement} The video element. - */ -ImageView.prototype.getVideo = function() { return this.videoElement_ }; - -/** - * @return {HTMLCanvasElement} The cached thumbnail image. - */ -ImageView.prototype.getThumbnail = function() { return this.thumbnailCanvas_ }; - -/** - * @return {number} The content revision number. - */ -ImageView.prototype.getContentRevision = function() { - return this.contentRevision_; -}; - -/** - * Copies an image fragment from a full resolution canvas to a device resolution - * canvas. - * - * @param {Rect} deviceRect Rectangle in the device coordinates. - * @param {HTMLCanvasElement} canvas Full resolution canvas. - * @param {Rect} imageRect Rectangle in the full resolution canvas. - */ -ImageView.prototype.paintDeviceRect = function(deviceRect, canvas, imageRect) { - // Map screen canvas (0,0) to (deviceBounds.left, deviceBounds.top) - var deviceBounds = this.viewport_.getDeviceClipped(); - deviceRect = deviceRect.shift(-deviceBounds.left, -deviceBounds.top); - - // The source canvas may have different physical size than the image size - // set at the viewport. Adjust imageRect accordingly. - var bounds = this.viewport_.getImageBounds(); - var scaleX = canvas.width / bounds.width; - var scaleY = canvas.height / bounds.height; - imageRect = new Rect(imageRect.left * scaleX, imageRect.top * scaleY, - imageRect.width * scaleX, imageRect.height * scaleY); - Rect.drawImage( - this.screenImage_.getContext('2d'), canvas, deviceRect, imageRect); -}; - -/** - * Creates an overlay canvas with properties similar to the screen canvas. - * Useful for showing quick feedback when editing. - * - * @return {HTMLCanvasElement} Overlay canvas. - */ -ImageView.prototype.createOverlayCanvas = function() { - var canvas = this.document_.createElement('canvas'); - canvas.className = 'image'; - this.container_.appendChild(canvas); - return canvas; -}; - -/** - * Sets up the canvas as a buffer in the device resolution. - * - * @param {HTMLCanvasElement} canvas The buffer canvas. - */ -ImageView.prototype.setupDeviceBuffer = function(canvas) { - var deviceRect = this.viewport_.getDeviceClipped(); - - // Set the canvas position and size in device pixels. - if (canvas.width !== deviceRect.width) - canvas.width = deviceRect.width; - - if (canvas.height !== deviceRect.height) - canvas.height = deviceRect.height; - - canvas.style.left = deviceRect.left + 'px'; - canvas.style.top = deviceRect.top + 'px'; - - // Scale the canvas down to screen pixels. - this.setTransform(canvas); -}; - -/** - * @return {ImageData} A new ImageData object with a copy of the content. - */ -ImageView.prototype.copyScreenImageData = function() { - return this.screenImage_.getContext('2d').getImageData( - 0, 0, this.screenImage_.width, this.screenImage_.height); -}; - -/** - * @return {boolean} True if the image is currently being loaded. - */ -ImageView.prototype.isLoading = function() { - return this.imageLoader_.isBusy(); -}; - -/** - * Cancels the current image loading operation. The callbacks will be ignored. - */ -ImageView.prototype.cancelLoad = function() { - this.imageLoader_.cancel(); -}; - -/** - * Loads and display a new image. - * - * Loads the thumbnail first, then replaces it with the main image. - * Takes into account the image orientation encoded in the metadata. - * - * @param {FileEntry} entry Image entry. - * @param {Object} metadata Metadata. - * @param {Object} effect Transition effect object. - * @param {function(number} displayCallback Called when the image is displayed - * (possibly as a prevew). - * @param {function(number} loadCallback Called when the image is fully loaded. - * The parameter is the load type. - */ -ImageView.prototype.load = function(entry, metadata, effect, - displayCallback, loadCallback) { - if (effect) { - // Skip effects when reloading repeatedly very quickly. - var time = Date.now(); - if (this.lastLoadTime_ && - (time - this.lastLoadTime_) < ImageView.FAST_SCROLL_INTERVAL) { - effect = null; - } - this.lastLoadTime_ = time; - } - - metadata = metadata || {}; - - ImageUtil.metrics.startInterval(ImageUtil.getMetricName('DisplayTime')); - - var self = this; - - this.contentEntry_ = entry; - this.contentRevision_ = -1; - - var loadingVideo = FileType.getMediaType(entry) === 'video'; - if (loadingVideo) { - var video = this.document_.createElement('video'); - var videoPreview = !!(metadata.thumbnail && metadata.thumbnail.url); - if (videoPreview) { - var thumbnailLoader = new ThumbnailLoader( - metadata.thumbnail.url, - ThumbnailLoader.LoaderType.CANVAS, - metadata); - thumbnailLoader.loadDetachedImage(function(success) { - if (success) { - var canvas = thumbnailLoader.getImage(); - video.setAttribute('poster', canvas.toDataURL('image/jpeg')); - this.replace(video, effect); // Show the poster immediately. - if (displayCallback) displayCallback(); - } - }.bind(this)); - } - - var onVideoLoad = function(error) { - video.removeEventListener('loadedmetadata', onVideoLoadSuccess); - video.removeEventListener('error', onVideoLoadError); - displayMainImage(ImageView.LOAD_TYPE_VIDEO_FILE, videoPreview, video, - error); - }; - var onVideoLoadError = onVideoLoad.bind(this, 'GALLERY_VIDEO_ERROR'); - var onVideoLoadSuccess = onVideoLoad.bind(this, null); - - video.addEventListener('loadedmetadata', onVideoLoadSuccess); - video.addEventListener('error', onVideoLoadError); - - video.src = entry.toURL(); - video.load(); - return; - } - - // Cache has to be evicted in advance, so the returned cached image is not - // evicted later by the prefetched image. - this.contentCache_.evictLRU(); - - var cached = this.contentCache_.getItem(this.contentEntry_); - if (cached) { - displayMainImage(ImageView.LOAD_TYPE_CACHED_FULL, - false /* no preview */, cached); - } else { - var cachedScreen = this.screenCache_.getItem(this.contentEntry_); - var imageWidth = metadata.media && metadata.media.width || - metadata.drive && metadata.drive.imageWidth; - var imageHeight = metadata.media && metadata.media.height || - metadata.drive && metadata.drive.imageHeight; - if (cachedScreen) { - // We have a cached screen-scale canvas, use it instead of a thumbnail. - displayThumbnail(ImageView.LOAD_TYPE_CACHED_SCREEN, cachedScreen); - // As far as the user can tell the image is loaded. We still need to load - // the full res image to make editing possible, but we can report now. - ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('DisplayTime')); - } else if ((!effect || (effect.constructor.name === 'Slide')) && - metadata.thumbnail && metadata.thumbnail.url && - !(imageWidth && imageHeight && - ImageUtil.ImageLoader.isTooLarge(imageWidth, imageHeight))) { - // Only show thumbnails if there is no effect or the effect is Slide. - // Also no thumbnail if the image is too large to be loaded. - var thumbnailLoader = new ThumbnailLoader( - metadata.thumbnail.url, - ThumbnailLoader.LoaderType.CANVAS, - metadata); - thumbnailLoader.loadDetachedImage(function(success) { - displayThumbnail(ImageView.LOAD_TYPE_IMAGE_FILE, - success ? thumbnailLoader.getImage() : null); - }); - } else { - loadMainImage(ImageView.LOAD_TYPE_IMAGE_FILE, entry, - false /* no preview*/, 0 /* delay */); - } - } - - function displayThumbnail(loadType, canvas) { - if (canvas) { - self.replace( - canvas, - effect, - metadata.media.width || metadata.drive.imageWidth, - metadata.media.height || metadata.drive.imageHeight, - true /* preview */); - if (displayCallback) displayCallback(); - } - loadMainImage(loadType, entry, !!canvas, - (effect && canvas) ? effect.getSafeInterval() : 0); - } - - function loadMainImage(loadType, contentEntry, previewShown, delay) { - if (self.prefetchLoader_.isLoading(contentEntry)) { - // The image we need is already being prefetched. Initiating another load - // would be a waste. Hijack the load instead by overriding the callback. - self.prefetchLoader_.setCallback( - displayMainImage.bind(null, loadType, previewShown)); - - // Swap the loaders so that the self.isLoading works correctly. - var temp = self.prefetchLoader_; - self.prefetchLoader_ = self.imageLoader_; - self.imageLoader_ = temp; - return; - } - self.prefetchLoader_.cancel(); // The prefetch was doing something useless. - - self.imageLoader_.load( - contentEntry, - self.localImageTransformFetcher_, - displayMainImage.bind(null, loadType, previewShown), - delay); - } - - function displayMainImage(loadType, previewShown, content, opt_error) { - if (opt_error) - loadType = ImageView.LOAD_TYPE_ERROR; - - // If we already displayed the preview we should not replace the content if: - // 1. The full content failed to load. - // or - // 2. We are loading a video (because the full video is displayed in the - // same HTML element as the preview). - var animationDuration = 0; - if (!(previewShown && - (loadType === ImageView.LOAD_TYPE_ERROR || - loadType === ImageView.LOAD_TYPE_VIDEO_FILE))) { - var replaceEffect = previewShown ? null : effect; - animationDuration = replaceEffect ? replaceEffect.getSafeInterval() : 0; - self.replace(content, replaceEffect); - if (!previewShown && displayCallback) displayCallback(); - } - - if (loadType !== ImageView.LOAD_TYPE_ERROR && - loadType !== ImageView.LOAD_TYPE_CACHED_SCREEN) { - ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('DisplayTime')); - } - ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('LoadMode'), - loadType, ImageView.LOAD_TYPE_TOTAL); - - if (loadType === ImageView.LOAD_TYPE_ERROR && - !navigator.onLine && metadata.streaming) { - // |streaming| is set only when the file is not locally cached. - loadType = ImageView.LOAD_TYPE_OFFLINE; - } - if (loadCallback) loadCallback(loadType, animationDuration, opt_error); - } -}; - -/** - * Prefetches an image. - * @param {FileEntry} entry The image entry. - * @param {number} delay Image load delay in ms. - */ -ImageView.prototype.prefetch = function(entry, delay) { - var self = this; - function prefetchDone(canvas) { - if (canvas.width) - self.contentCache_.putItem(entry, canvas); - } - - var cached = this.contentCache_.getItem(entry); - if (cached) { - prefetchDone(cached); - } else if (FileType.getMediaType(entry) === 'image') { - // Evict the LRU item before we allocate the new canvas to avoid unneeded - // strain on memory. - this.contentCache_.evictLRU(); - - this.prefetchLoader_.load( - entry, - this.localImageTransformFetcher_, - prefetchDone, - delay); - } -}; - -/** - * Renames the current image. - * @param {FileEntry} newEntry The new image Entry. - */ -ImageView.prototype.changeEntry = function(newEntry) { - this.contentCache_.renameItem(this.contentEntry_, newEntry); - this.screenCache_.renameItem(this.contentEntry_, newEntry); - this.contentEntry_ = newEntry; -}; - -/** - * Unloads content. - * @param {Rect} zoomToRect Target rectangle for zoom-out-effect. - */ -ImageView.prototype.unload = function(zoomToRect) { - if (this.unloadTimer_) { - clearTimeout(this.unloadTimer_); - this.unloadTimer_ = null; - } - if (zoomToRect && this.screenImage_) { - var effect = this.createZoomEffect(zoomToRect); - this.setTransform(this.screenImage_, effect); - this.screenImage_.setAttribute('fade', true); - this.unloadTimer_ = setTimeout(function() { - this.unloadTimer_ = null; - this.unload(null /* force unload */); - }.bind(this), - effect.getSafeInterval()); - return; - } - this.container_.textContent = ''; - this.contentCanvas_ = null; - this.screenImage_ = null; - this.videoElement_ = null; -}; - -/** - * @param {HTMLCanvasElement|HTMLVideoElement} content The image element. - * @param {number=} opt_width Image width. - * @param {number=} opt_height Image height. - * @param {boolean=} opt_preview True if the image is a preview (not full res). - * @private - */ -ImageView.prototype.replaceContent_ = function( - content, opt_width, opt_height, opt_preview) { - - if (this.contentCanvas_ && this.contentCanvas_.parentNode === this.container_) - this.container_.removeChild(this.contentCanvas_); - - if (content.constructor.name === 'HTMLVideoElement') { - this.contentCanvas_ = null; - this.videoElement_ = content; - this.screenImage_ = content; - this.screenImage_.className = 'image'; - this.container_.appendChild(this.screenImage_); - this.videoElement_.play(); - return; - } - - this.screenImage_ = this.document_.createElement('canvas'); - this.screenImage_.className = 'image'; - - this.videoElement_ = null; - this.contentCanvas_ = content; - this.invalidateCaches(); - this.viewport_.setImageSize( - opt_width || this.contentCanvas_.width, - opt_height || this.contentCanvas_.height); - this.viewport_.fitImage(); - this.viewport_.update(); - this.draw(); - - this.container_.appendChild(this.screenImage_); - - this.preview_ = opt_preview; - // If this is not a thumbnail, cache the content and the screen-scale image. - if (this.hasValidImage()) { - // Insert the full resolution canvas into DOM so that it can be printed. - this.container_.appendChild(this.contentCanvas_); - this.contentCanvas_.classList.add('fullres'); - - this.contentCache_.putItem(this.contentEntry_, this.contentCanvas_, true); - this.screenCache_.putItem(this.contentEntry_, this.screenImage_); - - // TODO(kaznacheev): It is better to pass screenImage_ as it is usually - // much smaller than contentCanvas_ and still contains the entire image. - // Once we implement zoom/pan we should pass contentCanvas_ instead. - this.updateThumbnail_(this.screenImage_); - - this.contentRevision_++; - for (var i = 0; i !== this.contentCallbacks_.length; i++) { - try { - this.contentCallbacks_[i](); - } catch (e) { - console.error(e); - } - } - } -}; - -/** - * Adds a listener for content changes. - * @param {function} callback Callback. - */ -ImageView.prototype.addContentCallback = function(callback) { - this.contentCallbacks_.push(callback); -}; - -/** - * Updates the cached thumbnail image. - * - * @param {HTMLCanvasElement} canvas The source canvas. - * @private - */ -ImageView.prototype.updateThumbnail_ = function(canvas) { - ImageUtil.trace.resetTimer('thumb'); - var pixelCount = 10000; - var downScale = - Math.max(1, Math.sqrt(canvas.width * canvas.height / pixelCount)); - - this.thumbnailCanvas_ = canvas.ownerDocument.createElement('canvas'); - this.thumbnailCanvas_.width = Math.round(canvas.width / downScale); - this.thumbnailCanvas_.height = Math.round(canvas.height / downScale); - Rect.drawImage(this.thumbnailCanvas_.getContext('2d'), canvas); - ImageUtil.trace.reportTimer('thumb'); -}; - -/** - * Replaces the displayed image, possibly with slide-in animation. - * - * @param {HTMLCanvasElement|HTMLVideoElement} content The image element. - * @param {Object=} opt_effect Transition effect object. - * @param {number=} opt_width Image width. - * @param {number=} opt_height Image height. - * @param {boolean=} opt_preview True if the image is a preview (not full res). - */ -ImageView.prototype.replace = function( - content, opt_effect, opt_width, opt_height, opt_preview) { - var oldScreenImage = this.screenImage_; - - this.replaceContent_(content, opt_width, opt_height, opt_preview); - if (!opt_effect) { - if (oldScreenImage) - oldScreenImage.parentNode.removeChild(oldScreenImage); - return; - } - - var newScreenImage = this.screenImage_; - - if (oldScreenImage) - ImageUtil.setAttribute(newScreenImage, 'fade', true); - this.setTransform(newScreenImage, opt_effect, 0 /* instant */); - - setTimeout(function() { - this.setTransform(newScreenImage, null, - opt_effect && opt_effect.getDuration()); - if (oldScreenImage) { - ImageUtil.setAttribute(newScreenImage, 'fade', false); - ImageUtil.setAttribute(oldScreenImage, 'fade', true); - console.assert(opt_effect.getReverse, 'Cannot revert an effect.'); - var reverse = opt_effect.getReverse(); - this.setTransform(oldScreenImage, reverse); - setTimeout(function() { - if (oldScreenImage.parentNode) - oldScreenImage.parentNode.removeChild(oldScreenImage); - }, reverse.getSafeInterval()); - } - }.bind(this), 0); -}; - -/** - * @param {HTMLCanvasElement|HTMLVideoElement} element The element to transform. - * @param {ImageView.Effect=} opt_effect The effect to apply. - * @param {number=} opt_duration Transition duration. - */ -ImageView.prototype.setTransform = function(element, opt_effect, opt_duration) { - if (!opt_effect) - opt_effect = new ImageView.Effect.None(); - if (typeof opt_duration !== 'number') - opt_duration = opt_effect.getDuration(); - element.style.webkitTransitionDuration = opt_duration + 'ms'; - element.style.webkitTransitionTimingFunction = opt_effect.getTiming(); - element.style.webkitTransform = opt_effect.transform(element, this.viewport_); -}; - -/** - * @param {Rect} screenRect Target rectangle in screen coordinates. - * @return {ImageView.Effect.Zoom} Zoom effect object. - */ -ImageView.prototype.createZoomEffect = function(screenRect) { - return new ImageView.Effect.Zoom( - this.viewport_.screenToDeviceRect(screenRect), - null /* use viewport */, - ImageView.MODE_TRANSITION_DURATION); -}; - -/** - * Visualizes crop or rotate operation. Hide the old image instantly, animate - * the new image to visualize the operation. - * - * @param {HTMLCanvasElement} canvas New content canvas. - * @param {Rect} imageCropRect The crop rectangle in image coordinates. - * Null for rotation operations. - * @param {number} rotate90 Rotation angle in 90 degree increments. - * @return {number} Animation duration. - */ -ImageView.prototype.replaceAndAnimate = function( - canvas, imageCropRect, rotate90) { - var oldScale = this.viewport_.getScale(); - var deviceCropRect = imageCropRect && this.viewport_.screenToDeviceRect( - this.viewport_.imageToScreenRect(imageCropRect)); - - var oldScreenImage = this.screenImage_; - this.replaceContent_(canvas); - var newScreenImage = this.screenImage_; - - // Display the new canvas, initially transformed. - var deviceFullRect = this.viewport_.getDeviceClipped(); - - var effect = rotate90 ? - new ImageView.Effect.Rotate( - oldScale / this.viewport_.getScale(), -rotate90) : - new ImageView.Effect.Zoom(deviceCropRect, deviceFullRect); - - this.setTransform(newScreenImage, effect, 0 /* instant */); - - oldScreenImage.parentNode.appendChild(newScreenImage); - oldScreenImage.parentNode.removeChild(oldScreenImage); - - // Let the layout fire, then animate back to non-transformed state. - setTimeout( - this.setTransform.bind( - this, newScreenImage, null, effect.getDuration()), - 0); - - return effect.getSafeInterval(); -}; - -/** - * Visualizes "undo crop". Shrink the current image to the given crop rectangle - * while fading in the new image. - * - * @param {HTMLCanvasElement} canvas New content canvas. - * @param {Rect} imageCropRect The crop rectangle in image coordinates. - * @return {number} Animation duration. - */ -ImageView.prototype.animateAndReplace = function(canvas, imageCropRect) { - var deviceFullRect = this.viewport_.getDeviceClipped(); - var oldScale = this.viewport_.getScale(); - - var oldScreenImage = this.screenImage_; - this.replaceContent_(canvas); - var newScreenImage = this.screenImage_; - - var deviceCropRect = this.viewport_.screenToDeviceRect( - this.viewport_.imageToScreenRect(imageCropRect)); - - var setFade = ImageUtil.setAttribute.bind(null, newScreenImage, 'fade'); - setFade(true); - oldScreenImage.parentNode.insertBefore(newScreenImage, oldScreenImage); - - var effect = new ImageView.Effect.Zoom(deviceCropRect, deviceFullRect); - // Animate to the transformed state. - this.setTransform(oldScreenImage, effect); - - setTimeout(setFade.bind(null, false), 0); - - setTimeout(function() { - if (oldScreenImage.parentNode) - oldScreenImage.parentNode.removeChild(oldScreenImage); - }, effect.getSafeInterval()); - - return effect.getSafeInterval(); -}; - - -/** - * Generic cache with a limited capacity and LRU eviction. - * @param {number} capacity Maximum number of cached item. - * @constructor - */ -ImageView.Cache = function(capacity) { - this.capacity_ = capacity; - this.map_ = {}; - this.order_ = []; -}; - -/** - * Fetches the item from the cache. - * @param {FileEntry} entry The entry. - * @return {Object} The cached item. - */ -ImageView.Cache.prototype.getItem = function(entry) { - return this.map_[entry.toURL()]; -}; - -/** - * Puts the item into the cache. - * - * @param {FileEntry} entry The entry. - * @param {Object} item The item object. - * @param {boolean=} opt_keepLRU True if the LRU order should not be modified. - */ -ImageView.Cache.prototype.putItem = function(entry, item, opt_keepLRU) { - var pos = this.order_.indexOf(entry.toURL()); - - if ((pos >= 0) !== (entry.toURL() in this.map_)) - throw new Error('Inconsistent cache state'); - - if (entry.toURL() in this.map_) { - if (!opt_keepLRU) { - // Move to the end (most recently used). - this.order_.splice(pos, 1); - this.order_.push(entry.toURL()); - } - } else { - this.evictLRU(); - this.order_.push(entry.toURL()); - } - - if ((pos >= 0) && (item !== this.map_[entry.toURL()])) - this.deleteItem_(this.map_[entry.toURL()]); - this.map_[entry.toURL()] = item; - - if (this.order_.length > this.capacity_) - throw new Error('Exceeded cache capacity'); -}; - -/** - * Evicts the least recently used items. - */ -ImageView.Cache.prototype.evictLRU = function() { - if (this.order_.length === this.capacity_) { - var url = this.order_.shift(); - this.deleteItem_(this.map_[url]); - delete this.map_[url]; - } -}; - -/** - * Changes the Entry. - * @param {FileEntry} oldEntry The old Entry. - * @param {FileEntry} newEntry The new Entry. - */ -ImageView.Cache.prototype.renameItem = function(oldEntry, newEntry) { - if (util.isSameEntry(oldEntry, newEntry)) - return; // No need to rename. - - var pos = this.order_.indexOf(oldEntry.toURL()); - if (pos < 0) - return; // Not cached. - - this.order_[pos] = newEntry.toURL(); - this.map_[newEntry.toURL()] = this.map_[oldEntry.toURL()]; - delete this.map_[oldEntry.toURL()]; -}; - -/** - * Disposes an object. - * - * @param {Object} item The item object. - * @private - */ -ImageView.Cache.prototype.deleteItem_ = function(item) { - // Trick to reduce memory usage without waiting for gc. - if (item instanceof HTMLCanvasElement) { - // If the canvas is being used somewhere else (eg. displayed on the screen), - // it will be cleared. - item.width = 0; - item.height = 0; - } -}; - -/* Transition effects */ - -/** - * Base class for effects. - * - * @param {number} duration Duration in ms. - * @param {string=} opt_timing CSS transition timing function name. - * @constructor - */ -ImageView.Effect = function(duration, opt_timing) { - this.duration_ = duration; - this.timing_ = opt_timing || 'linear'; -}; - -/** - * - */ -ImageView.Effect.DEFAULT_DURATION = 180; - -/** - * - */ -ImageView.Effect.MARGIN = 100; - -/** - * @return {number} Effect duration in ms. - */ -ImageView.Effect.prototype.getDuration = function() { return this.duration_ }; - -/** - * @return {number} Delay in ms since the beginning of the animation after which - * it is safe to perform CPU-heavy operations without disrupting the animation. - */ -ImageView.Effect.prototype.getSafeInterval = function() { - return this.getDuration() + ImageView.Effect.MARGIN; -}; - -/** - * @return {string} CSS transition timing function name. - */ -ImageView.Effect.prototype.getTiming = function() { return this.timing_ }; - -/** - * @param {HTMLCanvasElement|HTMLVideoElement} element Element. - * @return {number} Preferred pixel ration to use with this element. - * @private - */ -ImageView.Effect.getPixelRatio_ = function(element) { - if (element.constructor.name === 'HTMLCanvasElement') - return Viewport.getDevicePixelRatio(); - else - return 1; -}; - -/** - * Default effect. It is not a no-op as it needs to adjust a canvas scale - * for devicePixelRatio. - * - * @constructor - */ -ImageView.Effect.None = function() { - ImageView.Effect.call(this, 0); -}; - -/** - * Inherits from ImageView.Effect. - */ -ImageView.Effect.None.prototype = { __proto__: ImageView.Effect.prototype }; - -/** - * @param {HTMLCanvasElement|HTMLVideoElement} element Element. - * @return {string} Transform string. - */ -ImageView.Effect.None.prototype.transform = function(element) { - var ratio = ImageView.Effect.getPixelRatio_(element); - return 'scale(' + (1 / ratio) + ')'; -}; - -/** - * Slide effect. - * - * @param {number} direction -1 for left, 1 for right. - * @param {boolean=} opt_slow True if slow (as in slideshow). - * @constructor - */ -ImageView.Effect.Slide = function Slide(direction, opt_slow) { - ImageView.Effect.call(this, - opt_slow ? 800 : ImageView.Effect.DEFAULT_DURATION, 'ease-in-out'); - this.direction_ = direction; - this.slow_ = opt_slow; - this.shift_ = opt_slow ? 100 : 40; - if (this.direction_ < 0) this.shift_ = -this.shift_; -}; - -/** - * Inherits from ImageView.Effect. - */ -ImageView.Effect.Slide.prototype = { __proto__: ImageView.Effect.prototype }; - -/** - * @return {ImageView.Effect.Slide} Reverse Slide effect. - */ -ImageView.Effect.Slide.prototype.getReverse = function() { - return new ImageView.Effect.Slide(-this.direction_, this.slow_); -}; - -/** - * @param {HTMLCanvasElement|HTMLVideoElement} element Element. - * @return {string} Transform string. - */ -ImageView.Effect.Slide.prototype.transform = function(element) { - var ratio = ImageView.Effect.getPixelRatio_(element); - return 'scale(' + (1 / ratio) + ') translate(' + this.shift_ + 'px, 0px)'; -}; - -/** - * Zoom effect. - * - * Animates the original rectangle to the target rectangle. Both parameters - * should be given in device coordinates (accounting for devicePixelRatio). - * - * @param {Rect} deviceTargetRect Target rectangle. - * @param {Rect=} opt_deviceOriginalRect Original rectangle. If omitted, - * the full viewport will be used at the time of |transform| call. - * @param {number=} opt_duration Duration in ms. - * @constructor - */ -ImageView.Effect.Zoom = function( - deviceTargetRect, opt_deviceOriginalRect, opt_duration) { - ImageView.Effect.call(this, - opt_duration || ImageView.Effect.DEFAULT_DURATION); - this.target_ = deviceTargetRect; - this.original_ = opt_deviceOriginalRect; -}; - -/** - * Inherits from ImageView.Effect. - */ -ImageView.Effect.Zoom.prototype = { __proto__: ImageView.Effect.prototype }; - -/** - * @param {HTMLCanvasElement|HTMLVideoElement} element Element. - * @param {Viewport} viewport Viewport. - * @return {string} Transform string. - */ -ImageView.Effect.Zoom.prototype.transform = function(element, viewport) { - if (!this.original_) - this.original_ = viewport.getDeviceClipped(); - - var ratio = ImageView.Effect.getPixelRatio_(element); - - var dx = (this.target_.left + this.target_.width / 2) - - (this.original_.left + this.original_.width / 2); - var dy = (this.target_.top + this.target_.height / 2) - - (this.original_.top + this.original_.height / 2); - - var scaleX = this.target_.width / this.original_.width; - var scaleY = this.target_.height / this.original_.height; - - return 'translate(' + (dx / ratio) + 'px,' + (dy / ratio) + 'px) ' + - 'scaleX(' + (scaleX / ratio) + ') scaleY(' + (scaleY / ratio) + ')'; -}; - -/** - * Rotate effect. - * - * @param {number} scale Scale. - * @param {number} rotate90 Rotation in 90 degrees increments. - * @constructor - */ -ImageView.Effect.Rotate = function(scale, rotate90) { - ImageView.Effect.call(this, ImageView.Effect.DEFAULT_DURATION); - this.scale_ = scale; - this.rotate90_ = rotate90; -}; - -/** - * Inherits from ImageView.Effect. - */ -ImageView.Effect.Rotate.prototype = { __proto__: ImageView.Effect.prototype }; - -/** - * @param {HTMLCanvasElement|HTMLVideoElement} element Element. - * @return {string} Transform string. - */ -ImageView.Effect.Rotate.prototype.transform = function(element) { - var ratio = ImageView.Effect.getPixelRatio_(element); - return 'rotate(' + (this.rotate90_ * 90) + 'deg) ' + - 'scale(' + (this.scale_ / ratio) + ')'; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/viewport.js b/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/viewport.js deleted file mode 100644 index 4d6b8ea0874..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/image_editor/viewport.js +++ /dev/null @@ -1,430 +0,0 @@ -// 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. - -'use strict'; - -/** - * Viewport class controls the way the image is displayed (scale, offset etc). - * @constructor - */ -function Viewport() { - this.imageBounds_ = new Rect(); - this.screenBounds_ = new Rect(); - - this.scale_ = 1; - this.offsetX_ = 0; - this.offsetY_ = 0; - - this.generation_ = 0; - - this.scaleControl_ = null; - this.repaintCallbacks_ = []; - this.update(); -} - -/* - * Viewport modification. - */ - -/** - * @param {Object} scaleControl The UI object responsible for scaling. - */ -Viewport.prototype.setScaleControl = function(scaleControl) { - this.scaleControl_ = scaleControl; -}; - -/** - * @param {number} width Image width. - * @param {number} height Image height. - */ -Viewport.prototype.setImageSize = function(width, height) { - this.imageBounds_ = new Rect(width, height); - if (this.scaleControl_) this.scaleControl_.displayImageSize(width, height); - this.invalidateCaches(); -}; - -/** - * @param {number} width Screen width. - * @param {number} height Screen height. - */ -Viewport.prototype.setScreenSize = function(width, height) { - this.screenBounds_ = new Rect(width, height); - if (this.scaleControl_) - this.scaleControl_.setMinScale(this.getFittingScale()); - this.invalidateCaches(); -}; - -/** - * Set the size by an HTML element. - * - * @param {HTMLElement} frame The element acting as the "screen". - */ -Viewport.prototype.sizeByFrame = function(frame) { - this.setScreenSize(frame.clientWidth, frame.clientHeight); -}; - -/** - * Set the size and scale to fit an HTML element. - * - * @param {HTMLElement} frame The element acting as the "screen". - */ -Viewport.prototype.sizeByFrameAndFit = function(frame) { - var wasFitting = this.getScale() == this.getFittingScale(); - this.sizeByFrame(frame); - var minScale = this.getFittingScale(); - if (wasFitting || (this.getScale() < minScale)) { - this.setScale(minScale, true); - } -}; - -/** - * @return {number} Scale. - */ -Viewport.prototype.getScale = function() { return this.scale_ }; - -/** - * @param {number} scale The new scale. - * @param {boolean} notify True if the change should be reflected in the UI. - */ -Viewport.prototype.setScale = function(scale, notify) { - if (this.scale_ == scale) return; - this.scale_ = scale; - if (notify && this.scaleControl_) this.scaleControl_.displayScale(scale); - this.invalidateCaches(); -}; - -/** - * @return {number} Best scale to fit the current image into the current screen. - */ -Viewport.prototype.getFittingScale = function() { - var scaleX = this.screenBounds_.width / this.imageBounds_.width; - var scaleY = this.screenBounds_.height / this.imageBounds_.height; - // Scales > (1 / this.getDevicePixelRatio()) do not look good. Also they are - // not really useful as we do not have any pixel-level operations. - return Math.min(1 / Viewport.getDevicePixelRatio(), scaleX, scaleY); -}; - -/** - * Set the scale to fit the image into the screen. - */ -Viewport.prototype.fitImage = function() { - var scale = this.getFittingScale(); - if (this.scaleControl_) this.scaleControl_.setMinScale(scale); - this.setScale(scale, true); -}; - -/** - * @return {number} X-offset of the viewport. - */ -Viewport.prototype.getOffsetX = function() { return this.offsetX_ }; - -/** - * @return {number} Y-offset of the viewport. - */ -Viewport.prototype.getOffsetY = function() { return this.offsetY_ }; - -/** - * Set the image offset in the viewport. - * @param {number} x X-offset. - * @param {number} y Y-offset. - * @param {boolean} ignoreClipping True if no clipping should be applied. - */ -Viewport.prototype.setOffset = function(x, y, ignoreClipping) { - if (!ignoreClipping) { - x = this.clampOffsetX_(x); - y = this.clampOffsetY_(y); - } - if (this.offsetX_ == x && this.offsetY_ == y) return; - this.offsetX_ = x; - this.offsetY_ = y; - this.invalidateCaches(); -}; - -/** - * Return a closure that can be called to pan the image. - * Useful for implementing non-trivial variants of panning (overview etc). - * @param {number} originalX The x coordinate on the screen canvas that - * corresponds to zero change to offsetX. - * @param {number} originalY The y coordinate on the screen canvas that - * corresponds to zero change to offsetY. - * @param {function():number} scaleFunc returns the image to screen scale. - * @param {function(number,number):boolean} hitFunc returns true if (x,y) is - * in the valid region. - * @return {function} The closure to pan the image. - */ -Viewport.prototype.createOffsetSetter = function( - originalX, originalY, scaleFunc, hitFunc) { - var originalOffsetX = this.offsetX_; - var originalOffsetY = this.offsetY_; - if (!hitFunc) hitFunc = function() { return true }; - if (!scaleFunc) scaleFunc = this.getScale.bind(this); - - var self = this; - return function(x, y) { - if (hitFunc(x, y)) { - var scale = scaleFunc(); - self.setOffset( - originalOffsetX + (x - originalX) / scale, - originalOffsetY + (y - originalY) / scale); - self.repaint(); - } - }; -}; - -/* - * Access to the current viewport state. - */ - -/** - * @return {Rect} The image bounds in image coordinates. - */ -Viewport.prototype.getImageBounds = function() { return this.imageBounds_ }; - -/** -* @return {Rect} The screen bounds in screen coordinates. -*/ -Viewport.prototype.getScreenBounds = function() { return this.screenBounds_ }; - -/** - * @return {Rect} The visible part of the image, in image coordinates. - */ -Viewport.prototype.getImageClipped = function() { return this.imageClipped_ }; - -/** - * @return {Rect} The visible part of the image, in screen coordinates. - */ -Viewport.prototype.getScreenClipped = function() { return this.screenClipped_ }; - -/** - * A counter that is incremented with each viewport state change. - * Clients that cache anything that depends on the viewport state should keep - * track of this counter. - * @return {number} counter. - */ -Viewport.prototype.getCacheGeneration = function() { return this.generation_ }; - -/** - * Called on event view port state change (even if repaint has not been called). - */ -Viewport.prototype.invalidateCaches = function() { this.generation_++ }; - -/** - * @return {Rect} The image bounds in screen coordinates. - */ -Viewport.prototype.getImageBoundsOnScreen = function() { - return this.imageOnScreen_; -}; - -/* - * Conversion between the screen and image coordinate spaces. - */ - -/** - * @param {number} size Size in screen coordinates. - * @return {number} Size in image coordinates. - */ -Viewport.prototype.screenToImageSize = function(size) { - return size / this.getScale(); -}; - -/** - * @param {number} x X in screen coordinates. - * @return {number} X in image coordinates. - */ -Viewport.prototype.screenToImageX = function(x) { - return Math.round((x - this.imageOnScreen_.left) / this.getScale()); -}; - -/** - * @param {number} y Y in screen coordinates. - * @return {number} Y in image coordinates. - */ -Viewport.prototype.screenToImageY = function(y) { - return Math.round((y - this.imageOnScreen_.top) / this.getScale()); -}; - -/** - * @param {Rect} rect Rectangle in screen coordinates. - * @return {Rect} Rectangle in image coordinates. - */ -Viewport.prototype.screenToImageRect = function(rect) { - return new Rect( - this.screenToImageX(rect.left), - this.screenToImageY(rect.top), - this.screenToImageSize(rect.width), - this.screenToImageSize(rect.height)); -}; - -/** - * @param {number} size Size in image coordinates. - * @return {number} Size in screen coordinates. - */ -Viewport.prototype.imageToScreenSize = function(size) { - return size * this.getScale(); -}; - -/** - * @param {number} x X in image coordinates. - * @return {number} X in screen coordinates. - */ -Viewport.prototype.imageToScreenX = function(x) { - return Math.round(this.imageOnScreen_.left + x * this.getScale()); -}; - -/** - * @param {number} y Y in image coordinates. - * @return {number} Y in screen coordinates. - */ -Viewport.prototype.imageToScreenY = function(y) { - return Math.round(this.imageOnScreen_.top + y * this.getScale()); -}; - -/** - * @param {Rect} rect Rectangle in image coordinates. - * @return {Rect} Rectangle in screen coordinates. - */ -Viewport.prototype.imageToScreenRect = function(rect) { - return new Rect( - this.imageToScreenX(rect.left), - this.imageToScreenY(rect.top), - Math.round(this.imageToScreenSize(rect.width)), - Math.round(this.imageToScreenSize(rect.height))); -}; - -/** - * @return {number} The number of physical pixels in one CSS pixel. - */ -Viewport.getDevicePixelRatio = function() { return window.devicePixelRatio }; - -/** - * Convert a rectangle from screen coordinates to 'device' coordinates. - * - * This conversion enlarges the original rectangle devicePixelRatio times - * with the screen center as a fixed point. - * - * @param {Rect} rect Rectangle in screen coordinates. - * @return {Rect} Rectangle in device coordinates. - */ -Viewport.prototype.screenToDeviceRect = function(rect) { - var ratio = Viewport.getDevicePixelRatio(); - var screenCenterX = Math.round( - this.screenBounds_.left + this.screenBounds_.width / 2); - var screenCenterY = Math.round( - this.screenBounds_.top + this.screenBounds_.height / 2); - return new Rect(screenCenterX + (rect.left - screenCenterX) * ratio, - screenCenterY + (rect.top - screenCenterY) * ratio, - rect.width * ratio, - rect.height * ratio); -}; - -/** - * @return {Rect} The visible part of the image, in device coordinates. - */ -Viewport.prototype.getDeviceClipped = function() { - return this.screenToDeviceRect(this.getScreenClipped()); -}; - -/** - * @return {boolean} True if some part of the image is clipped by the screen. - */ -Viewport.prototype.isClipped = function() { - return this.getMarginX_() < 0 || this.getMarginY_() < 0; -}; - -/** - * @return {number} Horizontal margin. - * Negative if the image is clipped horizontally. - * @private - */ -Viewport.prototype.getMarginX_ = function() { - return Math.round( - (this.screenBounds_.width - this.imageBounds_.width * this.scale_) / 2); -}; - -/** - * @return {number} Vertical margin. - * Negative if the image is clipped vertically. - * @private - */ -Viewport.prototype.getMarginY_ = function() { - return Math.round( - (this.screenBounds_.height - this.imageBounds_.height * this.scale_) / 2); -}; - -/** - * @param {number} x X-offset. - * @return {number} X-offset clamped to the valid range. - * @private - */ -Viewport.prototype.clampOffsetX_ = function(x) { - var limit = Math.round(Math.max(0, -this.getMarginX_() / this.getScale())); - return ImageUtil.clamp(-limit, x, limit); -}; - -/** - * @param {number} y Y-offset. - * @return {number} Y-offset clamped to the valid range. - * @private - */ -Viewport.prototype.clampOffsetY_ = function(y) { - var limit = Math.round(Math.max(0, -this.getMarginY_() / this.getScale())); - return ImageUtil.clamp(-limit, y, limit); -}; - -/** - * Recalculate the viewport parameters. - */ -Viewport.prototype.update = function() { - var scale = this.getScale(); - - // Image bounds in screen coordinates. - this.imageOnScreen_ = new Rect( - this.getMarginX_(), - this.getMarginY_(), - Math.round(this.imageBounds_.width * scale), - Math.round(this.imageBounds_.height * scale)); - - // A visible part of the image in image coordinates. - this.imageClipped_ = new Rect(this.imageBounds_); - - // A visible part of the image in screen coordinates. - this.screenClipped_ = new Rect(this.screenBounds_); - - // Adjust for the offset. - if (this.imageOnScreen_.left < 0) { - this.imageOnScreen_.left += - Math.round(this.clampOffsetX_(this.offsetX_) * scale); - this.imageClipped_.left = Math.round(-this.imageOnScreen_.left / scale); - this.imageClipped_.width = Math.round(this.screenBounds_.width / scale); - } else { - this.screenClipped_.left = this.imageOnScreen_.left; - this.screenClipped_.width = this.imageOnScreen_.width; - } - - if (this.imageOnScreen_.top < 0) { - this.imageOnScreen_.top += - Math.round(this.clampOffsetY_(this.offsetY_) * scale); - this.imageClipped_.top = Math.round(-this.imageOnScreen_.top / scale); - this.imageClipped_.height = Math.round(this.screenBounds_.height / scale); - } else { - this.screenClipped_.top = this.imageOnScreen_.top; - this.screenClipped_.height = this.imageOnScreen_.height; - } -}; - -/** - * @param {function} callback Repaint callback. - */ -Viewport.prototype.addRepaintCallback = function(callback) { - this.repaintCallbacks_.push(callback); -}; - -/** - * Repaint all clients. - */ -Viewport.prototype.repaint = function() { - this.update(); - for (var i = 0; i != this.repaintCallbacks_.length; i++) - this.repaintCallbacks_[i](); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/main.js b/chromium/chrome/browser/resources/file_manager/foreground/js/main.js deleted file mode 100644 index f32c0a1ef47..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/main.js +++ /dev/null @@ -1,41 +0,0 @@ -// 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. - -'use strict'; - -/** - * @type {FileManager} - */ -var fileManager; - -/** - * Indicates if the DOM and scripts have been already loaded. - * @type {boolean} - */ -var pageLoaded = false; - -/** - * Kick off the file manager dialog. - * Called by main.html after the DOM has been parsed. - */ -function init() { - // Initializes UI and starts the File Manager dialog. - fileManager.initializeUI(document.body, function() { - chrome.test.sendMessage('ready'); - metrics.recordInterval('Load.Total'); - }); -} - -// Create the File Manager object. Note, that the DOM, nor any external -// scripts may not be ready yet. -fileManager = new FileManager(); - -// Initialize the core stuff, which doesn't require access to DOM nor to -// additional scripts. -fileManager.initializeCore(); - -// Final initialization is performed after all scripts and Dom is loaded. -util.addPageLoadHandler(init); - -metrics.recordInterval('Load.Script'); // Must be the last line. diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/main_scripts.js b/chromium/chrome/browser/resources/file_manager/foreground/js/main_scripts.js deleted file mode 100644 index 768d35ce8fd..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/main_scripts.js +++ /dev/null @@ -1,132 +0,0 @@ -// 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. - -// The include directives are put into Javascript-style comments to prevent -// parsing errors in non-flattened mode. The flattener still sees them. -// Note that this makes the flattener to comment out the first line of the -// included file but that's all right since any javascript file should start -// with a copyright comment anyway. - -// If you add a new dependency, you should update build files by rerunning -// gyp. Otherwise, you'll be bitten by a dependency issue like: -// -// 1) You add a new dependency to "whatever.js" -// 2) You make changes in "whatever.js" -// 3) Rebuild "resources.pak" and open Files.app -// 4) You don't see the changes in "whatever.js". Why is that? -// -// Because the dependencies are computed at gyp time, the existing build -// files don't know that "resources.pak" now has a dependency to -// "whatever.js". You should rerun gyp to let the build files know. -// -// //metrics.js initiates load performance tracking -// //so we want to parse it as early as possible. -//<include src="metrics.js"/> -// -//<include src="../../../image_loader/image_loader_client.js"/> -// -//<include src="../../../../../../ui/webui/resources/js/load_time_data.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr.js"/> -//<include src="../../../../../../ui/webui/resources/js/util.js"/> -//<include src="../../../../../../ui/webui/resources/js/i18n_template_no_process.js"/> -// -//<include src="../../../../../../ui/webui/resources/js/event_tracker.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/event_target.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/touch_handler.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/array_data_model.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/dialogs.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_item.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_selection_model.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_single_selection_model.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/list_selection_controller.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/list.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/tree.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/autocomplete_list.js"/> -// -//<include src="../../../../../../ui/webui/resources/js/cr/ui/splitter.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/table/table_splitter.js"/> -// -//<include src="../../../../../../ui/webui/resources/js/cr/ui/table/table_column.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/table/table_column_model.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/table/table_header.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/table/table_list.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/table.js"/> -// -//<include src="../../../../../../ui/webui/resources/js/cr/ui/grid.js"/> -// -//<include src="../../../../../../ui/webui/resources/js/cr/ui/command.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/position_util.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/menu_item.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/menu.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/menu_button.js"/> -//<include src="../../../../../../ui/webui/resources/js/cr/ui/context_menu_handler.js"/> - -(function() { -// 'strict mode' is invoked for this scope. - -// // This script must be loaded before all other Files.app's scripts. -//<include src="error_counter.js"/> -// -//<include src="../../common/js/async_util.js"/> -//<include src="../../common/js/path_util.js"/> -//<include src="../../common/js/util.js"/> -//<include src="../../common/js/progress_center_common.js"> -// -//<include src="combobutton.js"/> -//<include src="commandbutton.js"/> -//<include src="ui/file_manager_dialog_base.js"/> -// -//<include src="app_installer.js"/> -//<include src="cws_container_client.js"/> -//<include src="directory_contents.js"/> -//<include src="directory_model.js"/> -//<include src="directory_tree.js"/> -//<include src="drag_selector.js"/> -//<include src="drive_banners.js" /> -//<include src="error_dialog.js"/> -//<include src="file_operation_manager_wrapper.js"/> -//<include src="file_grid.js"/> -//<include src="file_manager.js"/> -//<include src="file_selection.js"/> -//<include src="file_table.js"/> -//<include src="file_tasks.js"/> -//<include src="file_transfer_controller.js"/> -//<include src="file_type.js"/> -//<include src="file_watcher.js"/> -//<include src="folder_shortcuts_data_model.js"/> -//<include src="navigation_list_model.js"/> -//<include src="scrollbar.js"/> -//<include src="share_client.js"/> -//<include src="share_dialog.js"/> -//<include src="suggest_apps_dialog.js"/> -//<include src="text_measure.js"/> -//<include src="tree.css.js"/> -//<include src="ui/breadcrumbs_controller.js"/> -//<include src="ui/conflict_dialog.js"/> -//<include src="ui/file_manager_ui.js"/> -//<include src="ui/navigation_list.js"/> -//<include src="ui/preview_panel.js"/> -//<include src="ui/progress_center_panel.js"/> -//<include src="ui/search_box.js"/> -//<include src="volume_manager_wrapper.js"/> -//<include src="media/media_util.js"/> -//<include src="metadata/metadata_cache.js"/> -//<include src="default_action_dialog.js"/> -//<include src="file_manager_commands.js"/> - -// // For accurate load performance tracking place main.js should be -// // the last include to include. -//<include src="main.js"/> - -// Global fileManager reference useful for poking at from the console. -window.fileManager = fileManager; - -// Exports -window.util = util; -window.FileOperationManagerWrapper = FileOperationManagerWrapper; - -window.unload = unload; - -})(); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/media/audio_player.js b/chromium/chrome/browser/resources/file_manager/foreground/js/media/audio_player.js deleted file mode 100644 index 4791c31f92b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/media/audio_player.js +++ /dev/null @@ -1,628 +0,0 @@ -// 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. - -'use strict'; - -/** - * TODO(mtomasz): Rewrite the entire audio player. - * - * @param {HTMLElement} container Container element. - * @constructor - */ -function AudioPlayer(container) { - this.container_ = container; - this.metadataCache_ = MetadataCache.createFull(); - this.currentTrack_ = -1; - this.playlistGeneration_ = 0; - this.selectedEntry_ = null; - this.volumeManager_ = new VolumeManagerWrapper( - VolumeManagerWrapper.DriveEnabledStatus.DRIVE_ENABLED); - - this.container_.classList.add('collapsed'); - - function createChild(opt_className, opt_tag) { - var child = container.ownerDocument.createElement(opt_tag || 'div'); - if (opt_className) - child.className = opt_className; - container.appendChild(child); - return child; - } - - // We create two separate containers (for expanded and compact view) and keep - // two sets of TrackInfo instances. We could fiddle with a single set instead - // but it would make keeping the list scroll position very tricky. - this.trackList_ = createChild('track-list'); - this.trackStack_ = createChild('track-stack'); - - createChild('title-button collapse').addEventListener( - 'click', this.onExpandCollapse_.bind(this)); - - this.audioControls_ = new FullWindowAudioControls( - createChild(), this.advance_.bind(this), this.onError_.bind(this)); - - this.audioControls_.attachMedia(createChild('', 'audio')); - - chrome.fileBrowserPrivate.getStrings(function(strings) { - container.ownerDocument.title = strings['AUDIO_PLAYER_TITLE']; - this.errorString_ = strings['AUDIO_ERROR']; - this.offlineString_ = strings['AUDIO_OFFLINE']; - AudioPlayer.TrackInfo.DEFAULT_ARTIST = - strings['AUDIO_PLAYER_DEFAULT_ARTIST']; - }.bind(this)); - - this.volumeManager_.addEventListener('externally-unmounted', - this.onExternallyUnmounted_.bind(this)); - - window.addEventListener('resize', this.onResize_.bind(this)); - - // Show the window after DOM is processed. - var currentWindow = chrome.app.window.current(); - setTimeout(currentWindow.show.bind(currentWindow), 0); -} - -/** - * Initial load method (static). - */ -AudioPlayer.load = function() { - document.ondragstart = function(e) { e.preventDefault() }; - - // TODO(mtomasz): Consider providing an exact size icon, instead of relying - // on downsampling by ash. - chrome.app.window.current().setIcon( - 'foreground/images/media/2x/audio_player.png'); - - AudioPlayer.instance = - new AudioPlayer(document.querySelector('.audio-player')); - reload(); -}; - -util.addPageLoadHandler(AudioPlayer.load); - -/** - * Unload the player. - */ -function unload() { - if (AudioPlayer.instance) - AudioPlayer.instance.onUnload(); -} - -/** - * Reload the player. - */ -function reload() { - if (window.appState) { - util.saveAppState(); - AudioPlayer.instance.load(window.appState); - return; - } -} - -/** - * Load a new playlist. - * @param {Playlist} playlist Playlist object passed via mediaPlayerPrivate. - */ -AudioPlayer.prototype.load = function(playlist) { - this.playlistGeneration_++; - this.audioControls_.pause(); - this.currentTrack_ = -1; - - // Save the app state, in case of restart. - window.appState = playlist; - util.saveAppState(); - - util.URLsToEntries(playlist.items, function(entries) { - this.entries_ = entries; - this.invalidTracks_ = {}; - this.cancelAutoAdvance_(); - - if (this.entries_.length <= 1) - this.container_.classList.add('single-track'); - else - this.container_.classList.remove('single-track'); - - this.syncHeight_(); - - this.trackList_.textContent = ''; - this.trackStack_.textContent = ''; - - this.trackListItems_ = []; - this.trackStackItems_ = []; - - if (this.entries_.length == 0) - return; - - for (var i = 0; i != this.entries_.length; i++) { - var entry = this.entries_[i]; - var onClick = this.select_.bind(this, i, false /* no restore */); - this.trackListItems_.push( - new AudioPlayer.TrackInfo(this.trackList_, entry, onClick)); - this.trackStackItems_.push( - new AudioPlayer.TrackInfo(this.trackStack_, entry, onClick)); - } - - this.select_(playlist.position, !!playlist.time); - - // This class will be removed if at least one track has art. - this.container_.classList.add('noart'); - - // Load the selected track metadata first, then load the rest. - this.loadMetadata_(playlist.position); - for (i = 0; i != this.entries_.length; i++) { - if (i != playlist.position) - this.loadMetadata_(i); - } - }.bind(this)); -}; - -/** - * Load metadata for a track. - * @param {number} track Track number. - * @private - */ -AudioPlayer.prototype.loadMetadata_ = function(track) { - this.fetchMetadata_( - this.entries_[track], this.displayMetadata_.bind(this, track)); -}; - -/** - * Display track's metadata. - * @param {number} track Track number. - * @param {Object} metadata Metadata object. - * @param {string=} opt_error Error message. - * @private - */ -AudioPlayer.prototype.displayMetadata_ = function(track, metadata, opt_error) { - this.trackListItems_[track]. - setMetadata(metadata, this.container_, opt_error); - this.trackStackItems_[track]. - setMetadata(metadata, this.container_, opt_error); -}; - -/** - * Closes audio player when a volume containing the selected item is unmounted. - * @param {Event} event The unmount event. - * @private - */ -AudioPlayer.prototype.onExternallyUnmounted_ = function(event) { - if (!this.selectedEntry_) - return; - - if (this.volumeManager_.getVolumeInfo(this.selectedEntry_) === - event.volumeInfo) { - window.close(); - } -}; - -/** - * Called on window is being unloaded. - */ -AudioPlayer.prototype.onUnload = function() { - this.audioControls_.cleanup(); - this.volumeManager_.dispose(); -}; - -/** - * Select a new track to play. - * @param {number} newTrack New track number. - * @param {boolean=} opt_restoreState True if restoring the play state from URL. - * @private - */ -AudioPlayer.prototype.select_ = function(newTrack, opt_restoreState) { - if (this.currentTrack_ == newTrack) return; - - this.changeSelectionInList_(this.currentTrack_, newTrack); - this.changeSelectionInStack_(this.currentTrack_, newTrack); - - this.currentTrack_ = newTrack; - - if (window.appState) { - window.appState.position = this.currentTrack_; - window.appState.time = 0; - util.saveAppState(); - } else { - util.platform.setPreference(AudioPlayer.TRACK_KEY, this.currentTrack_); - } - - this.scrollToCurrent_(false); - - var currentTrack = this.currentTrack_; - var entry = this.entries_[currentTrack]; - this.fetchMetadata_(entry, function(metadata) { - if (this.currentTrack_ != currentTrack) - return; - this.audioControls_.load(entry, opt_restoreState); - - // Resolve real filesystem path of the current audio file. - this.selectedEntry_ = entry; - }.bind(this)); -}; - -/** - * @param {Entry} entry Track file entry. - * @param {function(object)} callback Callback. - * @private - */ -AudioPlayer.prototype.fetchMetadata_ = function(entry, callback) { - this.metadataCache_.get(entry, 'thumbnail|media|streaming', - function(generation, metadata) { - // Do nothing if another load happened since the metadata request. - if (this.playlistGeneration_ == generation) - callback(metadata); - }.bind(this, this.playlistGeneration_)); -}; - -/** - * @param {number} oldTrack Old track number. - * @param {number} newTrack New track number. - * @private - */ -AudioPlayer.prototype.changeSelectionInList_ = function(oldTrack, newTrack) { - this.trackListItems_[newTrack].getBox().classList.add('selected'); - - if (oldTrack >= 0) { - this.trackListItems_[oldTrack].getBox().classList.remove('selected'); - } -}; - -/** - * @param {number} oldTrack Old track number. - * @param {number} newTrack New track number. - * @private - */ -AudioPlayer.prototype.changeSelectionInStack_ = function(oldTrack, newTrack) { - var newBox = this.trackStackItems_[newTrack].getBox(); - newBox.classList.add('selected'); // Put on top immediately. - newBox.classList.add('visible'); // Start fading in. - - if (oldTrack >= 0) { - var oldBox = this.trackStackItems_[oldTrack].getBox(); - oldBox.classList.remove('selected'); // Put under immediately. - setTimeout(function() { - if (!oldBox.classList.contains('selected')) { - // This will start fading out which is not really necessary because - // oldBox is already completely obscured by newBox. - oldBox.classList.remove('visible'); - } - }, 300); - } -}; - -/** - * Scrolls the current track into the viewport. - * - * @param {boolean} keepAtBottom If true, make the selected track the last - * of the visible (if possible). If false, perform minimal scrolling. - * @private - */ -AudioPlayer.prototype.scrollToCurrent_ = function(keepAtBottom) { - var box = this.trackListItems_[this.currentTrack_].getBox(); - this.trackList_.scrollTop = Math.max( - keepAtBottom ? 0 : Math.min(box.offsetTop, this.trackList_.scrollTop), - box.offsetTop + box.offsetHeight - this.trackList_.clientHeight); -}; - -/** - * @return {boolean} True if the player is be displayed in compact mode. - * @private - */ -AudioPlayer.prototype.isCompact_ = function() { - return this.container_.classList.contains('collapsed') || - this.container_.classList.contains('single-track'); -}; - -/** - * Go to the previous or the next track. - * @param {boolean} forward True if next, false if previous. - * @param {boolean=} opt_onlyIfValid True if invalid tracks should be selected. - * @private - */ -AudioPlayer.prototype.advance_ = function(forward, opt_onlyIfValid) { - this.cancelAutoAdvance_(); - - var newTrack = this.currentTrack_ + (forward ? 1 : -1); - if (newTrack < 0) newTrack = this.entries_.length - 1; - if (newTrack == this.entries_.length) newTrack = 0; - if (opt_onlyIfValid && this.invalidTracks_[newTrack]) - return; - this.select_(newTrack); -}; - -/** - * Media error handler. - * @private - */ -AudioPlayer.prototype.onError_ = function() { - var track = this.currentTrack_; - - this.invalidTracks_[track] = true; - - this.fetchMetadata_( - this.entries_[track], - function(metadata) { - var error = (!navigator.onLine && metadata.streaming) ? - this.offlineString_ : this.errorString_; - this.displayMetadata_(track, metadata, error); - this.scheduleAutoAdvance_(); - }.bind(this)); -}; - -/** - * Schedule automatic advance to the next track after a timeout. - * @private - */ -AudioPlayer.prototype.scheduleAutoAdvance_ = function() { - this.cancelAutoAdvance_(); - this.autoAdvanceTimer_ = setTimeout( - function() { - this.autoAdvanceTimer_ = null; - // We are advancing only if the next track is not known to be invalid. - // This prevents an endless auto-advancing in the case when all tracks - // are invalid (we will only visit each track once). - this.advance_(true /* forward */, true /* only if valid */); - }.bind(this), - 3000); -}; - -/** - * Cancel the scheduled auto advance. - * @private - */ -AudioPlayer.prototype.cancelAutoAdvance_ = function() { - if (this.autoAdvanceTimer_) { - clearTimeout(this.autoAdvanceTimer_); - this.autoAdvanceTimer_ = null; - } -}; - -/** - * Expand/collapse button click handler. Toggles the mode and updates the - * height of the window. - * - * @private - */ -AudioPlayer.prototype.onExpandCollapse_ = function() { - if (!this.isCompact_()) { - this.setExpanded_(false); - this.lastExpandedHeight_ = window.innerHeight; - } else { - this.setExpanded_(true); - } - this.syncHeight_(); -}; - -/** - * Toggles the current expand mode. - * - * @param {boolean} on True if on, false otherwise. - * @private - */ -AudioPlayer.prototype.setExpanded_ = function(on) { - if (on) { - this.container_.classList.remove('collapsed'); - this.scrollToCurrent_(true); - } else { - this.container_.classList.add('collapsed'); - } -}; - -/** - * Toggles the expanded mode when resizing. - * - * @param {Event} event Resize event. - * @private - */ -AudioPlayer.prototype.onResize_ = function(event) { - if (this.isCompact_() && - window.innerHeight >= AudioPlayer.EXPANDED_MODE_MIN_HEIGHT) { - this.setExpanded_(true); - } else if (!this.isCompact_() && - window.innerHeight < AudioPlayer.EXPANDED_MODE_MIN_HEIGHT) { - this.setExpanded_(false); - } -}; - -/* Keep the below constants in sync with the CSS. */ - -/** - * Window header size in pixels. - * @type {number} - * @const - */ -AudioPlayer.HEADER_HEIGHT = 28; - -/** - * Track height in pixels. - * @type {number} - * @const - */ -AudioPlayer.TRACK_HEIGHT = 58; - -/** - * Controls bar height in pixels. - * @type {number} - * @const - */ -AudioPlayer.CONTROLS_HEIGHT = 35; - -/** - * Default number of items in the expanded mode. - * @type {number} - * @const - */ -AudioPlayer.DEFAULT_EXPANDED_ITEMS = 5; - -/** - * Minimum size of the window in the expanded mode in pixels. - * @type {number} - * @const - */ -AudioPlayer.EXPANDED_MODE_MIN_HEIGHT = AudioPlayer.CONTROLS_HEIGHT + - AudioPlayer.TRACK_HEIGHT * 2; - -/** - * Set the correct player window height. - * @private - */ -AudioPlayer.prototype.syncHeight_ = function() { - var targetHeight; - - if (!this.isCompact_()) { - // Expanded. - if (this.lastExpandedHeight_) { - targetHeight = this.lastExpandedHeight_; - } else { - var expandedListHeight = - Math.min(this.entries_.length, AudioPlayer.DEFAULT_EXPANDED_ITEMS) * - AudioPlayer.TRACK_HEIGHT; - targetHeight = AudioPlayer.CONTROLS_HEIGHT + expandedListHeight; - } - } else { - // Not expaned. - targetHeight = AudioPlayer.CONTROLS_HEIGHT + AudioPlayer.TRACK_HEIGHT; - } - - window.resizeTo(window.innerWidth, targetHeight + AudioPlayer.HEADER_HEIGHT); -}; - -/** - * Create a TrackInfo object encapsulating the information about one track. - * - * @param {HTMLElement} container Container element. - * @param {Entry} entry Track entry. - * @param {function} onClick Click handler. - * @constructor - */ -AudioPlayer.TrackInfo = function(container, entry, onClick) { - this.entry_ = entry; - - var doc = container.ownerDocument; - - this.box_ = doc.createElement('div'); - this.box_.className = 'track'; - this.box_.addEventListener('click', onClick); - container.appendChild(this.box_); - - this.art_ = doc.createElement('div'); - this.art_.className = 'art blank'; - this.box_.appendChild(this.art_); - - this.img_ = doc.createElement('img'); - this.art_.appendChild(this.img_); - - this.data_ = doc.createElement('div'); - this.data_.className = 'data'; - this.box_.appendChild(this.data_); - - this.title_ = doc.createElement('div'); - this.title_.className = 'data-title'; - this.data_.appendChild(this.title_); - - this.artist_ = doc.createElement('div'); - this.artist_.className = 'data-artist'; - this.data_.appendChild(this.artist_); -}; - -/** - * @return {HTMLDivElement} The wrapper element for the track. - */ -AudioPlayer.TrackInfo.prototype.getBox = function() { return this.box_ }; - -/** - * @return {string} Default track title (file name extracted from the entry). - */ -AudioPlayer.TrackInfo.prototype.getDefaultTitle = function() { - // TODO(mtomasz): Reuse ImageUtil.getDisplayNameFromName(). - var name = this.entry_.name; - var dotIndex = name.lastIndexOf('.'); - var title = dotIndex >= 0 ? name.substr(0, dotIndex) : name; - return title; -}; - -/** - * TODO(kaznacheev): Localize. - */ -AudioPlayer.TrackInfo.DEFAULT_ARTIST = 'Unknown Artist'; - -/** - * @return {string} 'Unknown artist' string. - */ -AudioPlayer.TrackInfo.prototype.getDefaultArtist = function() { - return AudioPlayer.TrackInfo.DEFAULT_ARTIST; -}; - -/** - * @param {Object} metadata The metadata object. - * @param {HTMLElement} container The container for the tracks. - * @param {string} error Error string. - */ -AudioPlayer.TrackInfo.prototype.setMetadata = function( - metadata, container, error) { - if (error) { - this.art_.classList.add('blank'); - this.art_.classList.add('error'); - container.classList.remove('noart'); - } else if (metadata.thumbnail && metadata.thumbnail.url) { - this.img_.onload = function() { - // Only display the image if the thumbnail loaded successfully. - this.art_.classList.remove('blank'); - container.classList.remove('noart'); - }.bind(this); - this.img_.src = metadata.thumbnail.url; - } - this.title_.textContent = (metadata.media && metadata.media.title) || - this.getDefaultTitle(); - this.artist_.textContent = error || - (metadata.media && metadata.media.artist) || this.getDefaultArtist(); -}; - -/** - * Audio controls specific for the Audio Player. - * - * @param {HTMLElement} container Parent container. - * @param {function(boolean)} advanceTrack Parameter: true=forward. - * @param {function} onError Error handler. - * @constructor - */ -function FullWindowAudioControls(container, advanceTrack, onError) { - AudioControls.apply(this, arguments); - - document.addEventListener('keydown', function(e) { - if (e.keyIdentifier == 'U+0020') { - this.togglePlayState(); - e.preventDefault(); - } - }.bind(this)); -} - -FullWindowAudioControls.prototype = { __proto__: AudioControls.prototype }; - -/** - * Enable play state restore from the location hash. - * @param {FileEntry} entry Source Entry. - * @param {boolean} restore True if need to restore the play state. - */ -FullWindowAudioControls.prototype.load = function(entry, restore) { - this.media_.src = entry.toURL(); - this.media_.load(); - this.restoreWhenLoaded_ = restore; -}; - -/** - * Save the current state so that it survives page/app reload. - */ -FullWindowAudioControls.prototype.onPlayStateChanged = function() { - this.encodeState(); -}; - -/** - * Restore the state after page/app reload. - */ -FullWindowAudioControls.prototype.restorePlayState = function() { - if (this.restoreWhenLoaded_) { - this.restoreWhenLoaded_ = false; // This should only work once. - if (this.decodeState()) - return; - } - this.play(); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/media/media_controls.js b/chromium/chrome/browser/resources/file_manager/foreground/js/media/media_controls.js deleted file mode 100644 index a335bdc4c52..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/media/media_controls.js +++ /dev/null @@ -1,1245 +0,0 @@ -// 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. - -'use strict'; - -/** - * @fileoverview MediaControls class implements media playback controls - * that exist outside of the audio/video HTML element. - */ - -/** - * @param {HTMLElement} containerElement The container for the controls. - * @param {function} onMediaError Function to display an error message. - * @constructor - */ -function MediaControls(containerElement, onMediaError) { - this.container_ = containerElement; - this.document_ = this.container_.ownerDocument; - this.media_ = null; - - this.onMediaPlayBound_ = this.onMediaPlay_.bind(this, true); - this.onMediaPauseBound_ = this.onMediaPlay_.bind(this, false); - this.onMediaDurationBound_ = this.onMediaDuration_.bind(this); - this.onMediaProgressBound_ = this.onMediaProgress_.bind(this); - this.onMediaError_ = onMediaError || function() {}; -} - -/** - * Button's state types. Values are used as CSS class names. - * @enum {string} - */ -MediaControls.ButtonStateType = { - DEFAULT: 'default', - PLAYING: 'playing', - ENDED: 'ended' -}; - -/** - * @return {HTMLAudioElement|HTMLVideoElement} The media element. - */ -MediaControls.prototype.getMedia = function() { return this.media_ }; - -/** - * Format the time in hh:mm:ss format (omitting redundant leading zeros). - * - * @param {number} timeInSec Time in seconds. - * @return {string} Formatted time string. - * @private - */ -MediaControls.formatTime_ = function(timeInSec) { - var seconds = Math.floor(timeInSec % 60); - var minutes = Math.floor((timeInSec / 60) % 60); - var hours = Math.floor(timeInSec / 60 / 60); - var result = ''; - if (hours) result += hours + ':'; - if (hours && (minutes < 10)) result += '0'; - result += minutes + ':'; - if (seconds < 10) result += '0'; - result += seconds; - return result; -}; - -/** - * Create a custom control. - * - * @param {string} className Class name. - * @param {HTMLElement=} opt_parent Parent element or container if undefined. - * @return {HTMLElement} The new control element. - */ -MediaControls.prototype.createControl = function(className, opt_parent) { - var parent = opt_parent || this.container_; - var control = this.document_.createElement('div'); - control.className = className; - parent.appendChild(control); - return control; -}; - -/** - * Create a custom button. - * - * @param {string} className Class name. - * @param {function(Event)} handler Click handler. - * @param {HTMLElement=} opt_parent Parent element or container if undefined. - * @param {number=} opt_numStates Number of states, default: 1. - * @return {HTMLElement} The new button element. - */ -MediaControls.prototype.createButton = function( - className, handler, opt_parent, opt_numStates) { - opt_numStates = opt_numStates || 1; - - var button = this.createControl(className, opt_parent); - button.classList.add('media-button'); - button.addEventListener('click', handler); - - var stateTypes = Object.keys(MediaControls.ButtonStateType); - for (var state = 0; state != opt_numStates; state++) { - var stateClass = MediaControls.ButtonStateType[stateTypes[state]]; - this.createControl('normal ' + stateClass, button); - this.createControl('hover ' + stateClass, button); - this.createControl('active ' + stateClass, button); - } - this.createControl('disabled', button); - - button.setAttribute('state', MediaControls.ButtonStateType.DEFAULT); - button.addEventListener('click', handler); - return button; -}; - -/** - * Enable/disable controls matching a given selector. - * - * @param {string} selector CSS selector. - * @param {boolean} on True if enable, false if disable. - * @private - */ -MediaControls.prototype.enableControls_ = function(selector, on) { - var controls = this.container_.querySelectorAll(selector); - for (var i = 0; i != controls.length; i++) { - var classList = controls[i].classList; - if (on) - classList.remove('disabled'); - else - classList.add('disabled'); - } -}; - -/* - * Playback control. - */ - -/** - * Play the media. - */ -MediaControls.prototype.play = function() { - this.media_.play(); -}; - -/** - * Pause the media. - */ -MediaControls.prototype.pause = function() { - this.media_.pause(); -}; - -/** - * @return {boolean} True if the media is currently playing. - */ -MediaControls.prototype.isPlaying = function() { - return !this.media_.paused && !this.media_.ended; -}; - -/** - * Toggle play/pause. - */ -MediaControls.prototype.togglePlayState = function() { - if (this.isPlaying()) - this.pause(); - else - this.play(); -}; - -/** - * Toggle play/pause state on a mouse click on the play/pause button. Can be - * called externally. TODO(mtomasz): Remove it. http://www.crbug.com/254318. - * - * @param {Event=} opt_event Mouse click event. - */ -MediaControls.prototype.onPlayButtonClicked = function(opt_event) { - this.togglePlayState(); -}; - -/** - * @param {HTMLElement=} opt_parent Parent container. - */ -MediaControls.prototype.initPlayButton = function(opt_parent) { - this.playButton_ = this.createButton('play media-control', - this.onPlayButtonClicked.bind(this), opt_parent, 3 /* States. */); -}; - -/* - * Time controls - */ - -/** - * The default range of 100 is too coarse for the media progress slider. - */ -MediaControls.PROGRESS_RANGE = 5000; - -/** - * @param {boolean=} opt_seekMark True if the progress slider should have - * a seek mark. - * @param {HTMLElement=} opt_parent Parent container. - */ -MediaControls.prototype.initTimeControls = function(opt_seekMark, opt_parent) { - var timeControls = this.createControl('time-controls', opt_parent); - - var sliderConstructor = - opt_seekMark ? MediaControls.PreciseSlider : MediaControls.Slider; - - this.progressSlider_ = new sliderConstructor( - this.createControl('progress media-control', timeControls), - 0, /* value */ - MediaControls.PROGRESS_RANGE, - this.onProgressChange_.bind(this), - this.onProgressDrag_.bind(this)); - - var timeBox = this.createControl('time media-control', timeControls); - - this.duration_ = this.createControl('duration', timeBox); - // Set the initial width to the minimum to reduce the flicker. - this.duration_.textContent = MediaControls.formatTime_(0); - - this.currentTime_ = this.createControl('current', timeBox); -}; - -/** - * @param {number} current Current time is seconds. - * @param {number} duration Duration in seconds. - * @private - */ -MediaControls.prototype.displayProgress_ = function(current, duration) { - var ratio = current / duration; - this.progressSlider_.setValue(ratio); - this.currentTime_.textContent = MediaControls.formatTime_(current); -}; - -/** - * @param {number} value Progress [0..1]. - * @private - */ -MediaControls.prototype.onProgressChange_ = function(value) { - if (!this.media_.seekable || !this.media_.duration) { - console.error('Inconsistent media state'); - return; - } - - var current = this.media_.duration * value; - this.media_.currentTime = current; - this.currentTime_.textContent = MediaControls.formatTime_(current); -}; - -/** - * @param {boolean} on True if dragging. - * @private - */ -MediaControls.prototype.onProgressDrag_ = function(on) { - if (on) { - this.resumeAfterDrag_ = this.isPlaying(); - this.media_.pause(); - } else { - if (this.resumeAfterDrag_) { - if (this.media_.ended) - this.onMediaPlay_(false); - else - this.media_.play(); - } - this.updatePlayButtonState_(this.isPlaying()); - } -}; - -/* - * Volume controls - */ - -/** - * @param {HTMLElement=} opt_parent Parent element for the controls. - */ -MediaControls.prototype.initVolumeControls = function(opt_parent) { - var volumeControls = this.createControl('volume-controls', opt_parent); - - this.soundButton_ = this.createButton('sound media-control', - this.onSoundButtonClick_.bind(this), volumeControls); - this.soundButton_.setAttribute('level', 3); // max level. - - this.volume_ = new MediaControls.AnimatedSlider( - this.createControl('volume media-control', volumeControls), - 1, /* value */ - 100 /* range */, - this.onVolumeChange_.bind(this), - this.onVolumeDrag_.bind(this)); -}; - -/** - * Click handler for the sound level button. - * @private - */ -MediaControls.prototype.onSoundButtonClick_ = function() { - if (this.media_.volume == 0) { - this.volume_.setValue(this.savedVolume_ || 1); - } else { - this.savedVolume_ = this.media_.volume; - this.volume_.setValue(0); - } - this.onVolumeChange_(this.volume_.getValue()); -}; - -/** - * @param {number} value Volume [0..1]. - * @return {number} The rough level [0..3] used to pick an icon. - * @private - */ -MediaControls.getVolumeLevel_ = function(value) { - if (value == 0) return 0; - if (value <= 1 / 3) return 1; - if (value <= 2 / 3) return 2; - return 3; -}; - -/** - * @param {number} value Volume [0..1]. - * @private - */ -MediaControls.prototype.onVolumeChange_ = function(value) { - this.media_.volume = value; - this.soundButton_.setAttribute('level', MediaControls.getVolumeLevel_(value)); -}; - -/** - * @param {boolean} on True if dragging is in progress. - * @private - */ -MediaControls.prototype.onVolumeDrag_ = function(on) { - if (on && (this.media_.volume != 0)) { - this.savedVolume_ = this.media_.volume; - } -}; - -/* - * Media event handlers. - */ - -/** - * Attach a media element. - * - * @param {HTMLMediaElement} mediaElement The media element to control. - */ -MediaControls.prototype.attachMedia = function(mediaElement) { - this.media_ = mediaElement; - - this.media_.addEventListener('play', this.onMediaPlayBound_); - this.media_.addEventListener('pause', this.onMediaPauseBound_); - this.media_.addEventListener('durationchange', this.onMediaDurationBound_); - this.media_.addEventListener('timeupdate', this.onMediaProgressBound_); - this.media_.addEventListener('error', this.onMediaError_); - - // Reflect the media state in the UI. - this.onMediaDuration_(); - this.onMediaPlay_(this.isPlaying()); - this.onMediaProgress_(); - if (this.volume_) { - /* Copy the user selected volume to the new media element. */ - this.media_.volume = this.volume_.getValue(); - } -}; - -/** - * Detach media event handlers. - */ -MediaControls.prototype.detachMedia = function() { - if (!this.media_) - return; - - this.media_.removeEventListener('play', this.onMediaPlayBound_); - this.media_.removeEventListener('pause', this.onMediaPauseBound_); - this.media_.removeEventListener('durationchange', this.onMediaDurationBound_); - this.media_.removeEventListener('timeupdate', this.onMediaProgressBound_); - this.media_.removeEventListener('error', this.onMediaError_); - - this.media_ = null; -}; - -/** - * Force-empty the media pipeline. This is a workaround for crbug.com/149957. - * The document is not going to be GC-ed until the last Files app window closes, - * but we want the media pipeline to deinitialize ASAP to minimize leakage. - */ -MediaControls.prototype.cleanup = function() { - this.media_.src = ''; - this.media_.load(); - this.detachMedia(); -}; - -/** - * 'play' and 'pause' event handler. - * @param {boolean} playing True if playing. - * @private - */ -MediaControls.prototype.onMediaPlay_ = function(playing) { - if (this.progressSlider_.isDragging()) - return; - - this.updatePlayButtonState_(playing); - this.onPlayStateChanged(); -}; - -/** - * 'durationchange' event handler. - * @private - */ -MediaControls.prototype.onMediaDuration_ = function() { - if (!this.media_.duration) { - this.enableControls_('.media-control', false); - return; - } - - this.enableControls_('.media-control', true); - - var sliderContainer = this.progressSlider_.getContainer(); - if (this.media_.seekable) - sliderContainer.classList.remove('readonly'); - else - sliderContainer.classList.add('readonly'); - - var valueToString = function(value) { - return MediaControls.formatTime_(this.media_.duration * value); - }.bind(this); - - this.duration_.textContent = valueToString(1); - - if (this.progressSlider_.setValueToStringFunction) - this.progressSlider_.setValueToStringFunction(valueToString); - - if (this.media_.seekable) - this.restorePlayState(); -}; - -/** - * 'timeupdate' event handler. - * @private - */ -MediaControls.prototype.onMediaProgress_ = function() { - if (!this.media_.duration) { - this.displayProgress_(0, 1); - return; - } - - var current = this.media_.currentTime; - var duration = this.media_.duration; - - if (this.progressSlider_.isDragging()) - return; - - this.displayProgress_(current, duration); - - if (current == duration) { - this.onMediaComplete(); - } - this.onPlayStateChanged(); -}; - -/** - * Called when the media playback is complete. - */ -MediaControls.prototype.onMediaComplete = function() {}; - -/** - * Called when play/pause state is changed or on playback progress. - * This is the right moment to save the play state. - */ -MediaControls.prototype.onPlayStateChanged = function() {}; - -/** - * Updates the play button state. - * @param {boolean} playing If the video is playing. - * @private - */ -MediaControls.prototype.updatePlayButtonState_ = function(playing) { - if (playing) { - this.playButton_.setAttribute('state', - MediaControls.ButtonStateType.PLAYING); - } else if (!this.media_.ended) { - this.playButton_.setAttribute('state', - MediaControls.ButtonStateType.DEFAULT); - } else { - this.playButton_.setAttribute('state', - MediaControls.ButtonStateType.ENDED); - } -}; - -/** - * Restore play state. Base implementation is empty. - */ -MediaControls.prototype.restorePlayState = function() {}; - -/** - * Encode current state into the page URL or the app state. - */ -MediaControls.prototype.encodeState = function() { - if (!this.media_.duration) - return; - - if (window.appState) { - window.appState.time = this.media_.currentTime; - util.saveAppState(); - return; - } - - var playState = JSON.stringify({ - play: this.isPlaying(), - time: this.media_.currentTime - }); - - var newLocation = document.location.origin + document.location.pathname + - document.location.search + '#' + playState; - - document.location.href = newLocation; -}; - -/** - * Decode current state from the page URL or the app state. - * @return {boolean} True if decode succeeded. - */ -MediaControls.prototype.decodeState = function() { - if (window.appState) { - if (!('time' in window.appState)) - return false; - // There is no page reload for apps v2, only app restart. - // Always restart in paused state. - this.media_.currentTime = appState.time; - this.pause(); - return true; - } - - var hash = document.location.hash.substring(1); - if (hash) { - try { - var playState = JSON.parse(hash); - if (!('time' in playState)) - return false; - - this.media_.currentTime = playState.time; - - if (playState.play) - this.play(); - else - this.pause(); - - return true; - } catch (e) { - console.warn('Cannot decode play state'); - } - } - return false; -}; - -/** - * Remove current state from the page URL or the app state. - */ -MediaControls.prototype.clearState = function() { - if (window.appState) { - if ('time' in window.appState) - delete window.appState.time; - util.saveAppState(); - return; - } - - var newLocation = document.location.origin + document.location.pathname + - document.location.search + '#'; - - document.location.href = newLocation; -}; - -/** - * Create a customized slider control. - * - * @param {HTMLElement} container The containing div element. - * @param {number} value Initial value [0..1]. - * @param {number} range Number of distinct slider positions to be supported. - * @param {function(number)} onChange Value change handler. - * @param {function(boolean)} onDrag Drag begin/end handler. - * @constructor - */ - -MediaControls.Slider = function(container, value, range, onChange, onDrag) { - this.container_ = container; - this.onChange_ = onChange; - this.onDrag_ = onDrag; - - var document = this.container_.ownerDocument; - - this.container_.classList.add('custom-slider'); - - this.input_ = document.createElement('input'); - this.input_.type = 'range'; - this.input_.min = 0; - this.input_.max = range; - this.input_.value = value * range; - this.container_.appendChild(this.input_); - - this.input_.addEventListener( - 'change', this.onInputChange_.bind(this)); - this.input_.addEventListener( - 'mousedown', this.onInputDrag_.bind(this, true)); - this.input_.addEventListener( - 'mouseup', this.onInputDrag_.bind(this, false)); - - this.bar_ = document.createElement('div'); - this.bar_.className = 'bar'; - this.container_.appendChild(this.bar_); - - this.filled_ = document.createElement('div'); - this.filled_.className = 'filled'; - this.bar_.appendChild(this.filled_); - - var leftCap = document.createElement('div'); - leftCap.className = 'cap left'; - this.bar_.appendChild(leftCap); - - var rightCap = document.createElement('div'); - rightCap.className = 'cap right'; - this.bar_.appendChild(rightCap); - - this.value_ = value; - this.setFilled_(value); -}; - -/** - * @return {HTMLElement} The container element. - */ -MediaControls.Slider.prototype.getContainer = function() { - return this.container_; -}; - -/** - * @return {HTMLElement} The standard input element. - * @private - */ -MediaControls.Slider.prototype.getInput_ = function() { - return this.input_; -}; - -/** - * @return {HTMLElement} The slider bar element. - */ -MediaControls.Slider.prototype.getBar = function() { - return this.bar_; -}; - -/** - * @return {number} [0..1] The current value. - */ -MediaControls.Slider.prototype.getValue = function() { - return this.value_; -}; - -/** - * @param {number} value [0..1]. - */ -MediaControls.Slider.prototype.setValue = function(value) { - this.value_ = value; - this.setValueToUI_(value); -}; - -/** - * Fill the given proportion the slider bar (from the left). - * - * @param {number} proportion [0..1]. - * @private - */ -MediaControls.Slider.prototype.setFilled_ = function(proportion) { - this.filled_.style.width = proportion * 100 + '%'; -}; - -/** - * Get the value from the input element. - * - * @return {number} Value [0..1]. - * @private - */ -MediaControls.Slider.prototype.getValueFromUI_ = function() { - return this.input_.value / this.input_.max; -}; - -/** - * Update the UI with the current value. - * - * @param {number} value [0..1]. - * @private - */ -MediaControls.Slider.prototype.setValueToUI_ = function(value) { - this.input_.value = value * this.input_.max; - this.setFilled_(value); -}; - -/** - * Compute the proportion in which the given position divides the slider bar. - * - * @param {number} position in pixels. - * @return {number} [0..1] proportion. - */ -MediaControls.Slider.prototype.getProportion = function(position) { - var rect = this.bar_.getBoundingClientRect(); - return Math.max(0, Math.min(1, (position - rect.left) / rect.width)); -}; - -/** - * 'change' event handler. - * @private - */ -MediaControls.Slider.prototype.onInputChange_ = function() { - this.value_ = this.getValueFromUI_(); - this.setFilled_(this.value_); - this.onChange_(this.value_); -}; - -/** - * @return {boolean} True if dragging is in progress. - */ -MediaControls.Slider.prototype.isDragging = function() { - return this.isDragging_; -}; - -/** - * Mousedown/mouseup handler. - * @param {boolean} on True if the mouse is down. - * @private - */ -MediaControls.Slider.prototype.onInputDrag_ = function(on) { - this.isDragging_ = on; - this.onDrag_(on); -}; - -/** - * Create a customized slider with animated thumb movement. - * - * @param {HTMLElement} container The containing div element. - * @param {number} value Initial value [0..1]. - * @param {number} range Number of distinct slider positions to be supported. - * @param {function(number)} onChange Value change handler. - * @param {function(boolean)} onDrag Drag begin/end handler. - * @param {function(number):string} formatFunction Value formatting function. - * @constructor - */ -MediaControls.AnimatedSlider = function( - container, value, range, onChange, onDrag, formatFunction) { - MediaControls.Slider.apply(this, arguments); -}; - -MediaControls.AnimatedSlider.prototype = { - __proto__: MediaControls.Slider.prototype -}; - -/** - * Number of animation steps. - */ -MediaControls.AnimatedSlider.STEPS = 10; - -/** - * Animation duration. - */ -MediaControls.AnimatedSlider.DURATION = 100; - -/** - * @param {number} value [0..1]. - * @private - */ -MediaControls.AnimatedSlider.prototype.setValueToUI_ = function(value) { - if (this.animationInterval_) { - clearInterval(this.animationInterval_); - } - var oldValue = this.getValueFromUI_(); - var step = 0; - this.animationInterval_ = setInterval(function() { - step++; - var currentValue = oldValue + - (value - oldValue) * (step / MediaControls.AnimatedSlider.STEPS); - MediaControls.Slider.prototype.setValueToUI_.call(this, currentValue); - if (step == MediaControls.AnimatedSlider.STEPS) { - clearInterval(this.animationInterval_); - } - }.bind(this), - MediaControls.AnimatedSlider.DURATION / MediaControls.AnimatedSlider.STEPS); -}; - -/** - * Create a customized slider with a precise time feedback. - * - * The time value is shown above the slider bar at the mouse position. - * - * @param {HTMLElement} container The containing div element. - * @param {number} value Initial value [0..1]. - * @param {number} range Number of distinct slider positions to be supported. - * @param {function(number)} onChange Value change handler. - * @param {function(boolean)} onDrag Drag begin/end handler. - * @param {function(number):string} formatFunction Value formatting function. - * @constructor - */ -MediaControls.PreciseSlider = function( - container, value, range, onChange, onDrag, formatFunction) { - MediaControls.Slider.apply(this, arguments); - - var doc = this.container_.ownerDocument; - - /** - * @type {function(number):string} - * @private - */ - this.valueToString_ = null; - - this.seekMark_ = doc.createElement('div'); - this.seekMark_.className = 'seek-mark'; - this.getBar().appendChild(this.seekMark_); - - this.seekLabel_ = doc.createElement('div'); - this.seekLabel_.className = 'seek-label'; - this.seekMark_.appendChild(this.seekLabel_); - - this.getContainer().addEventListener( - 'mousemove', this.onMouseMove_.bind(this)); - this.getContainer().addEventListener( - 'mouseout', this.onMouseOut_.bind(this)); -}; - -MediaControls.PreciseSlider.prototype = { - __proto__: MediaControls.Slider.prototype -}; - -/** - * Show the seek mark after a delay. - */ -MediaControls.PreciseSlider.SHOW_DELAY = 200; - -/** - * Hide the seek mark for this long after changing the position with a click. - */ -MediaControls.PreciseSlider.HIDE_AFTER_MOVE_DELAY = 2500; - -/** - * Hide the seek mark for this long after changing the position with a drag. - */ -MediaControls.PreciseSlider.HIDE_AFTER_DRAG_DELAY = 750; - -/** - * Default hide timeout (no hiding). - */ -MediaControls.PreciseSlider.NO_AUTO_HIDE = 0; - -/** - * @param {function(number):string} func Value formatting function. - */ -MediaControls.PreciseSlider.prototype.setValueToStringFunction = - function(func) { - this.valueToString_ = func; - - /* It is not completely accurate to assume that the max value corresponds - to the longest string, but generous CSS padding will compensate for that. */ - var labelWidth = this.valueToString_(1).length / 2 + 1; - this.seekLabel_.style.width = labelWidth + 'em'; - this.seekLabel_.style.marginLeft = -labelWidth / 2 + 'em'; -}; - -/** - * Show the time above the slider. - * - * @param {number} ratio [0..1] The proportion of the duration. - * @param {number} timeout Timeout in ms after which the label should be hidden. - * MediaControls.PreciseSlider.NO_AUTO_HIDE means show until the next call. - * @private - */ -MediaControls.PreciseSlider.prototype.showSeekMark_ = - function(ratio, timeout) { - // Do not update the seek mark for the first 500ms after the drag is finished. - if (this.latestMouseUpTime_ && (this.latestMouseUpTime_ + 500 > Date.now())) - return; - - this.seekMark_.style.left = ratio * 100 + '%'; - - if (ratio < this.getValue()) { - this.seekMark_.classList.remove('inverted'); - } else { - this.seekMark_.classList.add('inverted'); - } - this.seekLabel_.textContent = this.valueToString_(ratio); - - this.seekMark_.classList.add('visible'); - - if (this.seekMarkTimer_) { - clearTimeout(this.seekMarkTimer_); - this.seekMarkTimer_ = null; - } - if (timeout != MediaControls.PreciseSlider.NO_AUTO_HIDE) { - this.seekMarkTimer_ = setTimeout(this.hideSeekMark_.bind(this), timeout); - } -}; - -/** - * @private - */ -MediaControls.PreciseSlider.prototype.hideSeekMark_ = function() { - this.seekMarkTimer_ = null; - this.seekMark_.classList.remove('visible'); -}; - -/** - * 'mouseout' event handler. - * @param {Event} e Event. - * @private - */ -MediaControls.PreciseSlider.prototype.onMouseMove_ = function(e) { - this.latestSeekRatio_ = this.getProportion(e.clientX); - - var self = this; - function showMark() { - if (!self.isDragging()) { - self.showSeekMark_(self.latestSeekRatio_, - MediaControls.PreciseSlider.HIDE_AFTER_MOVE_DELAY); - } - } - - if (this.seekMark_.classList.contains('visible')) { - showMark(); - } else if (!this.seekMarkTimer_) { - this.seekMarkTimer_ = - setTimeout(showMark, MediaControls.PreciseSlider.SHOW_DELAY); - } -}; - -/** - * 'mouseout' event handler. - * @param {Event} e Event. - * @private - */ -MediaControls.PreciseSlider.prototype.onMouseOut_ = function(e) { - for (var element = e.relatedTarget; element; element = element.parentNode) { - if (element == this.getContainer()) - return; - } - if (this.seekMarkTimer_) { - clearTimeout(this.seekMarkTimer_); - this.seekMarkTimer_ = null; - } - this.hideSeekMark_(); -}; - -/** - * 'change' event handler. - * @private - */ -MediaControls.PreciseSlider.prototype.onInputChange_ = function() { - MediaControls.Slider.prototype.onInputChange_.apply(this, arguments); - if (this.isDragging()) { - this.showSeekMark_( - this.getValue(), MediaControls.PreciseSlider.NO_AUTO_HIDE); - } -}; - -/** - * Mousedown/mouseup handler. - * @param {boolean} on True if the mouse is down. - * @private - */ -MediaControls.PreciseSlider.prototype.onInputDrag_ = function(on) { - MediaControls.Slider.prototype.onInputDrag_.apply(this, arguments); - - if (on) { - // Dragging started, align the seek mark with the thumb position. - this.showSeekMark_( - this.getValue(), MediaControls.PreciseSlider.NO_AUTO_HIDE); - } else { - // Just finished dragging. - // Show the label for the last time with a shorter timeout. - this.showSeekMark_( - this.getValue(), MediaControls.PreciseSlider.HIDE_AFTER_DRAG_DELAY); - this.latestMouseUpTime_ = Date.now(); - } -}; - -/** - * Create video controls. - * - * @param {HTMLElement} containerElement The container for the controls. - * @param {function} onMediaError Function to display an error message. - * @param {function(string):string} stringFunction Function providing localized - * strings. - * @param {function=} opt_fullScreenToggle Function to toggle fullscreen mode. - * @param {HTMLElement=} opt_stateIconParent The parent for the icon that - * gives visual feedback when the playback state changes. - * @constructor - */ -function VideoControls(containerElement, onMediaError, stringFunction, - opt_fullScreenToggle, opt_stateIconParent) { - MediaControls.call(this, containerElement, onMediaError); - this.stringFunction_ = stringFunction; - - this.container_.classList.add('video-controls'); - this.initPlayButton(); - this.initTimeControls(true /* show seek mark */); - this.initVolumeControls(); - - if (opt_fullScreenToggle) { - this.fullscreenButton_ = - this.createButton('fullscreen', opt_fullScreenToggle); - } - - if (opt_stateIconParent) { - this.stateIcon_ = this.createControl( - 'playback-state-icon', opt_stateIconParent); - this.textBanner_ = this.createControl('text-banner', opt_stateIconParent); - } - - var videoControls = this; - chrome.mediaPlayerPrivate.onTogglePlayState.addListener( - function() { videoControls.togglePlayStateWithFeedback(); }); -} - -/** - * No resume if we are within this margin from the start or the end. - */ -VideoControls.RESUME_MARGIN = 0.03; - -/** - * No resume for videos shorter than this. - */ -VideoControls.RESUME_THRESHOLD = 5 * 60; // 5 min. - -/** - * When resuming rewind back this much. - */ -VideoControls.RESUME_REWIND = 5; // seconds. - -VideoControls.prototype = { __proto__: MediaControls.prototype }; - -/** - * Shows icon feedback for the current state of the video player. - * @private - */ -VideoControls.prototype.showIconFeedback_ = function() { - this.stateIcon_.removeAttribute('state'); - setTimeout(function() { - this.stateIcon_.setAttribute('state', this.isPlaying() ? 'play' : 'pause'); - }.bind(this), 0); -}; - -/** - * Shows a text banner. - * - * @param {string} identifier String identifier. - * @private - */ -VideoControls.prototype.showTextBanner_ = function(identifier) { - this.textBanner_.removeAttribute('visible'); - this.textBanner_.textContent = this.stringFunction_(identifier); - setTimeout(function() { - this.textBanner_.setAttribute('visible', 'true'); - }.bind(this), 0); -}; - -/** - * Toggle play/pause state on a mouse click on the play/pause button. Can be - * called externally. - * - * @param {Event} event Mouse click event. - */ -VideoControls.prototype.onPlayButtonClicked = function(event) { - if (event.ctrlKey) { - this.toggleLoopedModeWithFeedback(true); - if (!this.isPlaying()) - this.togglePlayState(); - } else { - this.togglePlayState(); - } -}; - -/** - * Media completion handler. - */ -VideoControls.prototype.onMediaComplete = function() { - this.onMediaPlay_(false); // Just update the UI. - this.savePosition(); // This will effectively forget the position. -}; - -/** - * Toggles the looped mode with feedback. - * @param {boolean} on Whether enabled or not. - */ -VideoControls.prototype.toggleLoopedModeWithFeedback = function(on) { - if (!this.getMedia().duration) - return; - this.toggleLoopedMode(on); - if (on) { - // TODO(mtomasz): Simplify, crbug.com/254318. - this.showTextBanner_('GALLERY_VIDEO_LOOPED_MODE'); - } -}; - -/** - * Toggles the looped mode. - * @param {boolean} on Whether enabled or not. - */ -VideoControls.prototype.toggleLoopedMode = function(on) { - this.getMedia().loop = on; -}; - -/** - * Toggles play/pause state and flash an icon over the video. - */ -VideoControls.prototype.togglePlayStateWithFeedback = function() { - if (!this.getMedia().duration) - return; - - this.togglePlayState(); - this.showIconFeedback_(); -}; - -/** - * Toggles play/pause state. - */ -VideoControls.prototype.togglePlayState = function() { - if (this.isPlaying()) { - // User gave the Pause command. Save the state and reset the loop mode. - this.toggleLoopedMode(false); - this.savePosition(); - } - MediaControls.prototype.togglePlayState.apply(this, arguments); -}; - -/** - * Saves the playback position to the persistent storage. - * @param {boolean=} opt_sync True if the position must be saved synchronously - * (required when closing app windows). - */ -VideoControls.prototype.savePosition = function(opt_sync) { - if (!this.media_.duration || - this.media_.duration < VideoControls.RESUME_THRESHOLD) { - return; - } - - var ratio = this.media_.currentTime / this.media_.duration; - var position; - if (ratio < VideoControls.RESUME_MARGIN || - ratio > (1 - VideoControls.RESUME_MARGIN)) { - // We are too close to the beginning or the end. - // Remove the resume position so that next time we start from the beginning. - position = null; - } else { - position = Math.floor( - Math.max(0, this.media_.currentTime - VideoControls.RESUME_REWIND)); - } - - if (opt_sync) { - // Packaged apps cannot save synchronously. - // Pass the data to the background page. - if (!window.saveOnExit) - window.saveOnExit = []; - window.saveOnExit.push({ key: this.media_.src, value: position }); - } else { - util.AppCache.update(this.media_.src, position); - } -}; - -/** - * Resumes the playback position saved in the persistent storage. - */ -VideoControls.prototype.restorePlayState = function() { - if (this.media_.duration >= VideoControls.RESUME_THRESHOLD) { - util.AppCache.getValue(this.media_.src, function(position) { - if (position) - this.media_.currentTime = position; - }.bind(this)); - } -}; - -/** - * Updates style to best fit the size of the container. - */ -VideoControls.prototype.updateStyle = function() { - // We assume that the video controls element fills the parent container. - // This is easier than adding margins to this.container_.clientWidth. - var width = this.container_.parentNode.clientWidth; - - // Set the margin to 5px for width >= 400, 0px for width < 160, - // interpolate linearly in between. - this.container_.style.margin = - Math.ceil((Math.max(160, Math.min(width, 400)) - 160) / 48) + 'px'; - - var hideBelow = function(selector, limit) { - this.container_.querySelector(selector).style.display = - width < limit ? 'none' : '-webkit-box'; - }.bind(this); - - hideBelow('.time', 350); - hideBelow('.volume', 275); - hideBelow('.volume-controls', 210); - hideBelow('.fullscreen', 150); -}; - -/** - * Creates audio controls. - * - * @param {HTMLElement} container Parent container. - * @param {function(boolean)} advanceTrack Parameter: true=forward. - * @param {function} onError Error handler. - * @constructor - */ -function AudioControls(container, advanceTrack, onError) { - MediaControls.call(this, container, onError); - - this.container_.classList.add('audio-controls'); - - this.advanceTrack_ = advanceTrack; - - this.initPlayButton(); - this.initTimeControls(false /* no seek mark */); - /* No volume controls */ - this.createButton('previous', this.onAdvanceClick_.bind(this, false)); - this.createButton('next', this.onAdvanceClick_.bind(this, true)); - - var audioControls = this; - chrome.mediaPlayerPrivate.onNextTrack.addListener( - function() { audioControls.onAdvanceClick_(true); }); - chrome.mediaPlayerPrivate.onPrevTrack.addListener( - function() { audioControls.onAdvanceClick_(false); }); - chrome.mediaPlayerPrivate.onTogglePlayState.addListener( - function() { audioControls.togglePlayState(); }); -} - -AudioControls.prototype = { __proto__: MediaControls.prototype }; - -/** - * Media completion handler. Advances to the next track. - */ -AudioControls.prototype.onMediaComplete = function() { - this.advanceTrack_(true); -}; - -/** - * The track position after which "previous" button acts as "restart". - */ -AudioControls.TRACK_RESTART_THRESHOLD = 5; // seconds. - -/** - * @param {boolean} forward True if advancing forward. - * @private - */ -AudioControls.prototype.onAdvanceClick_ = function(forward) { - if (!forward && - (this.getMedia().currentTime > AudioControls.TRACK_RESTART_THRESHOLD)) { - // We are far enough from the beginning of the current track. - // Restart it instead of than skipping to the previous one. - this.getMedia().currentTime = 0; - } else { - this.advanceTrack_(forward); - } -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/media/media_util.js b/chromium/chrome/browser/resources/file_manager/foreground/js/media/media_util.js deleted file mode 100644 index a4c28348048..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/media/media_util.js +++ /dev/null @@ -1,421 +0,0 @@ -// 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. - -'use strict'; - -/** - * Loads a thumbnail using provided url. In CANVAS mode, loaded images - * are attached as <canvas> element, while in IMAGE mode as <img>. - * <canvas> renders faster than <img>, however has bigger memory overhead. - * - * @param {string} url File URL. - * @param {ThumbnailLoader.LoaderType=} opt_loaderType Canvas or Image loader, - * default: IMAGE. - * @param {Object=} opt_metadata Metadata object. - * @param {string=} opt_mediaType Media type. - * @param {ThumbnailLoader.UseEmbedded=} opt_useEmbedded If to use embedded - * jpeg thumbnail if available. Default: USE_EMBEDDED. - * @param {number=} opt_priority Priority, the highest is 0. default: 2. - * @constructor - */ -function ThumbnailLoader(url, opt_loaderType, opt_metadata, opt_mediaType, - opt_useEmbedded, opt_priority) { - opt_useEmbedded = opt_useEmbedded || ThumbnailLoader.UseEmbedded.USE_EMBEDDED; - - this.mediaType_ = opt_mediaType || FileType.getMediaType(url); - this.loaderType_ = opt_loaderType || ThumbnailLoader.LoaderType.IMAGE; - this.metadata_ = opt_metadata; - this.priority_ = (opt_priority !== undefined) ? opt_priority : 2; - this.transform_ = null; - - if (!opt_metadata) { - this.thumbnailUrl_ = url; // Use the URL directly. - return; - } - - this.fallbackUrl_ = null; - this.thumbnailUrl_ = null; - if (opt_metadata.drive && opt_metadata.drive.customIconUrl) - this.fallbackUrl_ = opt_metadata.drive.customIconUrl; - - // Fetch the rotation from the Drive metadata (if available). - var driveTransform; - if (opt_metadata.drive && opt_metadata.drive.imageRotation !== undefined) { - driveTransform = { - scaleX: 1, - scaleY: 1, - rotate90: opt_metadata.drive.imageRotation / 90 - }; - } - - if (opt_metadata.thumbnail && opt_metadata.thumbnail.url && - opt_useEmbedded == ThumbnailLoader.UseEmbedded.USE_EMBEDDED) { - this.thumbnailUrl_ = opt_metadata.thumbnail.url; - this.transform_ = driveTransform !== undefined ? driveTransform : - opt_metadata.thumbnail.transform; - } else if (FileType.isImage(url)) { - this.thumbnailUrl_ = url; - this.transform_ = driveTransform !== undefined ? driveTransform : - opt_metadata.media && opt_metadata.media.imageTransform; - } else if (this.fallbackUrl_) { - // Use fallback as the primary thumbnail. - this.thumbnailUrl_ = this.fallbackUrl_; - this.fallbackUrl_ = null; - } // else the generic thumbnail based on the media type will be used. -} - -/** - * In percents (0.0 - 1.0), how much area can be cropped to fill an image - * in a container, when loading a thumbnail in FillMode.AUTO mode. - * The specified 30% value allows to fill 16:9, 3:2 pictures in 4:3 element. - * @type {number} - */ -ThumbnailLoader.AUTO_FILL_THRESHOLD = 0.3; - -/** - * Type of displaying a thumbnail within a box. - * @enum {number} - */ -ThumbnailLoader.FillMode = { - FILL: 0, // Fill whole box. Image may be cropped. - FIT: 1, // Keep aspect ratio, do not crop. - OVER_FILL: 2, // Fill whole box with possible stretching. - AUTO: 3 // Try to fill, but if incompatible aspect ratio, then fit. -}; - -/** - * Optimization mode for downloading thumbnails. - * @enum {number} - */ -ThumbnailLoader.OptimizationMode = { - NEVER_DISCARD: 0, // Never discards downloading. No optimization. - DISCARD_DETACHED: 1 // Canceled if the container is not attached anymore. -}; - -/** - * Type of element to store the image. - * @enum {number} - */ -ThumbnailLoader.LoaderType = { - IMAGE: 0, - CANVAS: 1 -}; - -/** - * Whether to use the embedded thumbnail, or not. The embedded thumbnail may - * be small. - * @enum {number} - */ -ThumbnailLoader.UseEmbedded = { - USE_EMBEDDED: 0, - NO_EMBEDDED: 1 -}; - -/** - * Maximum thumbnail's width when generating from the full resolution image. - * @const - * @type {number} - */ -ThumbnailLoader.THUMBNAIL_MAX_WIDTH = 500; - -/** - * Maximum thumbnail's height when generating from the full resolution image. - * @const - * @type {number} - */ -ThumbnailLoader.THUMBNAIL_MAX_HEIGHT = 500; - -/** - * Loads and attaches an image. - * - * @param {HTMLElement} box Container element. - * @param {ThumbnailLoader.FillMode} fillMode Fill mode. - * @param {ThumbnailLoader.OptimizationMode=} opt_optimizationMode Optimization - * for downloading thumbnails. By default optimizations are disabled. - * @param {function(Image, Object)} opt_onSuccess Success callback, - * accepts the image and the transform. - * @param {function} opt_onError Error callback. - * @param {function} opt_onGeneric Callback for generic image used. - */ -ThumbnailLoader.prototype.load = function(box, fillMode, opt_optimizationMode, - opt_onSuccess, opt_onError, opt_onGeneric) { - opt_optimizationMode = opt_optimizationMode || - ThumbnailLoader.OptimizationMode.NEVER_DISCARD; - - if (!this.thumbnailUrl_) { - // Relevant CSS rules are in file_types.css. - box.setAttribute('generic-thumbnail', this.mediaType_); - if (opt_onGeneric) opt_onGeneric(); - return; - } - - this.cancel(); - this.canvasUpToDate_ = false; - this.image_ = new Image(); - this.image_.onload = function() { - this.attachImage(box, fillMode); - if (opt_onSuccess) - opt_onSuccess(this.image_, this.transform_); - }.bind(this); - this.image_.onerror = function() { - if (opt_onError) - opt_onError(); - if (this.fallbackUrl_) { - new ThumbnailLoader(this.fallbackUrl_, - this.loaderType_, - null, // No metadata. - this.mediaType_, - undefined, // Default value for use-embedded. - this.priority_). - load(box, fillMode, opt_optimizationMode, opt_onSuccess); - } else { - box.setAttribute('generic-thumbnail', this.mediaType_); - } - }.bind(this); - - if (this.image_.src) { - console.warn('Thumbnail already loaded: ' + this.thumbnailUrl_); - return; - } - - // TODO(mtomasz): Smarter calculation of the requested size. - var wasAttached = box.ownerDocument.contains(box); - var modificationTime = this.metadata_ && - this.metadata_.filesystem && - this.metadata_.filesystem.modificationTime && - this.metadata_.filesystem.modificationTime.getTime(); - this.taskId_ = util.loadImage( - this.image_, - this.thumbnailUrl_, - { maxWidth: ThumbnailLoader.THUMBNAIL_MAX_WIDTH, - maxHeight: ThumbnailLoader.THUMBNAIL_MAX_HEIGHT, - cache: true, - priority: this.priority_, - timestamp: modificationTime }, - function() { - if (opt_optimizationMode == - ThumbnailLoader.OptimizationMode.DISCARD_DETACHED && - !box.ownerDocument.contains(box)) { - // If the container is not attached, then invalidate the download. - return false; - } - return true; - }); -}; - -/** - * Cancels loading the current image. - */ -ThumbnailLoader.prototype.cancel = function() { - if (this.taskId_) { - this.image_.onload = function() {}; - this.image_.onerror = function() {}; - util.cancelLoadImage(this.taskId_); - this.taskId_ = null; - } -}; - -/** - * @return {boolean} True if a valid image is loaded. - */ -ThumbnailLoader.prototype.hasValidImage = function() { - return !!(this.image_ && this.image_.width && this.image_.height); -}; - -/** - * @return {boolean} True if the image is rotated 90 degrees left or right. - * @private - */ -ThumbnailLoader.prototype.isRotated_ = function() { - return this.transform_ && (this.transform_.rotate90 % 2 == 1); -}; - -/** - * @return {number} Image width (corrected for rotation). - */ -ThumbnailLoader.prototype.getWidth = function() { - return this.isRotated_() ? this.image_.height : this.image_.width; -}; - -/** - * @return {number} Image height (corrected for rotation). - */ -ThumbnailLoader.prototype.getHeight = function() { - return this.isRotated_() ? this.image_.width : this.image_.height; -}; - -/** - * Load an image but do not attach it. - * - * @param {function(boolean)} callback Callback, parameter is true if the image - * has loaded successfully or a stock icon has been used. - */ -ThumbnailLoader.prototype.loadDetachedImage = function(callback) { - if (!this.thumbnailUrl_) { - callback(true); - return; - } - - this.cancel(); - this.canvasUpToDate_ = false; - this.image_ = new Image(); - this.image_.onload = callback.bind(null, true); - this.image_.onerror = callback.bind(null, false); - - // TODO(mtomasz): Smarter calculation of the requested size. - var modificationTime = this.metadata_ && - this.metadata_.filesystem && - this.metadata_.filesystem.modificationTime && - this.metadata_.filesystem.modificationTime.getTime(); - this.taskId_ = util.loadImage( - this.image_, - this.thumbnailUrl_, - { maxWidth: ThumbnailLoader.THUMBNAIL_MAX_WIDTH, - maxHeight: ThumbnailLoader.THUMBNAIL_MAX_HEIGHT, - cache: true, - priority: this.priority_, - timestamp: modificationTime }); -}; - -/** - * Renders the thumbnail into either canvas or an image element. - * @private - */ -ThumbnailLoader.prototype.renderMedia_ = function() { - if (this.loaderType_ != ThumbnailLoader.LoaderType.CANVAS) - return; - - if (!this.canvas_) - this.canvas_ = document.createElement('canvas'); - - // Copy the image to a canvas if the canvas is outdated. - if (!this.canvasUpToDate_) { - this.canvas_.width = this.image_.width; - this.canvas_.height = this.image_.height; - var context = this.canvas_.getContext('2d'); - context.drawImage(this.image_, 0, 0); - this.canvasUpToDate_ = true; - } -}; - -/** - * Attach the image to a given element. - * @param {Element} container Parent element. - * @param {ThumbnailLoader.FillMode} fillMode Fill mode. - */ -ThumbnailLoader.prototype.attachImage = function(container, fillMode) { - if (!this.hasValidImage()) { - container.setAttribute('generic-thumbnail', this.mediaType_); - return; - } - - this.renderMedia_(); - util.applyTransform(container, this.transform_); - var attachableMedia = this.loaderType_ == ThumbnailLoader.LoaderType.CANVAS ? - this.canvas_ : this.image_; - - ThumbnailLoader.centerImage_( - container, attachableMedia, fillMode, this.isRotated_()); - - if (attachableMedia.parentNode != container) { - container.textContent = ''; - container.appendChild(attachableMedia); - } - - if (!this.taskId_) - attachableMedia.classList.add('cached'); -}; - -/** - * Gets the loaded image. - * TODO(mtomasz): Apply transformations. - * - * @return {Image|HTMLCanvasElement} Either image or a canvas object. - */ -ThumbnailLoader.prototype.getImage = function() { - this.renderMedia_(); - return this.loaderType_ == ThumbnailLoader.LoaderType.CANVAS ? this.canvas_ : - this.image_; -}; - -/** - * Update the image style to fit/fill the container. - * - * Using webkit center packing does not align the image properly, so we need - * to wait until the image loads and its dimensions are known, then manually - * position it at the center. - * - * @param {HTMLElement} box Containing element. - * @param {Image|HTMLCanvasElement} img Element containing an image. - * @param {ThumbnailLoader.FillMode} fillMode Fill mode. - * @param {boolean} rotate True if the image should be rotated 90 degrees. - * @private - */ -ThumbnailLoader.centerImage_ = function(box, img, fillMode, rotate) { - var imageWidth = img.width; - var imageHeight = img.height; - - var fractionX; - var fractionY; - - var boxWidth = box.clientWidth; - var boxHeight = box.clientHeight; - - var fill; - switch (fillMode) { - case ThumbnailLoader.FillMode.FILL: - case ThumbnailLoader.FillMode.OVER_FILL: - fill = true; - break; - case ThumbnailLoader.FillMode.FIT: - fill = false; - break; - case ThumbnailLoader.FillMode.AUTO: - var imageRatio = imageWidth / imageHeight; - var boxRatio = 1.0; - if (boxWidth && boxHeight) - boxRatio = boxWidth / boxHeight; - // Cropped area in percents. - var ratioFactor = boxRatio / imageRatio; - fill = (ratioFactor >= 1.0 - ThumbnailLoader.AUTO_FILL_THRESHOLD) && - (ratioFactor <= 1.0 + ThumbnailLoader.AUTO_FILL_THRESHOLD); - break; - } - - if (boxWidth && boxHeight) { - // When we know the box size we can position the image correctly even - // in a non-square box. - var fitScaleX = (rotate ? boxHeight : boxWidth) / imageWidth; - var fitScaleY = (rotate ? boxWidth : boxHeight) / imageHeight; - - var scale = fill ? - Math.max(fitScaleX, fitScaleY) : - Math.min(fitScaleX, fitScaleY); - - if (fillMode != ThumbnailLoader.FillMode.OVER_FILL) - scale = Math.min(scale, 1); // Never overscale. - - fractionX = imageWidth * scale / boxWidth; - fractionY = imageHeight * scale / boxHeight; - } else { - // We do not know the box size so we assume it is square. - // Compute the image position based only on the image dimensions. - // First try vertical fit or horizontal fill. - fractionX = imageWidth / imageHeight; - fractionY = 1; - if ((fractionX < 1) == !!fill) { // Vertical fill or horizontal fit. - fractionY = 1 / fractionX; - fractionX = 1; - } - } - - function percent(fraction) { - return (fraction * 100).toFixed(2) + '%'; - } - - img.style.width = percent(fractionX); - img.style.height = percent(fractionY); - img.style.left = percent((1 - fractionX) / 2); - img.style.top = percent((1 - fractionY) / 2); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/media/mediaplayer_scripts.js b/chromium/chrome/browser/resources/file_manager/foreground/js/media/mediaplayer_scripts.js deleted file mode 100644 index 496a8d09d98..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/media/mediaplayer_scripts.js +++ /dev/null @@ -1,33 +0,0 @@ -// 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. - -// The include directives are put into Javascript-style comments to prevent -// parsing errors in non-flattened mode. The flattener still sees them. -// Note that this makes the flattener to comment out the first line of the -// included file but that's all right since any javascript file should start -// with a copyright comment anyway. - - -//<include src="../../../../../../../ui/webui/resources/js/cr.js"/> -//<include src="../../../../../../../ui/webui/resources/js/cr/event_target.js"/> -//<include src="../../../../../../../ui/webui/resources/js/cr/ui/array_data_model.js"/> - -(function() { -// 'strict mode' is invoked for this scope. - -//<include src="../../../common/js/async_util.js"/> -//<include src="../../../common/js/util.js"/> -//<include src="../../../common/js/path_util.js"/> -//<include src="../file_type.js"/> -//<include src="../volume_manager_wrapper.js"> -//<include src="../metadata/metadata_cache.js"/> - -//<include src="media_controls.js"/> -//<include src="audio_player.js"/> -//<include src="player_testapi.js"/> - -window.reload = reload; -window.unload = unload; - -})(); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/media/player_testapi.js b/chromium/chrome/browser/resources/file_manager/foreground/js/media/player_testapi.js deleted file mode 100644 index 75f0b302502..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/media/player_testapi.js +++ /dev/null @@ -1,193 +0,0 @@ -// 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. - -'use strict'; - -/** - * Test API for Chrome OS Video Player and Audio Player. - * - * To test the Video Player open a tab with the URL: - * chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/video_player.html - * - * To test the Audio Player open a tab with the URL: - * chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/mediaplayer.html - * - */ -var playerTestAPI = { - - /* Methods common for audio and video players */ - - /** - * Respond with the path to the current media source. - */ - getSrc: function() { - playerTestAPI.respond_(util.extractFilePath(playerTestAPI.getMedia_().src)); - }, - - /** - * Respond with a boolean value, true if the media is playing. - */ - isPlaying: function() { - playerTestAPI.respond_(playerTestAPI.getControls_().isPlaying()); - }, - - /** - * Play the media. - */ - play: function() { - playerTestAPI.getControls_().play(); - }, - - /** - * Pause the playback. - */ - pause: function() { - playerTestAPI.getControls_().pause(); - }, - - /** - * Respond with a number, duration of the media in seconds. - */ - getDuration: function() { - playerTestAPI.respond_(playerTestAPI.getMedia_().duration); - }, - - /** - * Respond with a number, current media position in seconds. - */ - getCurrentTime: function() { - playerTestAPI.respond_(playerTestAPI.getMedia_().currentTime); - }, - - /** - * Change media position. - * @param {number} time Media positions. - */ - seekTo: function(time) { - playerTestAPI.getMedia_().currentTime = time; - }, - - /* Video player-specific methods. - * - * To test the video player open a tab with the url: - * chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/mediaplayer.html - * - */ - - /** - * Load the specified file in the video player, - * Starts playing immediately. - * @param {string} filePath File path. - */ - loadVideo: function(filePath) { - var url = util.makeFilesystemUrl(filePath); - location.href = location.origin + location.pathname + '?' + url; - reload(); - }, - - /** - * Respond with a number, current volume [0..100]. - */ - getVolume: function() { - playerTestAPI.respond_(playerTestAPI.getMedia_().volume * 100); - }, - - /** - * Change volume. - * @param {number} volume Volume [0..100]. - */ - setVolume: function(volume) { - playerTestAPI.respond_( - playerTestAPI.getControls_().onVolumeChange_(volume / 100)); - }, - - /** - * Respond with a boolean, true if the volume is muted. - */ - isMuted: function() { - playerTestAPI.respond_(playerTestAPI.getMedia_().volume == 0); - }, - - /** - * Mute the volume. No-op if already muted. - */ - mute: function() { - if (playerTestAPI.getMedia_().volume != 0) - playerTestAPI.getControls_().onSoundButtonClick_(); - }, - - /** - * Unmute the volume. No-op if not muted. - */ - unmute: function() { - if (playerTestAPI.getMedia_().volume == 0) - playerTestAPI.getControls_().onSoundButtonClick_(); - }, - - /* Audio player-specific methods. */ - - /** - * Load a group of tracks into the audio player. - * Starts playing one of the tracks immediately. - * @param {Array.<string>} filePaths Array of file paths. - * @param {number} firstTrack Number of the file to play first (0-based). - */ - loadAudio: function(filePaths, firstTrack) { - AudioPlayer.instance.load({ - items: filePaths.map(util.makeFilesystemUrl), - position: firstTrack - }); - }, - - /** - * Respond with a current track number, - */ - getTrackNumber: function() { - playerTestAPI.respond_(AudioPlayer.instance.currentTrack_); - }, - - /** - * Play the next track. - */ - forward: function() { - playerTestAPI.getControls_().onAdvanceClick_(true /* forward */); - }, - - /** - * Go back. Will restart the current track if the current position is > 5 sec - * or play the previous track otherwise. - */ - back: function() { - playerTestAPI.getControls_().onAdvanceClick_(false /* back */); - }, - - /* Utility methods */ - - /** - * @return {AudioControls|VideoControls} Media controls. - * @private - */ - getControls_: function() { - return window.controls || window.AudioPlayer.instance.audioControls_; - }, - - /** - * @return {HTMLVideoElement|HTMLAudioElement} Media element. - * @private - */ - getMedia_: function() { - return playerTestAPI.getControls_().getMedia(); - }, - - /** - * @param {string|boolean|number} value Value to send back. - * @private - */ - respond_: function(value) { - if (window.domAutomationController) - window.domAutomationController.send(value); - else - console.log('playerTestAPI response: ' + value); - } -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/media/util.js b/chromium/chrome/browser/resources/file_manager/foreground/js/media/util.js deleted file mode 100644 index 4d3c953dd55..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/media/util.js +++ /dev/null @@ -1,179 +0,0 @@ -// 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. - -'use strict'; - -/** - * A controller class detects mouse inactivity and hides "tool" elements. - * - * @param {Element} container The main DOM container. - * @param {number=} opt_timeout Hide timeout in ms. - * @param {function():boolean=} opt_toolsActive Function that returns |true| - * if the tools are active and should not be hidden. - * @constructor - */ -function MouseInactivityWatcher(container, opt_timeout, opt_toolsActive) { - this.container_ = container; - this.timeout_ = opt_timeout || MouseInactivityWatcher.DEFAULT_TIMEOUT; - this.toolsActive_ = opt_toolsActive || function() { return false }; - - this.onTimeoutBound_ = this.onTimeout_.bind(this); - this.timeoutID_ = null; - this.mouseOverTool_ = false; - - this.clientX_ = 0; - this.clientY_ = 0; - - /** - * Indicates if the inactivity watcher is enabled or disabled. Use getters - * and setters. - * @type {boolean} - * @private - **/ - this.disabled_ = false; - this.__defineSetter__('disabled', function(value) { - this.disabled_ = value; - if (value) - this.kick(); - else - this.check(); - }); - this.__defineGetter__('disabled', function() { - return this.disabled_; - }); - - this.container_.addEventListener('mousemove', this.onMouseMove_.bind(this)); - var tools = this.container_.querySelector('.tool'); - for (var i = 0; i < tools.length; i++) { - tools[i].addEventListener('mouseover', this.onToolMouseOver_.bind(this)); - tools[i].addEventListener('mouseout', this.onToolMouseOut_.bind(this)); - } - - // Show tools when the user touches the screen. - this.container_.addEventListener( - 'touchstart', this.activityStarted_.bind(this)); - var initiateFading = this.activityStopped_.bind(this, this.timeout_); - this.container_.addEventListener('touchend', initiateFading); - this.container_.addEventListener('touchcancel', initiateFading); -} - -/** - * Default inactivity timeout. - */ -MouseInactivityWatcher.DEFAULT_TIMEOUT = 3000; - -/** - * @param {boolean} on True if show, false if hide. - */ -MouseInactivityWatcher.prototype.showTools = function(on) { - if (on) - this.container_.setAttribute('tools', 'true'); - else - this.container_.removeAttribute('tools'); -}; - -/** - * To be called when the user started activity. Shows the tools - * and cancels the countdown. - * @private - */ -MouseInactivityWatcher.prototype.activityStarted_ = function() { - this.showTools(true); - - if (this.timeoutID_) { - clearTimeout(this.timeoutID_); - this.timeoutID_ = null; - } -}; - -/** - * Called when user activity has stopped. Re-starts the countdown. - * @param {number=} opt_timeout Timeout. - * @private - */ -MouseInactivityWatcher.prototype.activityStopped_ = function(opt_timeout) { - if (this.disabled_ || this.mouseOverTool_ || this.toolsActive_()) - return; - - if (this.timeoutID_) - clearTimeout(this.timeoutID_); - - this.timeoutID_ = setTimeout( - this.onTimeoutBound_, opt_timeout || this.timeout_); -}; - -/** - * Called when a user performed a short action (such as a click or a key press) - * that should show the tools if they are not visible. - * @param {number=} opt_timeout Timeout. - */ -MouseInactivityWatcher.prototype.kick = function(opt_timeout) { - this.activityStarted_(); - this.activityStopped_(opt_timeout); -}; - -/** - * Check if the tools are active and update the tools visibility accordingly. - */ -MouseInactivityWatcher.prototype.check = function() { - if (this.toolsActive_()) - this.activityStarted_(); - else - this.activityStopped_(); -}; - -/** - * Mouse move handler. - * - * @param {Event} e Event. - * @private - */ -MouseInactivityWatcher.prototype.onMouseMove_ = function(e) { - if (this.clientX_ == e.clientX && this.clientY_ == e.clientY) { - // The mouse has not moved, must be the cursor change triggered by - // some of the attributes on the root container. Ignore the event. - return; - } - this.clientX_ = e.clientX; - this.clientY_ = e.clientY; - - if (this.disabled_) - return; - - this.kick(); -}; - -/** - * Mouse over handler on a tool element. - * - * @param {Event} e Event. - * @private - */ -MouseInactivityWatcher.prototype.onToolMouseOver_ = function(e) { - this.mouseOverTool_ = true; - if (!this.disabled_) - this.kick(); -}; - -/** - * Mouse out handler on a tool element. - * - * @param {Event} e Event. - * @private - */ -MouseInactivityWatcher.prototype.onToolMouseOut_ = function(e) { - this.mouseOverTool_ = false; - if (!this.disabled_) - this.kick(); -}; - -/** - * Timeout handler. - * @private - */ -MouseInactivityWatcher.prototype.onTimeout_ = function() { - this.timeoutID_ = null; - if (!this.disabled_ && !this.toolsActive_()) - this.showTools(false); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/media/video_player.js b/chromium/chrome/browser/resources/file_manager/foreground/js/media/video_player.js deleted file mode 100644 index 9b4b663fdc1..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/media/video_player.js +++ /dev/null @@ -1,289 +0,0 @@ -// 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. - -'use strict'; - -/** - * Display error message. - * @param {string} message Message id. - */ -function showErrorMessage(message) { - var errorBanner = document.querySelector('#error'); - errorBanner.textContent = - loadTimeData.getString(message); - errorBanner.setAttribute('visible', 'true'); - - // The window is hidden if the video has not loaded yet. - chrome.app.window.current().show(); -} - -/** - * Handles playback (decoder) errors. - */ -function onPlaybackError() { - showErrorMessage('GALLERY_VIDEO_DECODING_ERROR'); - decodeErrorOccured = true; - - // Disable inactivity watcher, and disable the ui, by hiding tools manually. - controls.inactivityWatcher.disabled = true; - document.querySelector('#video-player').setAttribute('disabled', 'true'); - - // Detach the video element, since it may be unreliable and reset stored - // current playback time. - controls.cleanup(); - controls.clearState(); - - // Avoid reusing a video element. - video.parentNode.removeChild(video); - video = null; -} - -/** - * @param {Element} playerContainer Main container. - * @param {Element} videoContainer Container for the video element. - * @param {Element} controlsContainer Container for video controls. - * @constructor - */ -function FullWindowVideoControls( - playerContainer, videoContainer, controlsContainer) { - VideoControls.call(this, - controlsContainer, - onPlaybackError, - loadTimeData.getString.bind(loadTimeData), - this.toggleFullScreen_.bind(this), - videoContainer); - - this.playerContainer_ = playerContainer; - - this.updateStyle(); - window.addEventListener('resize', this.updateStyle.bind(this)); - - document.addEventListener('keydown', function(e) { - if (e.keyIdentifier == 'U+0020') { // Space - this.togglePlayStateWithFeedback(); - e.preventDefault(); - } - if (e.keyIdentifier == 'U+001B') { // Escape - util.toggleFullScreen( - chrome.app.window.current(), - false); // Leave the full screen mode. - e.preventDefault(); - } - }.bind(this)); - - // TODO(mtomasz): Simplify. crbug.com/254318. - videoContainer.addEventListener('click', function(e) { - if (e.ctrlKey) { - this.toggleLoopedModeWithFeedback(true); - if (!this.isPlaying()) - this.togglePlayStateWithFeedback(); - } else { - this.togglePlayStateWithFeedback(); - } - }.bind(this)); - - this.inactivityWatcher_ = new MouseInactivityWatcher(playerContainer); - this.__defineGetter__('inactivityWatcher', function() { - return this.inactivityWatcher_; - }); - - this.inactivityWatcher_.check(); -} - -FullWindowVideoControls.prototype = { __proto__: VideoControls.prototype }; - -/** - * Save the current state so that it survives page/app reload. - */ -FullWindowVideoControls.prototype.onPlayStateChanged = function() { - this.encodeState(); -}; - -/** - * Restore the state after the video is loaded. - */ -FullWindowVideoControls.prototype.restorePlayState = function() { - if (!this.decodeState()) { - VideoControls.prototype.restorePlayState.apply(this, arguments); - this.play(); - } -}; - -/** - * Toggles the full screen mode. - * @private - */ -FullWindowVideoControls.prototype.toggleFullScreen_ = function() { - var appWindow = chrome.app.window.current(); - util.toggleFullScreen(appWindow, !util.isFullScreen(appWindow)); -}; - -// TODO(mtomasz): Convert it to class members: crbug.com/171191. -var decodeErrorOccured; -var video; -var controls; -var metadataCache; -var volumeManager; -var selectedEntry; - -/** - * Initialize the video player window. - */ -function loadVideoPlayer() { - document.ondragstart = function(e) { e.preventDefault() }; - - chrome.fileBrowserPrivate.getStrings(function(strings) { - loadTimeData.data = strings; - - controls = new FullWindowVideoControls( - document.querySelector('#video-player'), - document.querySelector('#video-container'), - document.querySelector('#controls')); - - metadataCache = MetadataCache.createFull(); - volumeManager = new VolumeManagerWrapper( - VolumeManagerWrapper.DriveEnabledStatus.DRIVE_ENABLED); - volumeManager.addEventListener('externally-unmounted', - onExternallyUnmounted); - - // If the video player is starting before the first instance of the File - // Manager then it does not have access to filesystem URLs. - // Request it now. - volumeManager.ensureInitialized(reload); - var reloadVideo = function(e) { - if (decodeErrorOccured && - // Ignore shortcut keys - !e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey) { - reload(); - e.preventDefault(); - } - }; - - document.addEventListener('keydown', reloadVideo, true); - document.addEventListener('click', reloadVideo, true); - }); -} - -/** - * Closes video player when a volume containing the played item is unmounted. - * @param {Event} event The unmount event. - */ -function onExternallyUnmounted(event) { - if (!selectedEntry) - return; - - if (volumeManager.getVolumeInfo(selectedEntry) === event.volumeInfo) - window.close(); -} - -/** - * Unload the player. - */ -function unload() { - if (volumeManager) - volumeManager.dispose(); - - if (!controls.getMedia()) - return; - - controls.savePosition(true /* exiting */); - controls.cleanup(); -} - -/** - * Reload the player. - */ -function reload() { - // Re-enable ui and hide error message if already displayed. - document.querySelector('#video-player').removeAttribute('disabled'); - document.querySelector('#error').removeAttribute('visible'); - controls.inactivityWatcher.disabled = false; - decodeErrorOccured = false; - - var url; - if (window.appState) { - util.saveAppState(); - url = window.appState.url; - } else { - url = document.location.search.substr(1); - } - - document.title = decodeURIComponent(url.split('/').pop()); - var queue = new AsyncUtil.Queue(); - - queue.run(function(callback) { - webkitResolveLocalFileSystemURL(url, - function(entry) { - selectedEntry = entry; - callback(); - }, function() { - console.warn('Failed to resolve entry for: ' + url); - callback(); - }); - }); - - - queue.run(function(callback) { - if (!selectedEntry) { - showErrorMessage('GALLERY_VIDEO_ERROR'); - return; - } - metadataCache.get(selectedEntry, 'streaming', function(streaming) { - if (streaming && !navigator.onLine) { - showErrorMessage('GALLERY_VIDEO_OFFLINE'); - return; - } - - // Detach the previous video element, if exists. - if (video) - video.parentNode.removeChild(video); - - video = document.createElement('video'); - document.querySelector('#video-container').appendChild(video); - controls.attachMedia(video); - - video.src = selectedEntry.toURL(); - video.load(); - video.addEventListener('loadedmetadata', function() { - // TODO: chrome.app.window soon will be able to resize the content area. - // Until then use approximate title bar height. - var TITLE_HEIGHT = 28; - - var aspect = video.videoWidth / video.videoHeight; - var newWidth = video.videoWidth; - var newHeight = video.videoHeight + TITLE_HEIGHT; - - var shrinkX = newWidth / window.screen.availWidth; - var shrinkY = newHeight / window.screen.availHeight; - if (shrinkX > 1 || shrinkY > 1) { - if (shrinkY > shrinkX) { - newHeight = newHeight / shrinkY; - newWidth = (newHeight - TITLE_HEIGHT) * aspect; - } else { - newWidth = newWidth / shrinkX; - newHeight = newWidth / aspect + TITLE_HEIGHT; - } - } - - var oldLeft = window.screenX; - var oldTop = window.screenY; - var oldWidth = window.outerWidth; - var oldHeight = window.outerHeight; - - if (!oldWidth && !oldHeight) { - oldLeft = window.screen.availWidth / 2; - oldTop = window.screen.availHeight / 2; - } - - var appWindow = chrome.app.window.current(); - appWindow.resizeTo(newWidth, newHeight); - appWindow.moveTo(oldLeft - (newWidth - oldWidth) / 2, - oldTop - (newHeight - oldHeight) / 2); - appWindow.show(); - }); - }); - }); -} - -util.addPageLoadHandler(loadVideoPlayer); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/media/video_player_scripts.js b/chromium/chrome/browser/resources/file_manager/foreground/js/media/video_player_scripts.js deleted file mode 100644 index 54ea178f2fe..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/media/video_player_scripts.js +++ /dev/null @@ -1,34 +0,0 @@ -// 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. - -// The include directives are put into Javascript-style comments to prevent -// parsing errors in non-flattened mode. The flattener still sees them. -// Note that this makes the flattener to comment out the first line of the -// included file but that's all right since any javascript file should start -// with a copyright comment anyway. - -//<include src="../../../../../../../ui/webui/resources/js/cr.js"/> -//<include src="../../../../../../../ui/webui/resources/js/cr/event_target.js"/> -//<include src="../../../../../../../ui/webui/resources/js/cr/ui/array_data_model.js"/> -//<include src="../../../../../../../ui/webui/resources/js/load_time_data.js"/> - -(function() { -// 'strict mode' is invoked for this scope. - -//<include src="../../../common/js/async_util.js"/> -//<include src="../../../common/js/util.js"/> -//<include src="../../../common/js/path_util.js"/> -//<include src="../file_type.js"/> -//<include src="../volume_manager_wrapper.js"> -//<include src="../metadata/metadata_cache.js"/> - -//<include src="media_controls.js"/> -//<include src="util.js"/> -//<include src="video_player.js"/> -//<include src="player_testapi.js"/> - -window.reload = reload; -window.unload = unload; - -})(); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/byte_reader.js b/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/byte_reader.js deleted file mode 100644 index 09cf306b53c..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/byte_reader.js +++ /dev/null @@ -1,535 +0,0 @@ -// 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. - -'use strict'; - -/** - * @constructor - * @param {ArrayBuffer} arrayBuffer // TODO(JSDOC). - * @param {number=} opt_offset // TODO(JSDOC). - * @param {number=} opt_length // TODO(JSDOC). - */ -function ByteReader(arrayBuffer, opt_offset, opt_length) { - opt_offset = opt_offset || 0; - opt_length = opt_length || (arrayBuffer.byteLength - opt_offset); - this.view_ = new DataView(arrayBuffer, opt_offset, opt_length); - this.pos_ = 0; - this.seekStack_ = []; - this.setByteOrder(ByteReader.BIG_ENDIAN); -} - -// Static constants and methods. - -/** - * Intel, 0x1234 is [0x34, 0x12] - * @const - * @type {number} - */ -ByteReader.LITTLE_ENDIAN = 0; -/** - * Motorola, 0x1234 is [0x12, 0x34] - * @const - * @type {number} - */ -ByteReader.BIG_ENDIAN = 1; - -/** - * Seek relative to the beginning of the buffer. - * @const - * @type {number} - */ -ByteReader.SEEK_BEG = 0; -/** - * Seek relative to the current position. - * @const - * @type {number} - */ -ByteReader.SEEK_CUR = 1; -/** - * Seek relative to the end of the buffer. - * @const - * @type {number} - */ -ByteReader.SEEK_END = 2; - -/** - * Throw an error if (0 > pos >= end) or if (pos + size > end). - * - * Static utility function. - * - * @param {number} pos // TODO(JSDOC). - * @param {number} size // TODO(JSDOC). - * @param {number} end // TODO(JSDOC). - */ -ByteReader.validateRead = function(pos, size, end) { - if (pos < 0 || pos >= end) - throw new Error('Invalid read position'); - - if (pos + size > end) - throw new Error('Read past end of buffer'); -}; - -/** - * Read as a sequence of characters, returning them as a single string. - * - * This is a static utility function. There is a member function with the - * same name which side-effects the current read position. - * - * @param {DataView} dataView // TODO(JSDOC). - * @param {number} pos // TODO(JSDOC). - * @param {number} size // TODO(JSDOC). - * @param {number=} opt_end // TODO(JSDOC). - * @return {string} // TODO(JSDOC). - */ -ByteReader.readString = function(dataView, pos, size, opt_end) { - ByteReader.validateRead(pos, size, opt_end || dataView.byteLength); - - var codes = []; - - for (var i = 0; i < size; ++i) - codes.push(dataView.getUint8(pos + i)); - - return String.fromCharCode.apply(null, codes); -}; - -/** - * Read as a sequence of characters, returning them as a single string. - * - * This is a static utility function. There is a member function with the - * same name which side-effects the current read position. - * - * @param {DataView} dataView // TODO(JSDOC). - * @param {number} pos // TODO(JSDOC). - * @param {number} size // TODO(JSDOC). - * @param {number=} opt_end // TODO(JSDOC). - * @return {string} // TODO(JSDOC). - */ -ByteReader.readNullTerminatedString = function(dataView, pos, size, opt_end) { - ByteReader.validateRead(pos, size, opt_end || dataView.byteLength); - - var codes = []; - - for (var i = 0; i < size; ++i) { - var code = dataView.getUint8(pos + i); - if (code == 0) break; - codes.push(code); - } - - return String.fromCharCode.apply(null, codes); -}; - -/** - * Read as a sequence of UTF16 characters, returning them as a single string. - * - * This is a static utility function. There is a member function with the - * same name which side-effects the current read position. - * - * @param {DataView} dataView // TODO(JSDOC). - * @param {number} pos // TODO(JSDOC). - * @param {boolean} bom // TODO(JSDOC). - * @param {number} size // TODO(JSDOC). - * @param {number=} opt_end // TODO(JSDOC). - * @return {string} // TODO(JSDOC). - */ -ByteReader.readNullTerminatedStringUTF16 = function( - dataView, pos, bom, size, opt_end) { - ByteReader.validateRead(pos, size, opt_end || dataView.byteLength); - - var littleEndian = false; - var start = 0; - - if (bom) { - littleEndian = (dataView.getUint8(pos) == 0xFF); - start = 2; - } - - var codes = []; - - for (var i = start; i < size; i += 2) { - var code = dataView.getUint16(pos + i, littleEndian); - if (code == 0) break; - codes.push(code); - } - - return String.fromCharCode.apply(null, codes); -}; - -/** - * @const - * @type {Array.<string>} - * @private - */ -ByteReader.base64Alphabet_ = - ('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'). - split(''); - -/** - * Read as a sequence of bytes, returning them as a single base64 encoded - * string. - * - * This is a static utility function. There is a member function with the - * same name which side-effects the current read position. - * - * @param {DataView} dataView // TODO(JSDOC). - * @param {number} pos // TODO(JSDOC). - * @param {number} size // TODO(JSDOC). - * @param {number=} opt_end // TODO(JSDOC). - * @return {string} // TODO(JSDOC). - */ -ByteReader.readBase64 = function(dataView, pos, size, opt_end) { - ByteReader.validateRead(pos, size, opt_end || dataView.byteLength); - - var rv = []; - var chars = []; - var padding = 0; - - for (var i = 0; i < size; /* incremented inside */) { - var bits = dataView.getUint8(pos + (i++)) << 16; - - if (i < size) { - bits |= dataView.getUint8(pos + (i++)) << 8; - - if (i < size) { - bits |= dataView.getUint8(pos + (i++)); - } else { - padding = 1; - } - } else { - padding = 2; - } - - chars[3] = ByteReader.base64Alphabet_[bits & 63]; - chars[2] = ByteReader.base64Alphabet_[(bits >> 6) & 63]; - chars[1] = ByteReader.base64Alphabet_[(bits >> 12) & 63]; - chars[0] = ByteReader.base64Alphabet_[(bits >> 18) & 63]; - - rv.push.apply(rv, chars); - } - - if (padding > 0) - rv[rv.length - 1] = '='; - if (padding > 1) - rv[rv.length - 2] = '='; - - return rv.join(''); -}; - -/** - * Read as an image encoded in a data url. - * - * This is a static utility function. There is a member function with the - * same name which side-effects the current read position. - * - * @param {DataView} dataView // TODO(JSDOC). - * @param {number} pos // TODO(JSDOC). - * @param {number} size // TODO(JSDOC). - * @param {number=} opt_end // TODO(JSDOC). - * @return {string} // TODO(JSDOC). - */ -ByteReader.readImage = function(dataView, pos, size, opt_end) { - opt_end = opt_end || dataView.byteLength; - ByteReader.validateRead(pos, size, opt_end); - - // Two bytes is enough to identify the mime type. - var prefixToMime = { - '\x89P' : 'png', - '\xFF\xD8' : 'jpeg', - 'BM' : 'bmp', - 'GI' : 'gif' - }; - - var prefix = ByteReader.readString(dataView, pos, 2, opt_end); - var mime = prefixToMime[prefix] || - dataView.getUint16(pos, false).toString(16); // For debugging. - - var b64 = ByteReader.readBase64(dataView, pos, size, opt_end); - return 'data:image/' + mime + ';base64,' + b64; -}; - -// Instance methods. - -/** - * Return true if the requested number of bytes can be read from the buffer. - * - * @param {number} size // TODO(JSDOC). - * @return {boolean} // TODO(JSDOC). - */ -ByteReader.prototype.canRead = function(size) { - return this.pos_ + size <= this.view_.byteLength; -}; - -/** - * Return true if the current position is past the end of the buffer. - * @return {boolean} // TODO(JSDOC). - */ -ByteReader.prototype.eof = function() { - return this.pos_ >= this.view_.byteLength; -}; - -/** - * Return true if the current position is before the beginning of the buffer. - * @return {boolean} // TODO(JSDOC). - */ -ByteReader.prototype.bof = function() { - return this.pos_ < 0; -}; - -/** - * Return true if the current position is outside the buffer. - * @return {boolean} // TODO(JSDOC). - */ -ByteReader.prototype.beof = function() { - return this.pos_ >= this.view_.byteLength || this.pos_ < 0; -}; - -/** - * Set the expected byte ordering for future reads. - * @param {number} order // TODO(JSDOC). - */ -ByteReader.prototype.setByteOrder = function(order) { - this.littleEndian_ = order == ByteReader.LITTLE_ENDIAN; -}; - -/** - * Throw an error if the reader is at an invalid position, or if a read a read - * of |size| would put it in one. - * - * You may optionally pass opt_end to override what is considered to be the - * end of the buffer. - * - * @param {number} size // TODO(JSDOC). - * @param {number=} opt_end // TODO(JSDOC). - */ -ByteReader.prototype.validateRead = function(size, opt_end) { - if (typeof opt_end == 'undefined') - opt_end = this.view_.byteLength; - - ByteReader.validateRead(this.view_, this.pos_, size, opt_end); -}; - -/** - * @param {number} width // TODO(JSDOC). - * @param {boolean=} opt_signed // TODO(JSDOC). - * @param {number=} opt_end // TODO(JSDOC). - * @return {string} // TODO(JSDOC). - */ -ByteReader.prototype.readScalar = function(width, opt_signed, opt_end) { - var method = opt_signed ? 'getInt' : 'getUint'; - - switch (width) { - case 1: - method += '8'; - break; - - case 2: - method += '16'; - break; - - case 4: - method += '32'; - break; - - case 8: - method += '64'; - break; - - default: - throw new Error('Invalid width: ' + width); - break; - } - - this.validateRead(width, opt_end); - var rv = this.view_[method](this.pos_, this.littleEndian_); - this.pos_ += width; - return rv; -}; - -/** - * Read as a sequence of characters, returning them as a single string. - * - * Adjusts the current position on success. Throws an exception if the - * read would go past the end of the buffer. - * - * @param {number} size // TODO(JSDOC). - * @param {number=} opt_end // TODO(JSDOC). - * @return {string} // TODO(JSDOC). - */ -ByteReader.prototype.readString = function(size, opt_end) { - var rv = ByteReader.readString(this.view_, this.pos_, size, opt_end); - this.pos_ += size; - return rv; -}; - - -/** - * Read as a sequence of characters, returning them as a single string. - * - * Adjusts the current position on success. Throws an exception if the - * read would go past the end of the buffer. - * - * @param {number} size // TODO(JSDOC). - * @param {number=} opt_end // TODO(JSDOC). - * @return {string} // TODO(JSDOC). - */ -ByteReader.prototype.readNullTerminatedString = function(size, opt_end) { - var rv = ByteReader.readNullTerminatedString(this.view_, - this.pos_, - size, - opt_end); - this.pos_ += rv.length; - - if (rv.length < size) { - // If we've stopped reading because we found '0' but didn't hit size limit - // then we should skip additional '0' character - this.pos_++; - } - - return rv; -}; - - -/** - * Read as a sequence of UTF16 characters, returning them as a single string. - * - * Adjusts the current position on success. Throws an exception if the - * read would go past the end of the buffer. - * - * @param {boolean} bom // TODO(JSDOC). - * @param {number} size // TODO(JSDOC). - * @param {number=} opt_end // TODO(JSDOC). - * @return {string} // TODO(JSDOC). - */ -ByteReader.prototype.readNullTerminatedStringUTF16 = - function(bom, size, opt_end) { - var rv = ByteReader.readNullTerminatedStringUTF16( - this.view_, this.pos_, bom, size, opt_end); - - if (bom) { - // If the BOM word was present advance the position. - this.pos_ += 2; - } - - this.pos_ += rv.length; - - if (rv.length < size) { - // If we've stopped reading because we found '0' but didn't hit size limit - // then we should skip additional '0' character - this.pos_ += 2; - } - - return rv; -}; - - -/** - * Read as an array of numbers. - * - * Adjusts the current position on success. Throws an exception if the - * read would go past the end of the buffer. - * - * @param {number} size // TODO(JSDOC). - * @param {number=} opt_end // TODO(JSDOC). - * @param {function(new:Array.<*>)=} opt_arrayConstructor // TODO(JSDOC). - * @return {Array.<*>} // TODO(JSDOC). - */ -ByteReader.prototype.readSlice = function(size, opt_end, - opt_arrayConstructor) { - this.validateRead(size, opt_end); - - var arrayConstructor = opt_arrayConstructor || Uint8Array; - var slice = new arrayConstructor( - this.view_.buffer, this.view_.byteOffset + this.pos, size); - this.pos_ += size; - - return slice; -}; - -/** - * Read as a sequence of bytes, returning them as a single base64 encoded - * string. - * - * Adjusts the current position on success. Throws an exception if the - * read would go past the end of the buffer. - * - * @param {number} size // TODO(JSDOC). - * @param {number=} opt_end // TODO(JSDOC). - * @return {string} // TODO(JSDOC). - */ -ByteReader.prototype.readBase64 = function(size, opt_end) { - var rv = ByteReader.readBase64(this.view_, this.pos_, size, opt_end); - this.pos_ += size; - return rv; -}; - -/** - * Read an image returning it as a data url. - * - * Adjusts the current position on success. Throws an exception if the - * read would go past the end of the buffer. - * - * @param {number} size // TODO(JSDOC). - * @param {number=} opt_end // TODO(JSDOC). - * @return {string} // TODO(JSDOC). - */ -ByteReader.prototype.readImage = function(size, opt_end) { - var rv = ByteReader.readImage(this.view_, this.pos_, size, opt_end); - this.pos_ += size; - return rv; -}; - -/** - * Seek to a give position relative to opt_seekStart. - * - * @param {number} pos // TODO(JSDOC). - * @param {number=} opt_seekStart // TODO(JSDOC). - * @param {number=} opt_end // TODO(JSDOC). - */ -ByteReader.prototype.seek = function(pos, opt_seekStart, opt_end) { - opt_end = opt_end || this.view_.byteLength; - - var newPos; - if (opt_seekStart == ByteReader.SEEK_CUR) { - newPos = this.pos_ + pos; - } else if (opt_seekStart == ByteReader.SEEK_END) { - newPos = opt_end + pos; - } else { - newPos = pos; - } - - if (newPos < 0 || newPos > this.view_.byteLength) - throw new Error('Seek outside of buffer: ' + (newPos - opt_end)); - - this.pos_ = newPos; -}; - -/** - * Seek to a given position relative to opt_seekStart, saving the current - * position. - * - * Recover the current position with a call to seekPop. - * - * @param {number} pos // TODO(JSDOC). - * @param {number=} opt_seekStart // TODO(JSDOC). - */ -ByteReader.prototype.pushSeek = function(pos, opt_seekStart) { - var oldPos = this.pos_; - this.seek(pos, opt_seekStart); - // Alter the seekStack_ after the call to seek(), in case it throws. - this.seekStack_.push(oldPos); -}; - -/** - * Undo a previous seekPush. - */ -ByteReader.prototype.popSeek = function() { - this.seek(this.seekStack_.pop()); -}; - -/** - * Return the current read position. - * @return {number} // TODO(JSDOC). - */ -ByteReader.prototype.tell = function() { - return this.pos_; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/exif_parser.js b/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/exif_parser.js deleted file mode 100644 index f81e5cc0b9f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/exif_parser.js +++ /dev/null @@ -1,439 +0,0 @@ -// 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. - -'use strict'; - -var EXIF_MARK_SOI = 0xffd8; // Start of image data. -var EXIF_MARK_SOS = 0xffda; // Start of "stream" (the actual image data). -var EXIF_MARK_SOF = 0xffc0; // Start of "frame" -var EXIF_MARK_EXIF = 0xffe1; // Start of exif block. - -var EXIF_ALIGN_LITTLE = 0x4949; // Indicates little endian exif data. -var EXIF_ALIGN_BIG = 0x4d4d; // Indicates big endian exif data. - -var EXIF_TAG_TIFF = 0x002a; // First directory containing TIFF data. -var EXIF_TAG_GPSDATA = 0x8825; // Pointer from TIFF to the GPS directory. -var EXIF_TAG_EXIFDATA = 0x8769; // Pointer from TIFF to the EXIF IFD. -var EXIF_TAG_SUBIFD = 0x014a; // Pointer from TIFF to "Extra" IFDs. - -var EXIF_TAG_JPG_THUMB_OFFSET = 0x0201; // Pointer from TIFF to thumbnail. -var EXIF_TAG_JPG_THUMB_LENGTH = 0x0202; // Length of thumbnail data. - -var EXIF_TAG_ORIENTATION = 0x0112; -var EXIF_TAG_X_DIMENSION = 0xA002; -var EXIF_TAG_Y_DIMENSION = 0xA003; - -function ExifParser(parent) { - ImageParser.call(this, parent, 'jpeg', /\.jpe?g$/i); -} - -ExifParser.prototype = {__proto__: ImageParser.prototype}; - -/** - * @param {File} file // TODO(JSDOC). - * @param {Object} metadata // TODO(JSDOC). - * @param {function} callback // TODO(JSDOC). - * @param {function} errorCallback // TODO(JSDOC). - */ -ExifParser.prototype.parse = function(file, metadata, callback, errorCallback) { - this.requestSlice(file, callback, errorCallback, metadata, 0); -}; - -/** - * @param {File} file // TODO(JSDOC). - * @param {function} callback // TODO(JSDOC). - * @param {function} errorCallback // TODO(JSDOC). - * @param {Object} metadata // TODO(JSDOC). - * @param {number} filePos // TODO(JSDOC). - * @param {number=} opt_length // TODO(JSDOC). - */ -ExifParser.prototype.requestSlice = function( - file, callback, errorCallback, metadata, filePos, opt_length) { - // Read at least 1Kb so that we do not issue too many read requests. - opt_length = Math.max(1024, opt_length || 0); - - var self = this; - var reader = new FileReader(); - reader.onerror = errorCallback; - reader.onload = function() { self.parseSlice( - file, callback, errorCallback, metadata, filePos, reader.result); - }; - reader.readAsArrayBuffer(file.slice(filePos, filePos + opt_length)); -}; - -/** - * @param {File} file // TODO(JSDOC). - * @param {function} callback // TODO(JSDOC). - * @param {function} errorCallback // TODO(JSDOC). - * @param {Object} metadata // TODO(JSDOC). - * @param {number} filePos // TODO(JSDOC). - * @param {ArrayBuffer} buf // TODO(JSDOC). - */ -ExifParser.prototype.parseSlice = function( - file, callback, errorCallback, metadata, filePos, buf) { - try { - var br = new ByteReader(buf); - - if (!br.canRead(4)) { - // We never ask for less than 4 bytes. This can only mean we reached EOF. - throw new Error('Unexpected EOF @' + (filePos + buf.byteLength)); - } - - if (filePos == 0) { - // First slice, check for the SOI mark. - var firstMark = this.readMark(br); - if (firstMark != EXIF_MARK_SOI) - throw new Error('Invalid file header: ' + firstMark.toString(16)); - } - - var self = this; - var reread = function(opt_offset, opt_bytes) { - self.requestSlice(file, callback, errorCallback, metadata, - filePos + br.tell() + (opt_offset || 0), opt_bytes); - }; - - while (true) { - if (!br.canRead(4)) { - // Cannot read the mark and the length, request a minimum-size slice. - reread(); - return; - } - - var mark = this.readMark(br); - if (mark == EXIF_MARK_SOS) - throw new Error('SOS marker found before SOF'); - - var markLength = this.readMarkLength(br); - - var nextSectionStart = br.tell() + markLength; - if (!br.canRead(markLength)) { - // Get the entire section. - if (filePos + br.tell() + markLength > file.size) { - throw new Error( - 'Invalid section length @' + (filePos + br.tell() - 2)); - } - reread(-4, markLength + 4); - return; - } - - if (mark == EXIF_MARK_EXIF) { - this.parseExifSection(metadata, buf, br); - } else if (ExifParser.isSOF_(mark)) { - // The most reliable size information is encoded in the SOF section. - br.seek(1, ByteReader.SEEK_CUR); // Skip the precision byte. - var height = br.readScalar(2); - var width = br.readScalar(2); - ExifParser.setImageSize(metadata, width, height); - callback(metadata); // We are done! - return; - } - - br.seek(nextSectionStart, ByteReader.SEEK_BEG); - } - } catch (e) { - errorCallback(e.toString()); - } -}; - -/** - * @private - * @param {number} mark // TODO(JSDOC). - * @return {boolean} // TODO(JSDOC). - */ -ExifParser.isSOF_ = function(mark) { - // There are 13 variants of SOF fragment format distinguished by the last - // hex digit of the mark, but the part we want is always the same. - if ((mark & ~0xF) != EXIF_MARK_SOF) return false; - - // If the last digit is 4, 8 or 12 it is not really a SOF. - var type = mark & 0xF; - return (type != 4 && type != 8 && type != 12); -}; - -/** - * @param {Object} metadata // TODO(JSDOC). - * @param {ArrayBuffer} buf // TODO(JSDOC). - * @param {ByteReader} br // TODO(JSDOC). - */ -ExifParser.prototype.parseExifSection = function(metadata, buf, br) { - var magic = br.readString(6); - if (magic != 'Exif\0\0') { - // Some JPEG files may have sections marked with EXIF_MARK_EXIF - // but containing something else (e.g. XML text). Ignore such sections. - this.vlog('Invalid EXIF magic: ' + magic + br.readString(100)); - return; - } - - // Offsets inside the EXIF block are based after the magic string. - // Create a new ByteReader based on the current position to make offset - // calculations simpler. - br = new ByteReader(buf, br.tell()); - - var order = br.readScalar(2); - if (order == EXIF_ALIGN_LITTLE) { - br.setByteOrder(ByteReader.LITTLE_ENDIAN); - } else if (order != EXIF_ALIGN_BIG) { - this.log('Invalid alignment value: ' + order.toString(16)); - return; - } - - var tag = br.readScalar(2); - if (tag != EXIF_TAG_TIFF) { - this.log('Invalid TIFF tag: ' + tag.toString(16)); - return; - } - - metadata.littleEndian = (order == EXIF_ALIGN_LITTLE); - metadata.ifd = { - image: {}, - thumbnail: {} - }; - var directoryOffset = br.readScalar(4); - - // Image directory. - this.vlog('Read image directory.'); - br.seek(directoryOffset); - directoryOffset = this.readDirectory(br, metadata.ifd.image); - metadata.imageTransform = this.parseOrientation(metadata.ifd.image); - - // Thumbnail Directory chained from the end of the image directory. - if (directoryOffset) { - this.vlog('Read thumbnail directory.'); - br.seek(directoryOffset); - this.readDirectory(br, metadata.ifd.thumbnail); - // If no thumbnail orientation is encoded, assume same orientation as - // the primary image. - metadata.thumbnailTransform = - this.parseOrientation(metadata.ifd.thumbnail) || - metadata.imageTransform; - } - - // EXIF Directory may be specified as a tag in the image directory. - if (EXIF_TAG_EXIFDATA in metadata.ifd.image) { - this.vlog('Read EXIF directory.'); - directoryOffset = metadata.ifd.image[EXIF_TAG_EXIFDATA].value; - br.seek(directoryOffset); - metadata.ifd.exif = {}; - this.readDirectory(br, metadata.ifd.exif); - } - - // GPS Directory may also be linked from the image directory. - if (EXIF_TAG_GPSDATA in metadata.ifd.image) { - this.vlog('Read GPS directory.'); - directoryOffset = metadata.ifd.image[EXIF_TAG_GPSDATA].value; - br.seek(directoryOffset); - metadata.ifd.gps = {}; - this.readDirectory(br, metadata.ifd.gps); - } - - // Thumbnail may be linked from the image directory. - if (EXIF_TAG_JPG_THUMB_OFFSET in metadata.ifd.thumbnail && - EXIF_TAG_JPG_THUMB_LENGTH in metadata.ifd.thumbnail) { - this.vlog('Read thumbnail image.'); - br.seek(metadata.ifd.thumbnail[EXIF_TAG_JPG_THUMB_OFFSET].value); - metadata.thumbnailURL = br.readImage( - metadata.ifd.thumbnail[EXIF_TAG_JPG_THUMB_LENGTH].value); - } else { - this.vlog('Image has EXIF data, but no JPG thumbnail.'); - } -}; - -/** - * @param {Object} metadata // TODO(JSDOC). - * @param {number} width // TODO(JSDOC). - * @param {number} height // TODO(JSDOC). - */ -ExifParser.setImageSize = function(metadata, width, height) { - if (metadata.imageTransform && metadata.imageTransform.rotate90) { - metadata.width = height; - metadata.height = width; - } else { - metadata.width = width; - metadata.height = height; - } -}; - -/** - * @param {ByteReader} br // TODO(JSDOC). - * @return {number} // TODO(JSDOC). - */ -ExifParser.prototype.readMark = function(br) { - return br.readScalar(2); -}; - -/** - * @param {ByteReader} br // TODO(JSDOC). - * @return {number} // TODO(JSDOC). - */ -ExifParser.prototype.readMarkLength = function(br) { - // Length includes the 2 bytes used to store the length. - return br.readScalar(2) - 2; -}; - -/** - * @param {ByteReader} br // TODO(JSDOC). - * @param {Array.<Object>} tags // TODO(JSDOC). - * @return {number} // TODO(JSDOC). - */ -ExifParser.prototype.readDirectory = function(br, tags) { - var entryCount = br.readScalar(2); - for (var i = 0; i < entryCount; i++) { - var tagId = br.readScalar(2); - var tag = tags[tagId] = {id: tagId}; - tag.format = br.readScalar(2); - tag.componentCount = br.readScalar(4); - this.readTagValue(br, tag); - } - - return br.readScalar(4); -}; - -/** - * @param {ByteReader} br // TODO(JSDOC). - * @param {Object} tag // TODO(JSDOC). - */ -ExifParser.prototype.readTagValue = function(br, tag) { - var self = this; - - function safeRead(size, readFunction, signed) { - try { - unsafeRead(size, readFunction, signed); - } catch (ex) { - self.log('error reading tag 0x' + tag.id.toString(16) + '/' + - tag.format + ', size ' + tag.componentCount + '*' + size + ' ' + - (ex.stack || '<no stack>') + ': ' + ex); - tag.value = null; - } - } - - function unsafeRead(size, readFunction, signed) { - if (!readFunction) - readFunction = function(size) { return br.readScalar(size, signed) }; - - var totalSize = tag.componentCount * size; - if (totalSize < 1) { - // This is probably invalid exif data, skip it. - tag.componentCount = 1; - tag.value = br.readScalar(4); - return; - } - - if (totalSize > 4) { - // If the total size is > 4, the next 4 bytes will be a pointer to the - // actual data. - br.pushSeek(br.readScalar(4)); - } - - if (tag.componentCount == 1) { - tag.value = readFunction(size); - } else { - // Read multiple components into an array. - tag.value = []; - for (var i = 0; i < tag.componentCount; i++) - tag.value[i] = readFunction(size); - } - - if (totalSize > 4) { - // Go back to the previous position if we had to jump to the data. - br.popSeek(); - } else if (totalSize < 4) { - // Otherwise, if the value wasn't exactly 4 bytes, skip over the - // unread data. - br.seek(4 - totalSize, ByteReader.SEEK_CUR); - } - } - - switch (tag.format) { - case 1: // Byte - case 7: // Undefined - safeRead(1); - break; - - case 2: // String - safeRead(1); - if (tag.componentCount == 0) { - tag.value = ''; - } else if (tag.componentCount == 1) { - tag.value = String.fromCharCode(tag.value); - } else { - tag.value = String.fromCharCode.apply(null, tag.value); - } - break; - - case 3: // Short - safeRead(2); - break; - - case 4: // Long - safeRead(4); - break; - - case 9: // Signed Long - safeRead(4, null, true); - break; - - case 5: // Rational - safeRead(8, function() { - return [br.readScalar(4), br.readScalar(4)]; - }); - break; - - case 10: // Signed Rational - safeRead(8, function() { - return [br.readScalar(4, true), br.readScalar(4, true)]; - }); - break; - - default: // ??? - this.vlog('Unknown tag format 0x' + Number(tag.id).toString(16) + - ': ' + tag.format); - safeRead(4); - break; - } - - this.vlog('Read tag: 0x' + tag.id.toString(16) + '/' + tag.format + ': ' + - tag.value); -}; - -/** - * TODO(JSDOC) - * @const - * @type {Array.<number>} - */ -ExifParser.SCALEX = [1, -1, -1, 1, 1, 1, -1, -1]; - -/** - * TODO(JSDOC) - * @const - * @type {Array.<number>} - */ -ExifParser.SCALEY = [1, 1, -1, -1, -1, 1, 1, -1]; - -/** - * TODO(JSDOC) - * @const - * @type {Array.<number>} - */ -ExifParser.ROTATE90 = [0, 0, 0, 0, 1, 1, 1, 1]; - -/** - * Transform exif-encoded orientation into a set of parameters compatible with - * CSS and canvas transforms (scaleX, scaleY, rotation). - * - * @param {Object} ifd exif property dictionary (image or thumbnail). - * @return {Object} // TODO(JSDOC). - */ -ExifParser.prototype.parseOrientation = function(ifd) { - if (ifd[EXIF_TAG_ORIENTATION]) { - var index = (ifd[EXIF_TAG_ORIENTATION].value || 1) - 1; - return { - scaleX: ExifParser.SCALEX[index], - scaleY: ExifParser.SCALEY[index], - rotate90: ExifParser.ROTATE90[index] - }; - } - return null; -}; - -MetadataDispatcher.registerParserClass(ExifParser); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/function_parallel.js b/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/function_parallel.js deleted file mode 100644 index 1691a89a1fa..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/function_parallel.js +++ /dev/null @@ -1,82 +0,0 @@ -// 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. - -'use strict'; - -/** - * @class FunctionSequence to invoke steps in sequence - * - * @param {string} name // TODO(JSDOC). - * @param {Array.<function>} steps Array of functions to invoke in parallel. - * @param {Object} logger // TODO(JSDOC). - * @param {function()} callback Callback to invoke on success. - * @param {function(string)} failureCallback Callback to invoke on failure. - * @constructor - */ -function FunctionParallel(name, steps, logger, callback, failureCallback) { - // Private variables hidden in closure - this.currentStepIdx_ = -1; - this.failed_ = false; - this.steps_ = steps; - this.callback_ = callback; - this.failureCallback_ = failureCallback; - this.logger = logger; - this.name = name; - - this.remaining = this.steps_.length; - - this.nextStep = this.nextStep_.bind(this); - this.onError = this.onError_.bind(this); - this.apply = this.start.bind(this); -} - - -/** - * Error handling function, which fires error callback. - * - * @param {string} err Error message. - * @private - */ -FunctionParallel.prototype.onError_ = function(err) { - if (!this.failed_) { - this.failed_ = true; - this.failureCallback_(err); - } -}; - -/** - * Advances to next step. This method should not be used externally. In external - * cases should be used nextStep function, which is defined in closure and thus - * has access to internal variables of functionsequence. - * - * @private - */ -FunctionParallel.prototype.nextStep_ = function() { - if (--this.remaining == 0 && !this.failed_) { - this.callback_(); - } -}; - -/** - * This function should be called only once on start, so start all the children - * at once - * @param {...} var_args // TODO(JSDOC). - */ -FunctionParallel.prototype.start = function(var_args) { - this.logger.vlog('Starting [' + this.steps_.length + '] parallel tasks ' + - 'with ' + arguments.length + ' argument(s)'); - if (this.logger.verbose) { - for (var j = 0; j < arguments.length; j++) { - this.logger.vlog(arguments[j]); - } - } - for (var i = 0; i < this.steps_.length; i++) { - this.logger.vlog('Attempting to start step [' + this.steps_[i].name + ']'); - try { - this.steps_[i].apply(this, arguments); - } catch (e) { - this.onError(e.toString()); - } - } -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/function_sequence.js b/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/function_sequence.js deleted file mode 100644 index a2372f9f146..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/function_sequence.js +++ /dev/null @@ -1,133 +0,0 @@ -// 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. - -'use strict'; - -/** - * @class FunctionSequence to invoke steps in sequence - * - * @param {string} name // TODO(JSDOC). - * @param {Array} steps array of functions to invoke in sequence. - * @param {Object} logger logger. - * @param {function} callback callback to invoke on success. - * @param {function} failureCallback callback to invoke on failure. - * @constructor - */ -function FunctionSequence(name, steps, logger, callback, failureCallback) { - // Private variables hidden in closure - this.currentStepIdx_ = -1; - this.failed_ = false; - this.steps_ = steps; - this.callback_ = callback; - this.failureCallback_ = failureCallback; - this.logger = logger; - this.name = name; - - this.onError = this.onError_.bind(this); - this.finish = this.finish_.bind(this); - this.nextStep = this.nextStep_.bind(this); - this.apply = this.apply_.bind(this); -} - -/** - * Sets new callback - * - * @param {function} callback new callback to call on succeed. - */ -FunctionSequence.prototype.setCallback = function(callback) { - this.callback_ = callback; -}; - -/** - * Sets new error callback - * - * @param {function} failureCallback new callback to call on failure. - */ -FunctionSequence.prototype.setFailureCallback = function(failureCallback) { - this.failureCallback_ = failureCallback; -}; - - -/** - * Error handling function, which traces current error step, stops sequence - * advancing and fires error callback. - * - * @param {string} err Error message. - * @private - */ -FunctionSequence.prototype.onError_ = function(err) { - this.logger.vlog('Failed step: ' + this.steps_[this.currentStepIdx_].name + - ': ' + err); - if (!this.failed_) { - this.failed_ = true; - this.failureCallback_(err); - } -}; - -/** - * Finishes sequence processing and jumps to the last step. - * This method should not be used externally. In external - * cases should be used finish function, which is defined in closure and thus - * has access to internal variables of functionsequence. - * @private - */ -FunctionSequence.prototype.finish_ = function() { - if (!this.failed_ && this.currentStepIdx_ < this.steps_.length) { - this.currentStepIdx_ = this.steps_.length; - this.callback_(); - } -}; - -/** - * Advances to next step. - * This method should not be used externally. In external - * cases should be used nextStep function, which is defined in closure and thus - * has access to internal variables of functionsequence. - * @private - * @param {...} var_args // TODO(JSDOC). - */ -FunctionSequence.prototype.nextStep_ = function(var_args) { - if (this.failed_) { - return; - } - - if (++this.currentStepIdx_ >= this.steps_.length) { - this.logger.vlog('Sequence ended'); - this.callback_.apply(this, arguments); - } else { - this.logger.vlog('Attempting to start step [' + - this.steps_[this.currentStepIdx_].name + - ']'); - try { - this.steps_[this.currentStepIdx_].apply(this, arguments); - } catch (e) { - this.onError(e.toString()); - } - } -}; - -/** - * This function should be called only once on start, so start sequence pipeline - * @param {...} var_args // TODO(JSDOC). - */ -FunctionSequence.prototype.start = function(var_args) { - if (this.started) { - throw new Error('"Start" method of FunctionSequence was called twice'); - } - - this.logger.log('Starting sequence with ' + arguments.length + ' arguments'); - - this.started = true; - this.nextStep.apply(this, arguments); -}; - -/** - * Add Function object mimics to FunctionSequence - * @private - * @param {*} obj // TODO(JSDOC). - * @param {Array.*} args // TODO(JSDOC). - */ -FunctionSequence.prototype.apply_ = function(obj, args) { - this.start.apply(this, args); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/id3_parser.js b/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/id3_parser.js deleted file mode 100644 index 4037d02e43e..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/id3_parser.js +++ /dev/null @@ -1,708 +0,0 @@ -// 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. - -'use strict'; - -importScripts('function_sequence.js'); -importScripts('function_parallel.js'); - -function Id3Parser(parent) { - MetadataParser.call(this, parent, 'id3', /\.(mp3)$/i); -} - -Id3Parser.prototype = {__proto__: MetadataParser.prototype}; - -/** - * Reads synchsafe integer. - * 'SynchSafe' term is taken from id3 documentation. - * - * @param {ByteReader} reader - reader to use. - * @param {number} length - bytes to read. - * @return {number} // TODO(JSDOC). - * @private - */ -Id3Parser.readSynchSafe_ = function(reader, length) { - var rv = 0; - - switch (length) { - case 4: - rv = reader.readScalar(1, false) << 21; - case 3: - rv |= reader.readScalar(1, false) << 14; - case 2: - rv |= reader.readScalar(1, false) << 7; - case 1: - rv |= reader.readScalar(1, false); - } - - return rv; -}; - -/** - * Reads 3bytes integer. - * - * @param {ByteReader} reader - reader to use. - * @return {number} // TODO(JSDOC). - * @private - */ -Id3Parser.readUInt24_ = function(reader) { - return reader.readScalar(2, false) << 16 | reader.readScalar(1, false); -}; - -/** - * Reads string from reader with specified encoding - * - * @param {ByteReader} reader reader to use. - * @param {number} encoding string encoding. - * @param {number} size maximum string size. Actual result may be shorter. - * @return {string} // TODO(JSDOC). - * @private - */ -Id3Parser.prototype.readString_ = function(reader, encoding, size) { - switch (encoding) { - case Id3Parser.v2.ENCODING.ISO_8859_1: - return reader.readNullTerminatedString(size); - - case Id3Parser.v2.ENCODING.UTF_16: - return reader.readNullTerminatedStringUTF16(true, size); - - case Id3Parser.v2.ENCODING.UTF_16BE: - return reader.readNullTerminatedStringUTF16(false, size); - - case Id3Parser.v2.ENCODING.UTF_8: - // TODO: implement UTF_8. - this.log('UTF8 encoding not supported, used ISO_8859_1 instead'); - return reader.readNullTerminatedString(size); - - default: { - this.log('Unsupported encoding in ID3 tag: ' + encoding); - return ''; - } - } -}; - -/** - * Reads text frame from reader. - * - * @param {ByteReader} reader reader to use. - * @param {number} majorVersion major id3 version to use. - * @param {Object} frame frame so store data at. - * @param {number} end frame end position in reader. - * @private - */ -Id3Parser.prototype.readTextFrame_ = function(reader, - majorVersion, - frame, - end) { - frame.encoding = reader.readScalar(1, false, end); - frame.value = this.readString_(reader, frame.encoding, end - reader.tell()); -}; - -/** - * Reads user defined text frame from reader. - * - * @param {ByteReader} reader reader to use. - * @param {number} majorVersion major id3 version to use. - * @param {Object} frame frame so store data at. - * @param {number} end frame end position in reader. - * @private - */ -Id3Parser.prototype.readUserDefinedTextFrame_ = function(reader, - majorVersion, - frame, - end) { - frame.encoding = reader.readScalar(1, false, end); - - frame.description = this.readString_( - reader, - frame.encoding, - end - reader.tell()); - - frame.value = this.readString_( - reader, - frame.encoding, - end - reader.tell()); -}; - -/** - * @param {ByteReader} reader Reader to use. - * @param {number} majorVersion Major id3 version to use. - * @param {Object} frame Frame so store data at. - * @param {number} end Frame end position in reader. - * @private - */ -Id3Parser.prototype.readPIC_ = function(reader, majorVersion, frame, end) { - frame.encoding = reader.readScalar(1, false, end); - frame.format = reader.readNullTerminatedString(3, end - reader.tell()); - frame.pictureType = reader.readScalar(1, false, end); - frame.description = this.readString_(reader, - frame.encoding, - end - reader.tell()); - - - if (frame.format == '-->') { - frame.imageUrl = reader.readNullTerminatedString(end - reader.tell()); - } else { - frame.imageUrl = reader.readImage(end - reader.tell()); - } -}; - -/** - * @param {ByteReader} reader Reader to use. - * @param {number} majorVersion Major id3 version to use. - * @param {Object} frame Frame so store data at. - * @param {number} end Frame end position in reader. - * @private - */ -Id3Parser.prototype.readAPIC_ = function(reader, majorVersion, frame, end) { - this.vlog('Extracting picture'); - frame.encoding = reader.readScalar(1, false, end); - frame.mime = reader.readNullTerminatedString(end - reader.tell()); - frame.pictureType = reader.readScalar(1, false, end); - frame.description = this.readString_( - reader, - frame.encoding, - end - reader.tell()); - - if (frame.mime == '-->') { - frame.imageUrl = reader.readNullTerminatedString(end - reader.tell()); - } else { - frame.imageUrl = reader.readImage(end - reader.tell()); - } -}; - -/** - * Reads string from reader with specified encoding - * - * @param {ByteReader} reader reader to use. - * @param {number} majorVersion // TODO(JSDOC). - * @return {Object} frame read. - * @private - */ -Id3Parser.prototype.readFrame_ = function(reader, majorVersion) { - if (reader.eof()) - return null; - - var frame = {}; - - reader.pushSeek(reader.tell(), ByteReader.SEEK_BEG); - - var position = reader.tell(); - - frame.name = (majorVersion == 2) ? reader.readNullTerminatedString(3) : - reader.readNullTerminatedString(4); - - if (frame.name == '') - return null; - - this.vlog('Found frame ' + (frame.name) + ' at position ' + position); - - switch (majorVersion) { - case 2: - frame.size = Id3Parser.readUInt24_(reader); - frame.headerSize = 6; - break; - case 3: - frame.size = reader.readScalar(4, false); - frame.headerSize = 10; - frame.flags = reader.readScalar(2, false); - break; - case 4: - frame.size = Id3Parser.readSynchSafe_(reader, 4); - frame.headerSize = 10; - frame.flags = reader.readScalar(2, false); - break; - } - - this.vlog('Found frame [' + frame.name + '] with size [' + frame.size + ']'); - - if (Id3Parser.v2.HANDLERS[frame.name]) { - Id3Parser.v2.HANDLERS[frame.name].call( - this, - reader, - majorVersion, - frame, - reader.tell() + frame.size); - } else if (frame.name.charAt(0) == 'T' || frame.name.charAt(0) == 'W') { - this.readTextFrame_( - reader, - majorVersion, - frame, - reader.tell() + frame.size); - } - - reader.popSeek(); - - reader.seek(frame.size + frame.headerSize, ByteReader.SEEK_CUR); - - return frame; -}; - -/** - * @param {File} file // TODO(JSDOC). - * @param {Object} metadata // TODO(JSDOC). - * @param {function(Object)} callback // TODO(JSDOC). - * @param {function(etring)} onError // TODO(JSDOC). - */ -Id3Parser.prototype.parse = function(file, metadata, callback, onError) { - var self = this; - - this.log('Starting id3 parser for ' + file.name); - - var id3v1Parser = new FunctionSequence( - 'id3v1parser', - [ - /** - * Reads last 128 bytes of file in bytebuffer, - * which passes further. - * In last 128 bytes should be placed ID3v1 tag if available. - * @param {File} file File which bytes to read. - */ - function readTail(file) { - util.readFileBytes(file, file.size - 128, file.size, - this.nextStep, this.onError, this); - }, - - /** - * Attempts to extract ID3v1 tag from 128 bytes long ByteBuffer - * @param {File} file File which tags are being extracted. Could be used - * for logging purposes. - * @param {ByteReader} reader ByteReader of 128 bytes. - */ - function extractId3v1(file, reader) { - if (reader.readString(3) == 'TAG') { - this.logger.vlog('id3v1 found'); - var id3v1 = metadata.id3v1 = {}; - - var title = reader.readNullTerminatedString(30).trim(); - - if (title.length > 0) { - metadata.title = title; - } - - reader.seek(3 + 30, ByteReader.SEEK_BEG); - - var artist = reader.readNullTerminatedString(30).trim(); - if (artist.length > 0) { - metadata.artist = artist; - } - - reader.seek(3 + 30 + 30, ByteReader.SEEK_BEG); - - var album = reader.readNullTerminatedString(30).trim(); - if (album.length > 0) { - metadata.album = album; - } - } - this.nextStep(); - } - ], - this - ); - - var id3v2Parser = new FunctionSequence( - 'id3v2parser', - [ - function readHead(file) { - util.readFileBytes(file, 0, 10, this.nextStep, this.onError, - this); - }, - - /** - * Check if passed array of 10 bytes contains ID3 header. - * @param {File} file File to check and continue reading if ID3 - * metadata found. - * @param {ByteReader} reader Reader to fill with stream bytes. - */ - function checkId3v2(file, reader) { - if (reader.readString(3) == 'ID3') { - this.logger.vlog('id3v2 found'); - var id3v2 = metadata.id3v2 = {}; - id3v2.major = reader.readScalar(1, false); - id3v2.minor = reader.readScalar(1, false); - id3v2.flags = reader.readScalar(1, false); - id3v2.size = Id3Parser.readSynchSafe_(reader, 4); - - util.readFileBytes(file, 10, 10 + id3v2.size, this.nextStep, - this.onError, this); - } else { - this.finish(); - } - }, - - /** - * Extracts all ID3v2 frames from given bytebuffer. - * @param {File} file File being parsed. - * @param {ByteReader} reader Reader to use for metadata extraction. - */ - function extractFrames(file, reader) { - var id3v2 = metadata.id3v2; - - if ((id3v2.major > 2) && - (id3v2.flags & Id3Parser.v2.FLAG_EXTENDED_HEADER != 0)) { - // Skip extended header if found - if (id3v2.major == 3) { - reader.seek(reader.readScalar(4, false) - 4); - } else if (id3v2.major == 4) { - reader.seek(Id3Parser.readSynchSafe_(reader, 4) - 4); - } - } - - var frame; - - while (frame = self.readFrame_(reader, id3v2.major)) { - metadata.id3v2[frame.name] = frame; - } - - this.nextStep(); - }, - - /** - * Adds 'description' object to metadata. - * 'description' used to unify different parsers and make - * metadata parser-aware. - * Description is array if value-type pairs. Type should be used - * to properly format value before displaying to user. - */ - function prepareDescription() { - var id3v2 = metadata.id3v2; - - if (id3v2['APIC']) - metadata.thumbnailURL = id3v2['APIC'].imageUrl; - else if (id3v2['PIC']) - metadata.thumbnailURL = id3v2['PIC'].imageUrl; - - metadata.description = []; - - for (var key in id3v2) { - if (typeof(Id3Parser.v2.MAPPERS[key]) != 'undefined' && - id3v2[key].value.trim().length > 0) { - metadata.description.push({ - key: Id3Parser.v2.MAPPERS[key], - value: id3v2[key].value.trim() - }); - } - } - - function extract(propName, tags) { - for (var i = 1; i != arguments.length; i++) { - var tag = id3v2[arguments[i]]; - if (tag && tag.value) { - metadata[propName] = tag.value; - break; - } - } - } - - extract('album', 'TALB', 'TAL'); - extract('title', 'TIT2', 'TT2'); - extract('artist', 'TPE1', 'TP1'); - - metadata.description.sort(function(a, b) { - return Id3Parser.METADATA_ORDER.indexOf(a.key) - - Id3Parser.METADATA_ORDER.indexOf(b.key); - }); - this.nextStep(); - } - ], - this - ); - - var metadataParser = new FunctionParallel( - 'mp3metadataParser', - [id3v1Parser, id3v2Parser], - this, - function() { - callback.call(null, metadata); - }, - onError - ); - - id3v1Parser.setCallback(metadataParser.nextStep); - id3v2Parser.setCallback(metadataParser.nextStep); - - id3v1Parser.setFailureCallback(metadataParser.onError); - id3v2Parser.setFailureCallback(metadataParser.onError); - - this.vlog('Passed argument : ' + file); - - metadataParser.start(file); -}; - - -/** - * Metadata order to use for metadata generation - */ -Id3Parser.METADATA_ORDER = [ - 'ID3_TITLE', - 'ID3_LEAD_PERFORMER', - 'ID3_YEAR', - 'ID3_ALBUM', - 'ID3_TRACK_NUMBER', - 'ID3_BPM', - 'ID3_COMPOSER', - 'ID3_DATE', - 'ID3_PLAYLIST_DELAY', - 'ID3_LYRICIST', - 'ID3_FILE_TYPE', - 'ID3_TIME', - 'ID3_LENGTH', - 'ID3_FILE_OWNER', - 'ID3_BAND', - 'ID3_COPYRIGHT', - 'ID3_OFFICIAL_AUDIO_FILE_WEBPAGE', - 'ID3_OFFICIAL_ARTIST', - 'ID3_OFFICIAL_AUDIO_SOURCE_WEBPAGE', - 'ID3_PUBLISHERS_OFFICIAL_WEBPAGE' -]; - - -/** - * id3v1 constants - */ -Id3Parser.v1 = { - /** - * Genres list as described in id3 documentation. We aren't going to - * localize this list, because at least in Russian (and I think most - * other languages), translation exists at least for 10% and most time - * translation would degrade to transliteration. - */ - GENRES: [ - 'Blues', - 'Classic Rock', - 'Country', - 'Dance', - 'Disco', - 'Funk', - 'Grunge', - 'Hip-Hop', - 'Jazz', - 'Metal', - 'New Age', - 'Oldies', - 'Other', - 'Pop', - 'R&B', - 'Rap', - 'Reggae', - 'Rock', - 'Techno', - 'Industrial', - 'Alternative', - 'Ska', - 'Death Metal', - 'Pranks', - 'Soundtrack', - 'Euro-Techno', - 'Ambient', - 'Trip-Hop', - 'Vocal', - 'Jazz+Funk', - 'Fusion', - 'Trance', - 'Classical', - 'Instrumental', - 'Acid', - 'House', - 'Game', - 'Sound Clip', - 'Gospel', - 'Noise', - 'AlternRock', - 'Bass', - 'Soul', - 'Punk', - 'Space', - 'Meditative', - 'Instrumental Pop', - 'Instrumental Rock', - 'Ethnic', - 'Gothic', - 'Darkwave', - 'Techno-Industrial', - 'Electronic', - 'Pop-Folk', - 'Eurodance', - 'Dream', - 'Southern Rock', - 'Comedy', - 'Cult', - 'Gangsta', - 'Top 40', - 'Christian Rap', - 'Pop/Funk', - 'Jungle', - 'Native American', - 'Cabaret', - 'New Wave', - 'Psychadelic', - 'Rave', - 'Showtunes', - 'Trailer', - 'Lo-Fi', - 'Tribal', - 'Acid Punk', - 'Acid Jazz', - 'Polka', - 'Retro', - 'Musical', - 'Rock & Roll', - 'Hard Rock', - 'Folk', - 'Folk-Rock', - 'National Folk', - 'Swing', - 'Fast Fusion', - 'Bebob', - 'Latin', - 'Revival', - 'Celtic', - 'Bluegrass', - 'Avantgarde', - 'Gothic Rock', - 'Progressive Rock', - 'Psychedelic Rock', - 'Symphonic Rock', - 'Slow Rock', - 'Big Band', - 'Chorus', - 'Easy Listening', - 'Acoustic', - 'Humour', - 'Speech', - 'Chanson', - 'Opera', - 'Chamber Music', - 'Sonata', - 'Symphony', - 'Booty Bass', - 'Primus', - 'Porn Groove', - 'Satire', - 'Slow Jam', - 'Club', - 'Tango', - 'Samba', - 'Folklore', - 'Ballad', - 'Power Ballad', - 'Rhythmic Soul', - 'Freestyle', - 'Duet', - 'Punk Rock', - 'Drum Solo', - 'A capella', - 'Euro-House', - 'Dance Hall', - 'Goa', - 'Drum & Bass', - 'Club-House', - 'Hardcore', - 'Terror', - 'Indie', - 'BritPop', - 'Negerpunk', - 'Polsk Punk', - 'Beat', - 'Christian Gangsta Rap', - 'Heavy Metal', - 'Black Metal', - 'Crossover', - 'Contemporary Christian', - 'Christian Rock', - 'Merengue', - 'Salsa', - 'Thrash Metal', - 'Anime', - 'Jpop', - 'Synthpop' - ] -}; - -/** - * id3v2 constants - */ -Id3Parser.v2 = { - FLAG_EXTENDED_HEADER: 1 << 5, - - ENCODING: { - /** - * ISO-8859-1 [ISO-8859-1]. Terminated with $00. - * - * @const - * @type {number} - */ - ISO_8859_1: 0, - - - /** - * [UTF-16] encoded Unicode [UNICODE] with BOM. All - * strings in the same frame SHALL have the same byteorder. - * Terminated with $00 00. - * - * @const - * @type {number} - */ - UTF_16: 1, - - /** - * UTF-16BE [UTF-16] encoded Unicode [UNICODE] without BOM. - * Terminated with $00 00. - * - * @const - * @type {number} - */ - UTF_16BE: 2, - - /** - * UTF-8 [UTF-8] encoded Unicode [UNICODE]. Terminated with $00. - * - * @const - * @type {number} - */ - UTF_8: 3 - }, - HANDLERS: { - //User defined text information frame - TXX: Id3Parser.prototype.readUserDefinedTextFrame_, - //User defined URL link frame - WXX: Id3Parser.prototype.readUserDefinedTextFrame_, - - //User defined text information frame - TXXX: Id3Parser.prototype.readUserDefinedTextFrame_, - - //User defined URL link frame - WXXX: Id3Parser.prototype.readUserDefinedTextFrame_, - - //User attached image - PIC: Id3Parser.prototype.readPIC_, - - //User attached image - APIC: Id3Parser.prototype.readAPIC_ - }, - MAPPERS: { - TALB: 'ID3_ALBUM', - TBPM: 'ID3_BPM', - TCOM: 'ID3_COMPOSER', - TDAT: 'ID3_DATE', - TDLY: 'ID3_PLAYLIST_DELAY', - TEXT: 'ID3_LYRICIST', - TFLT: 'ID3_FILE_TYPE', - TIME: 'ID3_TIME', - TIT2: 'ID3_TITLE', - TLEN: 'ID3_LENGTH', - TOWN: 'ID3_FILE_OWNER', - TPE1: 'ID3_LEAD_PERFORMER', - TPE2: 'ID3_BAND', - TRCK: 'ID3_TRACK_NUMBER', - TYER: 'ID3_YEAR', - WCOP: 'ID3_COPYRIGHT', - WOAF: 'ID3_OFFICIAL_AUDIO_FILE_WEBPAGE', - WOAR: 'ID3_OFFICIAL_ARTIST', - WOAS: 'ID3_OFFICIAL_AUDIO_SOURCE_WEBPAGE', - WPUB: 'ID3_PUBLISHERS_OFFICIAL_WEBPAGE' - } -}; - -MetadataDispatcher.registerParserClass(Id3Parser); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/image_parsers.js b/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/image_parsers.js deleted file mode 100644 index 52c4fc4e8a8..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/image_parsers.js +++ /dev/null @@ -1,198 +0,0 @@ -// 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. - -'use strict'; - -/* Base class for image metadata parsers that only need to look at a short - fragment at the start of the file */ -function SimpleImageParser(parent, type, urlFilter, headerSize) { - ImageParser.call(this, parent, type, urlFilter); - this.headerSize = headerSize; -} - -SimpleImageParser.prototype = {__proto__: ImageParser.prototype}; - -/** - * @param {File} file // TODO(JSDOC). - * @param {Object} metadata // TODO(JSDOC). - * @param {function(Object)} callback // TODO(JSDOC). - * @param {function(string)} errorCallback // TODO(JSDOC). - */ -SimpleImageParser.prototype.parse = function( - file, metadata, callback, errorCallback) { - var self = this; - util.readFileBytes(file, 0, this.headerSize, - function(file, br) { - try { - self.parseHeader(metadata, br); - callback(metadata); - } catch (e) { - errorCallback(e.toString()); - } - }, - errorCallback); -}; - - -function PngParser(parent) { - SimpleImageParser.call(this, parent, 'png', /\.png$/i, 24); -} - -PngParser.prototype = {__proto__: SimpleImageParser.prototype}; - -/** - * @param {Object} metadata // TODO(JSDOC). - * @param {ByteReader} br // TODO(JSDOC). - */ -PngParser.prototype.parseHeader = function(metadata, br) { - br.setByteOrder(ByteReader.BIG_ENDIAN); - - var signature = br.readString(8); - if (signature != '\x89PNG\x0D\x0A\x1A\x0A') - throw new Error('Invalid PNG signature: ' + signature); - - br.seek(12); - var ihdr = br.readString(4); - if (ihdr != 'IHDR') - throw new Error('Missing IHDR chunk'); - - metadata.width = br.readScalar(4); - metadata.height = br.readScalar(4); -}; - -MetadataDispatcher.registerParserClass(PngParser); - - -function BmpParser(parent) { - SimpleImageParser.call(this, parent, 'bmp', /\.bmp$/i, 28); -} - -BmpParser.prototype = {__proto__: SimpleImageParser.prototype}; - -/** - * @param {Object} metadata // TODO(JSDOC). - * @param {ByteReader} br // TODO(JSDOC). - */ -BmpParser.prototype.parseHeader = function(metadata, br) { - br.setByteOrder(ByteReader.LITTLE_ENDIAN); - - var signature = br.readString(2); - if (signature != 'BM') - throw new Error('Invalid BMP signature: ' + signature); - - br.seek(18); - metadata.width = br.readScalar(4); - metadata.height = br.readScalar(4); -}; - -MetadataDispatcher.registerParserClass(BmpParser); - - -function GifParser(parent) { - SimpleImageParser.call(this, parent, 'gif', /\.Gif$/i, 10); -} - -GifParser.prototype = {__proto__: SimpleImageParser.prototype}; - -/** - * @param {Object} metadata // TODO(JSDOC). - * @param {ByteReader} br // TODO(JSDOC). - */ -GifParser.prototype.parseHeader = function(metadata, br) { - br.setByteOrder(ByteReader.LITTLE_ENDIAN); - - var signature = br.readString(6); - if (!signature.match(/GIF8(7|9)a/)) - throw new Error('Invalid GIF signature: ' + signature); - - metadata.width = br.readScalar(2); - metadata.height = br.readScalar(2); -}; - -MetadataDispatcher.registerParserClass(GifParser); - - -function WebpParser(parent) { - SimpleImageParser.call(this, parent, 'webp', /\.webp$/i, 30); -} - -WebpParser.prototype = {__proto__: SimpleImageParser.prototype}; - -/** - * @param {Object} metadata // TODO(JSDOC). - * @param {ByteReader} br // TODO(JSDOC). - */ -WebpParser.prototype.parseHeader = function(metadata, br) { - br.setByteOrder(ByteReader.LITTLE_ENDIAN); - - var riffSignature = br.readString(4); - if (riffSignature != 'RIFF') - throw new Error('Invalid RIFF signature: ' + riffSignature); - - br.seek(8); - var webpSignature = br.readString(4); - if (webpSignature != 'WEBP') - throw new Error('Invalid WEBP signature: ' + webpSignature); - - var chunkFormat = br.readString(4); - if (chunkFormat != 'VP8 ' && chunkFormat != 'VP8L') - throw new Error('Invalid chunk format: ' + chunkFormat); - - if (chunkFormat == 'VP8 ') { - // VP8 lossy bitstream format. - br.seek(23); - var lossySignature = br.readScalar(2) | (br.readScalar(1) << 16); - if (lossySignature != 0x2a019d) - throw new Error('Invalid VP8 lossy bitstream signature: ' + - lossySignature); - - var dimensionBits = br.readScalar(4); - metadata.width = dimensionBits & 0x3fff; - metadata.height = (dimensionBits >> 16) & 0x3fff; - } else { - // VP8 lossless bitstream format. - br.seek(20); - var losslessSignature = br.readScalar(1); - if (losslessSignature != 0x2f) - throw new Error('Invalid VP8 lossless bitstream signature: ' + - losslessSignature); - - var dimensionBits = br.readScalar(4); - metadata.width = (dimensionBits & 0x3fff) + 1; - metadata.height = ((dimensionBits >> 14) & 0x3fff) + 1; - } -}; - -MetadataDispatcher.registerParserClass(WebpParser); - -/** - * Parser for the header of .ico icon files. - * @param {MetadataDispatcher} parent Parent metadata dispatcher object. - * @constructor - * @extends SimpleImageParser - */ -function IcoParser(parent) { - SimpleImageParser.call(this, parent, 'ico', /\.ico$/i, 8); -} - -IcoParser.prototype = {__proto__: SimpleImageParser.prototype}; - -/** - * Parse the binary data as a ico header and stores to metadata. - * @param {Object} metadata Dictionary to store the parser metadata. - * @param {ByteReader} byteReader Reader for header binary data. - */ -IcoParser.prototype.parseHeader = function(metadata, byteReader) { - byteReader.setByteOrder(ByteReader.LITTLE_ENDIAN); - - var signature = byteReader.readString(4); - if (signature !== '\x00\x00\x00\x01') - throw new Error('Invalid ICO signature: ' + signature); - - byteReader.seek(2); - metadata.width = byteReader.readScalar(1); - metadata.height = byteReader.readScalar(1); -}; - -MetadataDispatcher.registerParserClass(IcoParser); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_cache.js b/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_cache.js deleted file mode 100644 index 4bbbe182958..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_cache.js +++ /dev/null @@ -1,1042 +0,0 @@ -// 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. - -'use strict'; - -/** - * MetadataCache is a map from Entry to an object containing properties. - * Properties are divided by types, and all properties of one type are accessed - * at once. - * Some of the properties: - * { - * filesystem: size, modificationTime - * internal: presence - * drive: pinned, present, hosted, availableOffline - * streaming: (no property) - * - * Following are not fetched for non-present drive files. - * media: artist, album, title, width, height, imageTransform, etc. - * thumbnail: url, transform - * - * Following are always fetched from content, and so force the downloading - * of remote drive files. One should use this for required content metadata, - * i.e. image orientation. - * fetchedMedia: width, height, etc. - * } - * - * Typical usages: - * { - * cache.get([entry1, entry2], 'drive|filesystem', function(metadata) { - * if (metadata[0].drive.pinned && metadata[1].filesystem.size == 0) - * alert("Pinned and empty!"); - * }); - * - * cache.set(entry, 'internal', {presence: 'deleted'}); - * - * cache.clear([fileEntry1, fileEntry2], 'filesystem'); - * - * // Getting fresh value. - * cache.clear(entry, 'thumbnail'); - * cache.get(entry, 'thumbnail', function(thumbnail) { - * img.src = thumbnail.url; - * }); - * - * var cached = cache.getCached(entry, 'filesystem'); - * var size = (cached && cached.size) || UNKNOWN_SIZE; - * } - * - * @constructor - */ -function MetadataCache() { - /** - * Map from Entry (using Entry.toURL) to metadata. Metadata contains - * |properties| - an hierarchical object of values, and an object for each - * metadata provider: <prodiver-id>: {time, callbacks} - * @private - */ - this.cache_ = {}; - - /** - * List of metadata providers. - * @private - */ - this.providers_ = []; - - /** - * List of observers added. Each one is an object with fields: - * re - regexp of urls; - * type - metadata type; - * callback - the callback. - * @private - */ - this.observers_ = []; - this.observerId_ = 0; - - this.batchCount_ = 0; - this.totalCount_ = 0; - - this.currentCacheSize_ = 0; - - /** - * Time of first get query of the current batch. Items updated later than this - * will not be evicted. - * @private - */ - this.lastBatchStart_ = new Date(); -} - -/** - * Observer type: it will be notified if the changed Entry is exactly the same - * as the observed Entry. - */ -MetadataCache.EXACT = 0; - -/** - * Observer type: it will be notified if the changed Entry is an immediate child - * of the observed Entry. - */ -MetadataCache.CHILDREN = 1; - -/** - * Observer type: it will be notified if the changed Entry is a descendant of - * of the observer Entry. - */ -MetadataCache.DESCENDANTS = 2; - -/** - * Margin of the cache size. This amount of caches may be kept in addition. - */ -MetadataCache.EVICTION_THRESHOLD_MARGIN = 500; - -/** - * @return {MetadataCache!} The cache with all providers. - */ -MetadataCache.createFull = function() { - var cache = new MetadataCache(); - cache.providers_.push(new FilesystemProvider()); - cache.providers_.push(new DriveProvider()); - cache.providers_.push(new ContentProvider()); - return cache; -}; - -/** - * Clones metadata entry. Metadata entries may contain scalars, arrays, - * hash arrays and Date object. Other objects are not supported. - * @param {Object} metadata Metadata object. - * @return {Object} Cloned entry. - */ -MetadataCache.cloneMetadata = function(metadata) { - if (metadata instanceof Array) { - var result = []; - for (var index = 0; index < metadata.length; index++) { - result[index] = MetadataCache.cloneMetadata(metadata[index]); - } - return result; - } else if (metadata instanceof Date) { - var result = new Date(); - result.setTime(metadata.getTime()); - return result; - } else if (metadata instanceof Object) { // Hash array only. - var result = {}; - for (var property in metadata) { - if (metadata.hasOwnProperty(property)) - result[property] = MetadataCache.cloneMetadata(metadata[property]); - } - return result; - } else { - return metadata; - } -}; - -/** - * @return {boolean} Whether all providers are ready. - */ -MetadataCache.prototype.isInitialized = function() { - for (var index = 0; index < this.providers_.length; index++) { - if (!this.providers_[index].isInitialized()) return false; - } - return true; -}; - -/** - * Sets the size of cache. The actual cache size may be larger than the given - * value. - * @param {number} size The cache size to be set. - */ -MetadataCache.prototype.setCacheSize = function(size) { - this.currentCacheSize_ = size; - - if (this.totalCount_ > this.currentEvictionThreshold_()) - this.evict_(); -}; - -/** - * Returns the current threshold to evict caches. When the number of caches - * exceeds this, the cache should be evicted. - * @return {number} Threshold to evict caches. - * @private - */ -MetadataCache.prototype.currentEvictionThreshold_ = function() { - return this.currentCacheSize_ * 2 + MetadataCache.EVICTION_THRESHOLD_MARGIN; -}; - -/** - * Fetches the metadata, puts it in the cache, and passes to callback. - * If required metadata is already in the cache, does not fetch it again. - * @param {Entry|Array.<Entry>} entries The list of entries. May be just a - * single item. - * @param {string} type The metadata type. - * @param {function(Object)} callback The metadata is passed to callback. - */ -MetadataCache.prototype.get = function(entries, type, callback) { - if (!(entries instanceof Array)) { - this.getOne(entries, type, callback); - return; - } - - if (entries.length == 0) { - if (callback) callback([]); - return; - } - - var result = []; - var remaining = entries.length; - this.startBatchUpdates(); - - var onOneItem = function(index, value) { - result[index] = value; - remaining--; - if (remaining == 0) { - this.endBatchUpdates(); - if (callback) setTimeout(callback, 0, result); - } - }; - - for (var index = 0; index < entries.length; index++) { - result.push(null); - this.getOne(entries[index], type, onOneItem.bind(this, index)); - } -}; - -/** - * Fetches the metadata for one Entry. See comments to |get|. - * @param {Entry} entry The entry. - * @param {string} type Metadata type. - * @param {function(Object)} callback The callback. - */ -MetadataCache.prototype.getOne = function(entry, type, callback) { - if (type.indexOf('|') != -1) { - var types = type.split('|'); - var result = {}; - var typesLeft = types.length; - - var onOneType = function(requestedType, metadata) { - result[requestedType] = metadata; - typesLeft--; - if (typesLeft == 0) callback(result); - }; - - for (var index = 0; index < types.length; index++) { - this.getOne(entry, types[index], onOneType.bind(null, types[index])); - } - return; - } - - callback = callback || function() {}; - - var entryURL = entry.toURL(); - if (!(entryURL in this.cache_)) { - this.cache_[entryURL] = this.createEmptyItem_(); - this.totalCount_++; - } - - var item = this.cache_[entryURL]; - - if (type in item.properties) { - callback(item.properties[type]); - return; - } - - this.startBatchUpdates(); - var providers = this.providers_.slice(); - var currentProvider; - var self = this; - - var onFetched = function() { - if (type in item.properties) { - self.endBatchUpdates(); - // Got properties from provider. - callback(item.properties[type]); - } else { - tryNextProvider(); - } - }; - - var onProviderProperties = function(properties) { - var id = currentProvider.getId(); - var fetchedCallbacks = item[id].callbacks; - delete item[id].callbacks; - item.time = new Date(); - self.mergeProperties_(entry, properties); - - for (var index = 0; index < fetchedCallbacks.length; index++) { - fetchedCallbacks[index](); - } - }; - - var queryProvider = function() { - var id = currentProvider.getId(); - if ('callbacks' in item[id]) { - // We are querying this provider now. - item[id].callbacks.push(onFetched); - } else { - item[id].callbacks = [onFetched]; - currentProvider.fetch(entry, type, onProviderProperties); - } - }; - - var tryNextProvider = function() { - if (providers.length == 0) { - self.endBatchUpdates(); - callback(item.properties[type] || null); - return; - } - - currentProvider = providers.shift(); - if (currentProvider.supportsEntry(entry) && - currentProvider.providesType(type)) { - queryProvider(); - } else { - tryNextProvider(); - } - }; - - tryNextProvider(); -}; - -/** - * Returns the cached metadata value, or |null| if not present. - * @param {Entry|Array.<Entry>} entries The list of entries. May be just a - * single entry. - * @param {string} type The metadata type. - * @return {Object} The metadata or null. - */ -MetadataCache.prototype.getCached = function(entries, type) { - var single = false; - if (!(entries instanceof Array)) { - single = true; - entries = [entries]; - } - - var result = []; - for (var index = 0; index < entries.length; index++) { - var entryURL = entries[index].toURL(); - result.push(entryURL in this.cache_ ? - (this.cache_[entryURL].properties[type] || null) : null); - } - - return single ? result[0] : result; -}; - -/** - * Puts the metadata into cache - * @param {Entry|Array.<Entry>} entries The list of entries. May be just a - * single entry. - * @param {string} type The metadata type. - * @param {Array.<Object>} values List of corresponding metadata values. - */ -MetadataCache.prototype.set = function(entries, type, values) { - if (!(entries instanceof Array)) { - entries = [entries]; - values = [values]; - } - - this.startBatchUpdates(); - for (var index = 0; index < entries.length; index++) { - var entryURL = entries[index].toURL(); - if (!(entryURL in this.cache_)) { - this.cache_[entryURL] = this.createEmptyItem_(); - this.totalCount_++; - } - this.cache_[entryURL].properties[type] = values[index]; - this.notifyObservers_(entries[index], type); - } - this.endBatchUpdates(); -}; - -/** - * Clears the cached metadata values. - * @param {Entry|Array.<Entry>} entries The list of entries. May be just a - * single entry. - * @param {string} type The metadata types or * for any type. - */ -MetadataCache.prototype.clear = function(entries, type) { - if (!(entries instanceof Array)) - entries = [entries]; - - var types = type.split('|'); - - for (var index = 0; index < entries.length; index++) { - var entry = entries[index]; - var entryURL = entry.toURL(); - if (entryURL in this.cache_) { - if (type === '*') { - this.cache_[entryURL].properties = {}; - } else { - for (var j = 0; j < types.length; j++) { - var type = types[j]; - delete this.cache_[entryURL].properties[type]; - } - } - } - } -}; - -/** - * Clears the cached metadata values recursively. - * @param {Entry} entry An entry to be cleared recursively from cache. - * @param {string} type The metadata types or * for any type. - */ -MetadataCache.prototype.clearRecursively = function(entry, type) { - var types = type.split('|'); - var keys = Object.keys(this.cache_); - var entryURL = entry.toURL(); - - for (var index = 0; index < keys.length; index++) { - var cachedEntryURL = keys[index]; - if (cachedEntryURL.substring(0, entryURL.length) === entryURL) { - if (type === '*') { - this.cache_[cachedEntryURL].properties = {}; - } else { - for (var j = 0; j < types.length; j++) { - var type = types[j]; - delete this.cache_[cachedEntryURL].properties[type]; - } - } - } - } -}; - -/** - * Adds an observer, which will be notified when metadata changes. - * @param {Entry} entry The root entry to look at. - * @param {number} relation This defines, which items will trigger the observer. - * See comments to |MetadataCache.EXACT| and others. - * @param {string} type The metadata type. - * @param {function(Array.<Entry>, Array.<Object>)} observer List of entries - * and corresponding metadata values are passed to this callback. - * @return {number} The observer id, which can be used to remove it. - */ -MetadataCache.prototype.addObserver = function( - entry, relation, type, observer) { - var entryURL = entry.toURL(); - var re; - if (relation == MetadataCache.CHILDREN) - re = entryURL + '(/[^/]*)?'; - else if (relation == MetadataCache.DESCENDANTS) - re = entryURL + '(/.*)?'; - else - re = entryURL; - - var id = ++this.observerId_; - this.observers_.push({ - re: new RegExp('^' + re + '$'), - type: type, - callback: observer, - id: id, - pending: {} - }); - - return id; -}; - -/** - * Removes the observer. - * @param {number} id Observer id. - * @return {boolean} Whether observer was removed or not. - */ -MetadataCache.prototype.removeObserver = function(id) { - for (var index = 0; index < this.observers_.length; index++) { - if (this.observers_[index].id == id) { - this.observers_.splice(index, 1); - return true; - } - } - return false; -}; - -/** - * Start batch updates. - */ -MetadataCache.prototype.startBatchUpdates = function() { - this.batchCount_++; - if (this.batchCount_ == 1) - this.lastBatchStart_ = new Date(); -}; - -/** - * End batch updates. Notifies observers if all nested updates are finished. - */ -MetadataCache.prototype.endBatchUpdates = function() { - this.batchCount_--; - if (this.batchCount_ != 0) return; - if (this.totalCount_ > this.currentEvictionThreshold_()) - this.evict_(); - for (var index = 0; index < this.observers_.length; index++) { - var observer = this.observers_[index]; - var entries = []; - var properties = []; - for (var entryURL in observer.pending) { - if (observer.pending.hasOwnProperty(entryURL) && - entryURL in this.cache_) { - var entry = observer.pending[entryURL]; - entries.push(entry); - properties.push( - this.cache_[entryURL].properties[observer.type] || null); - } - } - observer.pending = {}; - if (entries.length > 0) { - observer.callback(entries, properties); - } - } -}; - -/** - * Notifies observers or puts the data to pending list. - * @param {Entry} entry Changed entry. - * @param {string} type Metadata type. - * @private - */ -MetadataCache.prototype.notifyObservers_ = function(entry, type) { - var entryURL = entry.toURL(); - for (var index = 0; index < this.observers_.length; index++) { - var observer = this.observers_[index]; - if (observer.type == type && observer.re.test(entryURL)) { - if (this.batchCount_ == 0) { - // Observer expects array of urls and array of properties. - observer.callback( - [entry], [this.cache_[entryURL].properties[type] || null]); - } else { - observer.pending[entryURL] = entry; - } - } - } -}; - -/** - * Removes the oldest items from the cache. - * This method never removes the items from last batch. - * @private - */ -MetadataCache.prototype.evict_ = function() { - var toRemove = []; - - // We leave only a half of items, so we will not call evict_ soon again. - var desiredCount = this.currentEvictionThreshold_(); - var removeCount = this.totalCount_ - desiredCount; - for (var url in this.cache_) { - if (this.cache_.hasOwnProperty(url) && - this.cache_[url].time < this.lastBatchStart_) { - toRemove.push(url); - } - } - - toRemove.sort(function(a, b) { - var aTime = this.cache_[a].time; - var bTime = this.cache_[b].time; - return aTime < bTime ? -1 : aTime > bTime ? 1 : 0; - }.bind(this)); - - removeCount = Math.min(removeCount, toRemove.length); - this.totalCount_ -= removeCount; - for (var index = 0; index < removeCount; index++) { - delete this.cache_[toRemove[index]]; - } -}; - -/** - * @return {Object} Empty cache item. - * @private - */ -MetadataCache.prototype.createEmptyItem_ = function() { - var item = {properties: {}}; - for (var index = 0; index < this.providers_.length; index++) { - item[this.providers_[index].getId()] = {}; - } - return item; -}; - -/** - * Caches all the properties from data to cache entry for the entry. - * @param {Entry} entry The file entry. - * @param {Object} data The properties. - * @private - */ -MetadataCache.prototype.mergeProperties_ = function(entry, data) { - if (data == null) return; - var properties = this.cache_[entry.toURL()].properties; - for (var type in data) { - if (data.hasOwnProperty(type) && !properties.hasOwnProperty(type)) { - properties[type] = data[type]; - this.notifyObservers_(entry, type); - } - } -}; - -/** - * Base class for metadata providers. - * @constructor - */ -function MetadataProvider() { -} - -/** - * @param {Entry} entry The entry. - * @return {boolean} Whether this provider supports the entry. - */ -MetadataProvider.prototype.supportsEntry = function(entry) { return false; }; - -/** - * @param {string} type The metadata type. - * @return {boolean} Whether this provider provides this metadata. - */ -MetadataProvider.prototype.providesType = function(type) { return false; }; - -/** - * @return {string} Unique provider id. - */ -MetadataProvider.prototype.getId = function() { return ''; }; - -/** - * @return {boolean} Whether provider is ready. - */ -MetadataProvider.prototype.isInitialized = function() { return true; }; - -/** - * Fetches the metadata. It's suggested to return all the metadata this provider - * can fetch at once. - * @param {Entry} entry File entry. - * @param {string} type Requested metadata type. - * @param {function(Object)} callback Callback expects a map from metadata type - * to metadata value. - */ -MetadataProvider.prototype.fetch = function(entry, type, callback) { - throw new Error('Default metadata provider cannot fetch.'); -}; - - -/** - * Provider of filesystem metadata. - * This provider returns the following objects: - * filesystem: { size, modificationTime } - * @constructor - */ -function FilesystemProvider() { - MetadataProvider.call(this); -} - -FilesystemProvider.prototype = { - __proto__: MetadataProvider.prototype -}; - -/** - * @param {Entry} entry The entry. - * @return {boolean} Whether this provider supports the entry. - */ -FilesystemProvider.prototype.supportsEntry = function(entry) { - return true; -}; - -/** - * @param {string} type The metadata type. - * @return {boolean} Whether this provider provides this metadata. - */ -FilesystemProvider.prototype.providesType = function(type) { - return type == 'filesystem'; -}; - -/** - * @return {string} Unique provider id. - */ -FilesystemProvider.prototype.getId = function() { return 'filesystem'; }; - -/** - * Fetches the metadata. - * @param {Entry} entry File entry. - * @param {string} type Requested metadata type. - * @param {function(Object)} callback Callback expects a map from metadata type - * to metadata value. - */ -FilesystemProvider.prototype.fetch = function( - entry, type, callback) { - function onError(error) { - callback(null); - } - - function onMetadata(entry, metadata) { - callback({ - filesystem: { - size: entry.isFile ? (metadata.size || 0) : -1, - modificationTime: metadata.modificationTime - } - }); - } - - entry.getMetadata(onMetadata.bind(null, entry), onError); -}; - -/** - * Provider of drive metadata. - * This provider returns the following objects: - * drive: { pinned, hosted, present, customIconUrl, etc. } - * thumbnail: { url, transform } - * streaming: { } - * @constructor - */ -function DriveProvider() { - MetadataProvider.call(this); - - // We batch metadata fetches into single API call. - this.entries_ = []; - this.callbacks_ = []; - this.scheduled_ = false; - - this.callApiBound_ = this.callApi_.bind(this); -} - -DriveProvider.prototype = { - __proto__: MetadataProvider.prototype -}; - -/** - * @param {Entry} entry The entry. - * @return {boolean} Whether this provider supports the entry. - */ -DriveProvider.prototype.supportsEntry = function(entry) { - return FileType.isOnDrive(entry); -}; - -/** - * @param {string} type The metadata type. - * @return {boolean} Whether this provider provides this metadata. - */ -DriveProvider.prototype.providesType = function(type) { - return type == 'drive' || type == 'thumbnail' || - type == 'streaming' || type == 'media'; -}; - -/** - * @return {string} Unique provider id. - */ -DriveProvider.prototype.getId = function() { return 'drive'; }; - -/** - * Fetches the metadata. - * @param {Entry} entry File entry. - * @param {string} type Requested metadata type. - * @param {function(Object)} callback Callback expects a map from metadata type - * to metadata value. - */ -DriveProvider.prototype.fetch = function(entry, type, callback) { - this.entries_.push(entry); - this.callbacks_.push(callback); - if (!this.scheduled_) { - this.scheduled_ = true; - setTimeout(this.callApiBound_, 0); - } -}; - -/** - * Schedules the API call. - * @private - */ -DriveProvider.prototype.callApi_ = function() { - this.scheduled_ = false; - - var entries = this.entries_; - var callbacks = this.callbacks_; - this.entries_ = []; - this.callbacks_ = []; - var self = this; - - var task = function(entry, callback) { - // TODO(mtomasz): Make getDriveEntryProperties accept Entry instead of URL. - var entryURL = entry.toURL(); - chrome.fileBrowserPrivate.getDriveEntryProperties(entryURL, - function(properties) { - callback(self.convert_(properties, entry)); - }); - }; - - for (var i = 0; i < entries.length; i++) - task(entries[i], callbacks[i]); -}; - -/** - * @param {DriveEntryProperties} data Drive entry properties. - * @param {Entry} entry File entry. - * @return {boolean} True if the file is available offline. - */ -DriveProvider.isAvailableOffline = function(data, entry) { - if (data.isPresent) - return true; - - if (!data.isHosted) - return false; - - // What's available offline? See the 'Web' column at: - // http://support.google.com/drive/bin/answer.py?hl=en&answer=1628467 - var subtype = FileType.getType(entry).subtype; - return (subtype == 'doc' || - subtype == 'draw' || - subtype == 'sheet' || - subtype == 'slides'); -}; - -/** - * @param {DriveEntryProperties} data Drive entry properties. - * @return {boolean} True if opening the file does not require downloading it - * via a metered connection. - */ -DriveProvider.isAvailableWhenMetered = function(data) { - return data.isPresent || data.isHosted; -}; - -/** - * Converts API metadata to internal format. - * @param {Object} data Metadata from API call. - * @param {Entry} entry File entry. - * @return {Object} Metadata in internal format. - * @private - */ -DriveProvider.prototype.convert_ = function(data, entry) { - var result = {}; - result.drive = { - present: data.isPresent, - pinned: data.isPinned, - hosted: data.isHosted, - imageWidth: data.imageWidth, - imageHeight: data.imageHeight, - imageRotation: data.imageRotation, - availableOffline: DriveProvider.isAvailableOffline(data, entry), - availableWhenMetered: DriveProvider.isAvailableWhenMetered(data), - customIconUrl: data.customIconUrl || '', - contentMimeType: data.contentMimeType || '', - sharedWithMe: data.sharedWithMe, - shared: data.shared - }; - - if (!data.isPresent) { - // Block the local fetch for drive files, which require downloading. - result.thumbnail = {url: '', transform: null}; - result.media = {}; - } - - if ('thumbnailUrl' in data) { - result.thumbnail = { - url: data.thumbnailUrl, - transform: null - }; - } - if (!data.isPresent) { - // Indicate that the data is not available in local cache. - // It used to have a field 'url' for streaming play, but it is - // derprecated. See crbug.com/174560. - result.streaming = {}; - } - return result; -}; - - -/** - * Provider of content metadata. - * This provider returns the following objects: - * thumbnail: { url, transform } - * media: { artist, album, title, width, height, imageTransform, etc. } - * fetchedMedia: { same fields here } - * @constructor - */ -function ContentProvider() { - MetadataProvider.call(this); - - // Pass all URLs to the metadata reader until we have a correct filter. - this.urlFilter_ = /.*/; - - var path = document.location.pathname; - var workerPath = document.location.origin + - path.substring(0, path.lastIndexOf('/') + 1) + - 'foreground/js/metadata/metadata_dispatcher.js'; - - this.dispatcher_ = new SharedWorker(workerPath).port; - this.dispatcher_.start(); - - this.dispatcher_.onmessage = this.onMessage_.bind(this); - this.dispatcher_.postMessage({verb: 'init'}); - - // Initialization is not complete until the Worker sends back the - // 'initialized' message. See below. - this.initialized_ = false; - - // Map from Entry.toURL() to callback. - // Note that simultaneous requests for same url are handled in MetadataCache. - this.callbacks_ = {}; -} - -ContentProvider.prototype = { - __proto__: MetadataProvider.prototype -}; - -/** - * @param {Entry} entry The entry. - * @return {boolean} Whether this provider supports the entry. - */ -ContentProvider.prototype.supportsEntry = function(entry) { - return entry.toURL().match(this.urlFilter_); -}; - -/** - * @param {string} type The metadata type. - * @return {boolean} Whether this provider provides this metadata. - */ -ContentProvider.prototype.providesType = function(type) { - return type == 'thumbnail' || type == 'fetchedMedia' || type == 'media'; -}; - -/** - * @return {string} Unique provider id. - */ -ContentProvider.prototype.getId = function() { return 'content'; }; - -/** - * Fetches the metadata. - * @param {Entry} entry File entry. - * @param {string} type Requested metadata type. - * @param {function(Object)} callback Callback expects a map from metadata type - * to metadata value. - */ -ContentProvider.prototype.fetch = function(entry, type, callback) { - if (entry.isDirectory) { - callback({}); - return; - } - var entryURL = entry.toURL(); - this.callbacks_[entryURL] = callback; - this.dispatcher_.postMessage({verb: 'request', arguments: [entryURL]}); -}; - -/** - * Dispatch a message from a metadata reader to the appropriate on* method. - * @param {Object} event The event. - * @private - */ -ContentProvider.prototype.onMessage_ = function(event) { - var data = event.data; - - var methodName = - 'on' + data.verb.substr(0, 1).toUpperCase() + data.verb.substr(1) + '_'; - - if (!(methodName in this)) { - console.error('Unknown message from metadata reader: ' + data.verb, data); - return; - } - - this[methodName].apply(this, data.arguments); -}; - -/** - * @return {boolean} Whether provider is ready. - */ -ContentProvider.prototype.isInitialized = function() { - return this.initialized_; -}; - -/** - * Handles the 'initialized' message from the metadata reader Worker. - * @param {Object} regexp Regexp of supported urls. - * @private - */ -ContentProvider.prototype.onInitialized_ = function(regexp) { - this.urlFilter_ = regexp; - - // Tests can monitor for this state with - // ExtensionTestMessageListener listener("worker-initialized"); - // ASSERT_TRUE(listener.WaitUntilSatisfied()); - // Automated tests need to wait for this, otherwise we crash in - // browser_test cleanup because the worker process still has - // URL requests in-flight. - var test = chrome.test || window.top.chrome.test; - test.sendMessage('worker-initialized'); - this.initialized_ = true; -}; - -/** - * Converts content metadata from parsers to the internal format. - * @param {Object} metadata The content metadata. - * @param {Object=} opt_result The internal metadata object ot put result in. - * @return {Object!} Converted metadata. - */ -ContentProvider.ConvertContentMetadata = function(metadata, opt_result) { - var result = opt_result || {}; - - if ('thumbnailURL' in metadata) { - metadata.thumbnailTransform = metadata.thumbnailTransform || null; - result.thumbnail = { - url: metadata.thumbnailURL, - transform: metadata.thumbnailTransform - }; - } - - for (var key in metadata) { - if (metadata.hasOwnProperty(key)) { - if (!('media' in result)) result.media = {}; - result.media[key] = metadata[key]; - } - } - - if ('media' in result) { - result.fetchedMedia = result.media; - } - - return result; -}; - -/** - * Handles the 'result' message from the worker. - * @param {string} url File url. - * @param {Object} metadata The metadata. - * @private - */ -ContentProvider.prototype.onResult_ = function(url, metadata) { - var callback = this.callbacks_[url]; - delete this.callbacks_[url]; - callback(ContentProvider.ConvertContentMetadata(metadata)); -}; - -/** - * Handles the 'error' message from the worker. - * @param {string} url File entry. - * @param {string} step Step failed. - * @param {string} error Error description. - * @param {Object?} metadata The metadata, if available. - * @private - */ -ContentProvider.prototype.onError_ = function(url, step, error, metadata) { - if (MetadataCache.log) // Avoid log spam by default. - console.warn('metadata: ' + url + ': ' + step + ': ' + error); - metadata = metadata || {}; - // Prevent asking for thumbnail again. - metadata.thumbnailURL = ''; - this.onResult_(url, metadata); -}; - -/** - * Handles the 'log' message from the worker. - * @param {Array.<*>} arglist Log arguments. - * @private - */ -ContentProvider.prototype.onLog_ = function(arglist) { - if (MetadataCache.log) // Avoid log spam by default. - console.log.apply(console, ['metadata:'].concat(arglist)); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_dispatcher.js b/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_dispatcher.js deleted file mode 100644 index b711d7559b7..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_dispatcher.js +++ /dev/null @@ -1,226 +0,0 @@ -// 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. - -'use strict'; - -// All of these scripts could be imported with a single call to importScripts, -// but then load and compile time errors would all be reported from the same -// line. -importScripts('metadata_parser.js'); -importScripts('byte_reader.js'); -importScripts('../../../common/js/util.js'); - -/** - * Dispatches metadata requests to the correct parser. - * - * @param {Object} port Worker port. - * @constructor - */ -function MetadataDispatcher(port) { - this.port_ = port; - this.port_.onmessage = this.onMessage.bind(this); - - // Make sure to update component_extension_resources.grd - // when adding new parsers. - importScripts('exif_parser.js'); - importScripts('image_parsers.js'); - importScripts('mpeg_parser.js'); - importScripts('id3_parser.js'); - - var patterns = []; - - this.parserInstances_ = []; - for (var i = 0; i < MetadataDispatcher.parserClasses_.length; i++) { - var parserClass = MetadataDispatcher.parserClasses_[i]; - var parser = new parserClass(this); - this.parserInstances_.push(parser); - patterns.push(parser.urlFilter.source); - } - - this.parserRegexp_ = new RegExp('(' + patterns.join('|') + ')', 'i'); - - this.messageHandlers_ = { - init: this.init_.bind(this), - request: this.request_.bind(this) - }; -} - -/** - * List of registered parser classes. - * @private - */ -MetadataDispatcher.parserClasses_ = []; - -/** - * @param {function} parserClass Parser constructor function. - */ -MetadataDispatcher.registerParserClass = function(parserClass) { - MetadataDispatcher.parserClasses_.push(parserClass); -}; - -/** - * Verbose logging for the dispatcher. - * - * Individual parsers also take this as their default verbosity setting. - */ -MetadataDispatcher.prototype.verbose = false; - -/** - * |init| message handler. - * @private - */ -MetadataDispatcher.prototype.init_ = function() { - // Inform our owner that we're done initializing. - // If we need to pass more data back, we can add it to the param array. - this.postMessage('initialized', [this.parserRegexp_]); - this.log('initialized with URL filter ' + this.parserRegexp_); -}; - -/** - * |request| message handler. - * @param {string} fileURL File URL. - * @private - */ -MetadataDispatcher.prototype.request_ = function(fileURL) { - try { - this.processOneFile(fileURL, function callback(metadata) { - this.postMessage('result', [fileURL, metadata]); - }.bind(this)); - } catch (ex) { - this.error(fileURL, ex); - } -}; - -/** - * Indicate to the caller that an operation has failed. - * - * No other messages relating to the failed operation should be sent. - * @param {...Object} var_args Arguments. - */ -MetadataDispatcher.prototype.error = function(var_args) { - var ary = Array.apply(null, arguments); - this.postMessage('error', ary); -}; - -/** - * Send a log message to the caller. - * - * Callers must not parse log messages for control flow. - * @param {...Object} var_args Arguments. - */ -MetadataDispatcher.prototype.log = function(var_args) { - var ary = Array.apply(null, arguments); - this.postMessage('log', ary); -}; - -/** - * Send a log message to the caller only if this.verbose is true. - * @param {...Object} var_args Arguments. - */ -MetadataDispatcher.prototype.vlog = function(var_args) { - if (this.verbose) - this.log.apply(this, arguments); -}; - -/** - * Post a properly formatted message to the caller. - * @param {string} verb Message type descriptor. - * @param {Array.<Object>} args Arguments array. - */ -MetadataDispatcher.prototype.postMessage = function(verb, args) { - this.port_.postMessage({verb: verb, arguments: args}); -}; - -/** - * Message handler. - * @param {Event} event Event object. - */ -MetadataDispatcher.prototype.onMessage = function(event) { - var data = event.data; - - if (this.messageHandlers_.hasOwnProperty(data.verb)) { - this.messageHandlers_[data.verb].apply(this, data.arguments); - } else { - this.log('Unknown message from client: ' + data.verb, data); - } -}; - -/** - * @param {string} fileURL File URL. - * @param {function(Object)} callback Completion callback. - */ -MetadataDispatcher.prototype.processOneFile = function(fileURL, callback) { - var self = this; - var currentStep = -1; - - function nextStep(var_args) { - self.vlog('nextStep: ' + steps[currentStep + 1].name); - steps[++currentStep].apply(self, arguments); - } - - var metadata; - - function onError(err, stepName) { - self.error(fileURL, stepName || steps[currentStep].name, err.toString(), - metadata); - } - - var steps = - [ // Step one, find the parser matching the url. - function detectFormat() { - for (var i = 0; i != self.parserInstances_.length; i++) { - var parser = self.parserInstances_[i]; - if (fileURL.match(parser.urlFilter)) { - // Create the metadata object as early as possible so that we can - // pass it with the error message. - metadata = parser.createDefaultMetadata(); - nextStep(parser); - return; - } - } - onError('unsupported format'); - }, - - // Step two, turn the url into an entry. - function getEntry(parser) { - webkitResolveLocalFileSystemURL( - fileURL, - function(entry) { nextStep(entry, parser) }, - onError); - }, - - // Step three, turn the entry into a file. - function getFile(entry, parser) { - entry.file(function(file) { nextStep(file, parser) }, onError); - }, - - // Step four, parse the file content. - function parseContent(file, parser) { - metadata.fileSize = file.size; - try { - parser.parse(file, metadata, callback, onError); - } catch (e) { - onError(e.stack); - } - } - ]; - - nextStep(); -}; - -// Webworker spec says that the worker global object is called self. That's -// a terrible name since we use it all over the chrome codebase to capture -// the 'this' keyword in lambdas. -var global = self; - -if (global.constructor.name == 'SharedWorkerGlobalScope') { - global.addEventListener('connect', function(e) { - var port = e.ports[0]; - new MetadataDispatcher(port); - port.start(); - }); -} else { - // Non-shared worker. - new MetadataDispatcher(global); -} diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_parser.js b/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_parser.js deleted file mode 100644 index 087eb42a9aa..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/metadata_parser.js +++ /dev/null @@ -1,62 +0,0 @@ -// 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. - -'use strict'; - -/** - * @param {MetadataDispatcher} parent Parent object. - * @param {string} type Parser type. - * @param {RegExp} urlFilter RegExp to match URLs. - * @constructor - */ -function MetadataParser(parent, type, urlFilter) { - this.parent_ = parent; - this.type = type; - this.urlFilter = urlFilter; - this.verbose = parent.verbose; - this.mimeType = 'unknown'; -} - -/** - * Output an error message. - * @param {...Object} var_args Arguments. - */ -MetadataParser.prototype.error = function(var_args) { - this.parent_.error.apply(this.parent_, arguments); -}; - -/** - * Output a log message. - * @param {...Object} var_args Arguments. - */ -MetadataParser.prototype.log = function(var_args) { - this.parent_.log.apply(this.parent_, arguments); -}; - -/** - * Output a log message if |verbose| flag is on. - * @param {...Object} var_args Arguments. - */ -MetadataParser.prototype.vlog = function(var_args) { - if (this.verbose) - this.parent_.log.apply(this.parent_, arguments); -}; - -/** - * @return {Object} Metadata object with the minimal set of properties. - */ -MetadataParser.prototype.createDefaultMetadata = function() { - return { - type: this.type, - mimeType: this.mimeType - }; -}; - -/* Base class for image metadata parsers */ -function ImageParser(parent, type, urlFilter) { - MetadataParser.apply(this, arguments); - this.mimeType = 'image/' + this.type; -} - -ImageParser.prototype = {__proto__: MetadataParser.prototype}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/mpeg_parser.js b/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/mpeg_parser.js deleted file mode 100644 index 03637cff6ad..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/metadata/mpeg_parser.js +++ /dev/null @@ -1,317 +0,0 @@ -// 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. - -'use strict'; - -/** - * @param {MetadataDispatcher} parent Parent object. - * @constructor - */ -function MpegParser(parent) { - MetadataParser.call(this, parent, 'mpeg', /\.(mp4|m4v|m4a|mpe?g4?)$/i); - this.mimeType = 'video/mpeg'; -} - -MpegParser.prototype = {__proto__: MetadataParser.prototype}; - -/** - * Size of the atom header. - */ -MpegParser.HEADER_SIZE = 8; - -/** - * @param {ByteReader} br ByteReader instance. - * @param {number=} opt_end End of atom position. - * @return {number} Atom size. - */ -MpegParser.readAtomSize = function(br, opt_end) { - var pos = br.tell(); - - if (opt_end) { - // Assert that opt_end <= buffer end. - // When supplied, opt_end is the end of the enclosing atom and is used to - // check the correct nesting. - br.validateRead(opt_end - pos); - } - - var size = br.readScalar(4, false, opt_end); - - if (size < MpegParser.HEADER_SIZE) - throw 'atom too short (' + size + ') @' + pos; - - if (opt_end && pos + size > opt_end) - throw 'atom too long (' + size + '>' + (opt_end - pos) + ') @' + pos; - - return size; -}; - -/** - * @param {ByteReader} br ByteReader instance. - * @param {number=} opt_end End of atom position. - * @return {string} Atom name. - */ -MpegParser.readAtomName = function(br, opt_end) { - return br.readString(4, opt_end).toLowerCase(); -}; - -/** - * @param {Object} metadata Metadata object. - * @return {Object} Root of the parser tree. - */ -MpegParser.createRootParser = function(metadata) { - function findParentAtom(atom, name) { - for (;;) { - atom = atom.parent; - if (!atom) return null; - if (atom.name == name) return atom; - } - } - - function parseFtyp(br, atom) { - metadata.brand = br.readString(4, atom.end); - } - - function parseMvhd(br, atom) { - var version = br.readScalar(4, false, atom.end); - var offset = (version == 0) ? 8 : 16; - br.seek(offset, ByteReader.SEEK_CUR); - var timescale = br.readScalar(4, false, atom.end); - var duration = br.readScalar(4, false, atom.end); - metadata.duration = duration / timescale; - } - - function parseHdlr(br, atom) { - br.seek(8, ByteReader.SEEK_CUR); - findParentAtom(atom, 'trak').trackType = br.readString(4, atom.end); - } - - function parseStsd(br, atom) { - var track = findParentAtom(atom, 'trak'); - if (track && track.trackType == 'vide') { - br.seek(40, ByteReader.SEEK_CUR); - metadata.width = br.readScalar(2, false, atom.end); - metadata.height = br.readScalar(2, false, atom.end); - } - } - - function parseDataString(name, br, atom) { - br.seek(8, ByteReader.SEEK_CUR); - metadata[name] = br.readString(atom.end - br.tell(), atom.end); - } - - function parseCovr(br, atom) { - br.seek(8, ByteReader.SEEK_CUR); - metadata.thumbnailURL = br.readImage(atom.end - br.tell(), atom.end); - } - - // 'meta' atom can occur at one of the several places in the file structure. - var parseMeta = { - ilst: { - '©nam': { data: parseDataString.bind(null, 'title') }, - '©alb': { data: parseDataString.bind(null, 'album') }, - '©art': { data: parseDataString.bind(null, 'artist') }, - 'covr': { data: parseCovr } - }, - versioned: true - }; - - // main parser for the entire file structure. - return { - ftyp: parseFtyp, - moov: { - mvhd: parseMvhd, - trak: { - mdia: { - hdlr: parseHdlr, - minf: { - stbl: { - stsd: parseStsd - } - } - }, - meta: parseMeta - }, - udta: { - meta: parseMeta - }, - meta: parseMeta - }, - meta: parseMeta - }; -}; - -/** - * - * @param {File} file File. - * @param {Object} metadata Metadata. - * @param {function(Object)} callback Success callback. - * @param {function} onError Error callback. - */ -MpegParser.prototype.parse = function(file, metadata, callback, onError) { - this.rootParser_ = MpegParser.createRootParser(metadata); - - // Kick off the processing by reading the first atom's header. - this.requestRead(file, 0, MpegParser.HEADER_SIZE, null, - onError, callback.bind(null, metadata)); -}; - -/** - * @param {function(ByteReader, Object)|Object} parser Parser tree node. - * @param {ByteReader} br ByteReader instance. - * @param {Object} atom Atom descriptor. - * @param {number} filePos File position of the atom start. - */ -MpegParser.prototype.applyParser = function(parser, br, atom, filePos) { - if (this.verbose) { - var path = atom.name; - for (var p = atom.parent; p && p.name; p = p.parent) { - path = p.name + '.' + path; - } - - var action; - if (!parser) { - action = 'skipping '; - } else if (parser instanceof Function) { - action = 'parsing '; - } else { - action = 'recursing'; - } - - var start = atom.start - MpegParser.HEADER_SIZE; - this.vlog(path + ': ' + - '@' + (filePos + start) + ':' + (atom.end - start), - action); - } - - if (parser) { - if (parser instanceof Function) { - br.pushSeek(atom.start); - parser(br, atom); - br.popSeek(); - } else { - if (parser.versioned) { - atom.start += 4; - } - this.parseMpegAtomsInRange(parser, br, atom, filePos); - } - } -}; - -/** - * @param {function(ByteReader, Object)|Object} parser Parser tree node. - * @param {ByteReader} br ByteReader instance. - * @param {Object} parentAtom Parent atom descriptor. - * @param {number} filePos File position of the atom start. - */ -MpegParser.prototype.parseMpegAtomsInRange = function( - parser, br, parentAtom, filePos) { - var count = 0; - for (var offset = parentAtom.start; offset != parentAtom.end;) { - if (count++ > 100) // Most likely we are looping through a corrupt file. - throw 'too many child atoms in ' + parentAtom.name + ' @' + offset; - - br.seek(offset); - var size = MpegParser.readAtomSize(br, parentAtom.end); - var name = MpegParser.readAtomName(br, parentAtom.end); - - this.applyParser( - parser[name], - br, - { start: offset + MpegParser.HEADER_SIZE, - end: offset + size, - name: name, - parent: parentAtom - }, - filePos - ); - - offset += size; - } -}; - -/** - * @param {File} file File. - * @param {number} filePos Start position in the file. - * @param {number} size Atom size. - * @param {string} name Atom name. - * @param {function} onError Error callback. - * @param {function} onSuccess Success callback. - */ -MpegParser.prototype.requestRead = function( - file, filePos, size, name, onError, onSuccess) { - var self = this; - var reader = new FileReader(); - reader.onerror = onError; - reader.onload = function(event) { - self.processTopLevelAtom( - reader.result, file, filePos, size, name, onError, onSuccess); - }; - this.vlog('reading @' + filePos + ':' + size); - reader.readAsArrayBuffer(file.slice(filePos, filePos + size)); -}; - -/** - * @param {ArrayBuffer} buf Data buffer. - * @param {File} file File. - * @param {number} filePos Start position in the file. - * @param {number} size Atom size. - * @param {string} name Atom name. - * @param {function} onError Error callback. - * @param {function} onSuccess Success callback. - */ -MpegParser.prototype.processTopLevelAtom = function( - buf, file, filePos, size, name, onError, onSuccess) { - try { - var br = new ByteReader(buf); - - // the header has already been read. - var atomEnd = size - MpegParser.HEADER_SIZE; - - var bufLength = buf.byteLength; - - // Check the available data size. It should be either exactly - // what we requested or HEADER_SIZE bytes less (for the last atom). - if (bufLength != atomEnd && bufLength != size) { - throw 'Read failure @' + filePos + ', ' + - 'requested ' + size + ', read ' + bufLength; - } - - // Process the top level atom. - if (name) { // name is null only the first time. - this.applyParser( - this.rootParser_[name], - br, - {start: 0, end: atomEnd, name: name}, - filePos - ); - } - - filePos += bufLength; - if (bufLength == size) { - // The previous read returned everything we asked for, including - // the next atom header at the end of the buffer. - // Parse this header and schedule the next read. - br.seek(-MpegParser.HEADER_SIZE, ByteReader.SEEK_END); - var nextSize = MpegParser.readAtomSize(br); - var nextName = MpegParser.readAtomName(br); - - // If we do not have a parser for the next atom, skip the content and - // read only the header (the one after the next). - if (!this.rootParser_[nextName]) { - filePos += nextSize - MpegParser.HEADER_SIZE; - nextSize = MpegParser.HEADER_SIZE; - } - - this.requestRead(file, filePos, nextSize, nextName, onError, onSuccess); - } else { - // The previous read did not return the next atom header, EOF reached. - this.vlog('EOF @' + filePos); - onSuccess(); - } - } catch (e) { - onError(e.toString()); - } -}; - -MetadataDispatcher.registerParserClass(MpegParser); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/metrics.js b/chromium/chrome/browser/resources/file_manager/foreground/js/metrics.js deleted file mode 100644 index 3f34e51a299..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/metrics.js +++ /dev/null @@ -1,131 +0,0 @@ -// 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 Utility methods for accessing chrome.metricsPrivate API. - * - * To be included as a first script in main.html - */ - -var metrics = {}; - -/** - * A map from interval name to interval start timestamp. - */ -metrics.intervals = {}; - -/** - * Start the named time interval. - * Should be followed by a call to recordInterval with the same name. - * - * @param {string} name Unique interval name. - */ -metrics.startInterval = function(name) { - metrics.intervals[name] = Date.now(); -}; - -metrics.startInterval('Load.Total'); -metrics.startInterval('Load.Script'); - -/** - * Convert a short metric name to the full format. - * - * @param {string} name Short metric name. - * @return {string} Full metric name. - * @private - */ -metrics.convertName_ = function(name) { - return 'FileBrowser.' + name; -}; - -/** - * Wrapper method for calling chrome.fileBrowserPrivate safely. - * @param {string} name Method name. - * @param {Array.<Object>} args Arguments. - * @private - */ -metrics.call_ = function(name, args) { - try { - chrome.metricsPrivate[name].apply(chrome.metricsPrivate, args); - } catch (e) { - console.error(e.stack); - } -}; - -/** - * Create a decorator function that calls a chrome.metricsPrivate function - * with the same name and correct parameters. - * - * @param {string} name Method name. - */ -metrics.decorate = function(name) { - metrics[name] = function() { - var args = Array.apply(null, arguments); - args[0] = metrics.convertName_(args[0]); - metrics.call_(name, args); - if (metrics.log) { - console.log('chrome.metricsPrivate.' + name, args); - } - }; -}; - -metrics.decorate('recordMediumCount'); -metrics.decorate('recordSmallCount'); -metrics.decorate('recordTime'); -metrics.decorate('recordUserAction'); - -/** - * Complete the time interval recording. - * - * Should be preceded by a call to startInterval with the same name. * - * - * @param {string} name Unique interval name. - */ -metrics.recordInterval = function(name) { - if (name in metrics.intervals) { - metrics.recordTime(name, Date.now() - metrics.intervals[name]); - } else { - console.error('Unknown interval: ' + name); - } -}; - -/** - * Record an enum value. - * - * @param {string} name Metric name. - * @param {Object} value Enum value. - * @param {Array.<Object>|number} validValues Array of valid values - * or a boundary number value. - */ -metrics.recordEnum = function(name, value, validValues) { - var boundaryValue; - var index; - if (validValues.constructor.name == 'Array') { - index = validValues.indexOf(value); - boundaryValue = validValues.length; - } else { - index = value; - boundaryValue = validValues; - } - // Collect invalid values in the overflow bucket at the end. - if (index < 0 || index > boundaryValue) - index = boundaryValue; - - // Setting min to 1 looks strange but this is exactly the recommended way - // of using histograms for enum-like types. Bucket #0 works as a regular - // bucket AND the underflow bucket. - // (Source: UMA_HISTOGRAM_ENUMERATION definition in base/metrics/histogram.h) - var metricDescr = { - 'metricName': metrics.convertName_(name), - 'type': 'histogram-linear', - 'min': 1, - 'max': boundaryValue, - 'buckets': boundaryValue + 1 - }; - metrics.call_('recordValue', [metricDescr, index]); - if (metrics.log) { - console.log('chrome.metricsPrivate.recordValue', - [metricDescr.metricName, index, value]); - } -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/navigation_list_model.js b/chromium/chrome/browser/resources/file_manager/foreground/js/navigation_list_model.js deleted file mode 100644 index f1d31e6966d..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/navigation_list_model.js +++ /dev/null @@ -1,350 +0,0 @@ -// 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. - -'use strict'; - -/** - * Entry of NavigationListModel. This constructor should be called only from - * the helper methods (NavigationModelItem.create). - * - * @param {string} path Path. - * @param {DirectoryEntry} entry Entry. Can be null. - * @param {string} label Label. - * @constructor - */ -function NavigationModelItem(path, entry, label) { - this.path_ = path; - this.entry_ = entry; - this.label_ = label; - this.resolvingQueue_ = new AsyncUtil.Queue(); - - Object.seal(this); -} - -NavigationModelItem.prototype = { - get path() { return this.path_; }, - get label() { return this.label_; } -}; - -/** - * Returns the cached entry of the item. This may return NULL if the target is - * not available on the filesystem, is not resolved or is under resolving the - * entry. - * - * @return {Entry} Cached entry. - */ -NavigationModelItem.prototype.getCachedEntry = function() { - return this.entry_; -}; - -/** - * TODO(mtomasz): Use Entry instead of path. - * @param {VolumeManagerWrapper} volumeManager VolumeManagerWrapper instance. - * @param {string} path Path. - * @param {DirectoryEntry} entry Entry. Can be null. - * @param {string} label Label. - * @param {function(FileError)} errorCallback Called when the resolving is - * failed with the error. - * @return {NavigationModelItem} Created NavigationModelItem. - */ -NavigationModelItem.create = function( - volumeManager, path, entry, label, errorCallback) { - var item = new NavigationModelItem(path, entry, label); - - // If the given entry is null, try to resolve path to get an entry. - if (!entry) { - item.resolvingQueue_.run(function(continueCallback) { - volumeManager.resolveAbsolutePath( - path, - function(entry) { - if (entry.isDirectory) - item.entry_ = entry; - else - errorCallback(util.createFileError(FileError.TYPE_MISMATCH_ERR)); - continueCallback(); - }, - function(error) { - errorCallback(error); - continueCallback(); - }); - }); - } - return item; -}; - -/** - * Retrieves the entry. If the entry is being retrieved, waits until it - * finishes. - * @param {function(Entry)} callback Called with the resolved entry. The entry - * may be NULL if resolving is failed. - */ -NavigationModelItem.prototype.getEntryAsync = function(callback) { - // If resolving the entry is running, wait until it finishes. - this.resolvingQueue_.run(function(continueCallback) { - callback(this.entry_); - continueCallback(); - }.bind(this)); -}; - -/** - * Returns if this item is a shortcut or a volume root. - * @return {boolean} True if a shortcut, false if a volume root. - */ -NavigationModelItem.prototype.isShortcut = function() { - return !PathUtil.isRootPath(this.path_); -}; - -/** - * A navigation list model. This model combines the 2 lists. - * @param {VolumeManagerWrapper} volumeManager VolumeManagerWrapper instance. - * @param {cr.ui.ArrayDataModel} shortcutListModel The list of folder shortcut. - * @constructor - * @extends {cr.EventTarget} - */ -function NavigationListModel(volumeManager, shortcutListModel) { - cr.EventTarget.call(this); - - this.volumeManager_ = volumeManager; - this.shortcutListModel_ = shortcutListModel; - - var volumeInfoToModelItem = function(volumeInfo) { - if (volumeInfo.volumeType == util.VolumeType.DRIVE) { - // For drive volume, we assign the path to "My Drive". - return NavigationModelItem.create( - this.volumeManager_, - volumeInfo.mountPath + '/root', - null, - volumeInfo.getLabel(), - function() {}); - } else { - return NavigationModelItem.create( - this.volumeManager_, - volumeInfo.mountPath, - volumeInfo.root, - volumeInfo.getLabel(), - function() {}); - } - }.bind(this); - - var pathToModelItem = function(path) { - var item = NavigationModelItem.create( - this.volumeManager_, - path, - null, // Entry will be resolved. - PathUtil.getFolderLabel(path), - function(error) { - if (error.code == FileError.NOT_FOUND_ERR) - this.onItemNotFoundError(item); - }.bind(this)); - return item; - }.bind(this); - - /** - * Type of updated list. - * @enum {number} - * @const - */ - var ListType = { - VOLUME_LIST: 1, - SHORTCUT_LIST: 2 - }; - Object.freeze(ListType); - - // Generates this.volumeList_ and this.shortcutList_ from the models. - this.volumeList_ = - this.volumeManager_.volumeInfoList.slice().map(volumeInfoToModelItem); - - this.shortcutList_ = []; - for (var i = 0; i < this.shortcutListModel_.length; i++) { - var shortcutPath = this.shortcutListModel_.item(i); - var volumeInfo = this.volumeManager_.getVolumeInfo(shortcutPath); - var isMounted = volumeInfo && !volumeInfo.error; - if (isMounted) - this.shortcutList_.push(pathToModelItem(shortcutPath)); - } - - // Generates a combined 'permuted' event from an event of either list. - var permutedHandler = function(listType, event) { - var permutation; - - // Build the volumeList. - if (listType == ListType.VOLUME_LIST) { - // The volume is mounted or unmounted. - var newList = []; - - // Use the old instances if they just move. - for (var i = 0; i < event.permutation.length; i++) { - if (event.permutation[i] >= 0) - newList[event.permutation[i]] = this.volumeList_[i]; - } - - // Create missing instances. - for (var i = 0; i < event.newLength; i++) { - if (!newList[i]) { - newList[i] = volumeInfoToModelItem( - this.volumeManager_.volumeInfoList.item(i)); - } - } - this.volumeList_ = newList; - - permutation = event.permutation.slice(); - } else { - // volumeList part has not been changed, so the permutation should be - // idenetity mapping. - permutation = []; - for (var i = 0; i < this.volumeList_.length; i++) - permutation[i] = i; - } - - // Build the shortcutList. Even if the event is for the volumeInfoList - // update, the short cut path may be unmounted or newly mounted. So, here - // shortcutList will always be re-built. - // Currently this code may be redundant, as shortcut folder is supported - // only on Drive File System and we can assume single-profile, but - // multi-profile will be supported later. - // The shortcut list is sorted in case-insensitive lexicographical order. - // So we just can traverse the two list linearly. - var modelIndex = 0; - var oldListIndex = 0; - var newList = []; - while (modelIndex < this.shortcutListModel_.length && - oldListIndex < this.shortcutList_.length) { - var shortcutPath = this.shortcutListModel_.item(modelIndex); - var cmp = this.shortcutListModel_.compare( - shortcutPath, this.shortcutList_[oldListIndex].path); - if (cmp > 0) { - // The shortcut at shortcutList_[oldListIndex] is removed. - permutation.push(-1); - oldListIndex++; - continue; - } - - // Check if the volume where the shortcutPath is is mounted or not. - var volumeInfo = this.volumeManager_.getVolumeInfo(shortcutPath); - var isMounted = volumeInfo && !volumeInfo.error; - if (cmp == 0) { - // There exists an old NavigationModelItem instance. - if (isMounted) { - // Reuse the old instance. - permutation.push(newList.length + this.volumeList_.length); - newList.push(this.shortcutList_[oldListIndex]); - } else { - permutation.push(-1); - } - oldListIndex++; - } else { - // We needs to create a new instance for the shortcut path. - if (isMounted) - newList.push(pathToModelItem(shortcutPath)); - } - modelIndex++; - } - - // Add remaining (new) shortcuts if necessary. - for (; modelIndex < this.shortcutListModel_.length; modelIndex++) { - var shortcutPath = this.shortcutListModel_.item(modelIndex); - var volumeInfo = this.volumeManager_.getVolumeInfo(shortcutPath); - var isMounted = volumeInfo && !volumeInfo.error; - if (isMounted) - newList.push(pathToModelItem(shortcutPath)); - } - - // Fill remaining permutation if necessary. - for (; oldListIndex < this.shortcutList_.length; oldListIndex++) - permutation.push(-1); - - this.shortcutList_ = newList; - - // Dispatch permuted event. - var permutedEvent = new Event('permuted'); - permutedEvent.newLength = - this.volumeList_.length + this.shortcutList_.length; - permutedEvent.permutation = permutation; - this.dispatchEvent(permutedEvent); - }; - - this.volumeManager_.volumeInfoList.addEventListener( - 'permuted', permutedHandler.bind(this, ListType.VOLUME_LIST)); - this.shortcutListModel_.addEventListener( - 'permuted', permutedHandler.bind(this, ListType.SHORTCUT_LIST)); - - // 'change' event is just ignored, because it is not fired neither in - // the folder shortcut list nor in the volume info list. - // 'splice' and 'sorted' events are not implemented, since they are not used - // in list.js. -} - -/** - * NavigationList inherits cr.EventTarget. - */ -NavigationListModel.prototype = { - __proto__: cr.EventTarget.prototype, - get length() { return this.length_(); }, - get folderShortcutList() { return this.shortcutList_; } -}; - -/** - * Returns the item at the given index. - * @param {number} index The index of the entry to get. - * @return {?string} The path at the given index. - */ -NavigationListModel.prototype.item = function(index) { - var offset = this.volumeList_.length; - if (index < offset) - return this.volumeList_[index]; - return this.shortcutList_[index - offset]; -}; - -/** - * Returns the number of items in the model. - * @return {number} The length of the model. - * @private - */ -NavigationListModel.prototype.length_ = function() { - return this.volumeList_.length + this.shortcutList_.length; -}; - -/** - * Returns the first matching item. - * @param {NavigationModelItem} modelItem The entry to find. - * @param {number=} opt_fromIndex If provided, then the searching start at - * the {@code opt_fromIndex}. - * @return {number} The index of the first found element or -1 if not found. - */ -NavigationListModel.prototype.indexOf = function(modelItem, opt_fromIndex) { - for (var i = opt_fromIndex || 0; i < this.length; i++) { - if (modelItem === this.item(i)) - return i; - } - return -1; -}; - -/** - * Called when one od the items is not found on the filesystem. - * @param {NavigationModelItem} modelItem The entry which is not found. - */ -NavigationListModel.prototype.onItemNotFoundError = function(modelItem) { - var index = this.indexOf(modelItem); - if (index === -1) { - // Invalid modelItem. - } else if (index < this.volumeList_.length) { - // The item is in the volume list. - // Not implemented. - // TODO(yoshiki): Implement it when necessary. - } else { - // The item is in the folder shortcut list. - if (this.isDriveMounted()) - this.shortcutListModel_.remove(modelItem.path); - } -}; - -/** - * Returns if the drive is mounted or not. - * @return {boolean} True if the drive is mounted, false otherwise. - */ -NavigationListModel.prototype.isDriveMounted = function() { - var volumeInfo = - this.volumeManager_.getCurrentProfileVolumeInfo(RootType.DRIVE); - return !!volumeInfo && volumeInfo.root; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/photo/gallery.js b/chromium/chrome/browser/resources/file_manager/foreground/js/photo/gallery.js deleted file mode 100644 index 91171b6d3f1..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/photo/gallery.js +++ /dev/null @@ -1,867 +0,0 @@ -// 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. - -'use strict'; - -/** - * Called from the main frame when unloading. - * @return {string?} User-visible message on null if it is OK to close. - */ -function beforeunload() { return Gallery.instance.onBeforeUnload() } - -/** - * Called from the main frame when unloading. - * @param {boolean=} opt_exiting True if the app is exiting. - */ -function unload(opt_exiting) { Gallery.instance.onUnload(opt_exiting) } - -/** - * Gallery for viewing and editing image files. - * - * @param {Object} context Object containing the following: - * {function(string)} onNameChange Called every time a selected - * item name changes (on rename and on selection change). - * {AppWindow} appWindow - * {function(string)} onBack - * {function()} onClose - * {function()} onMaximize - * {function(boolean)} onAppRegionChanged - * {MetadataCache} metadataCache - * {Array.<Object>} shareActions - * {string} readonlyDirName Directory name for readonly warning or null. - * {DirEntry} saveDirEntry Directory to save to. - * {function(string)} displayStringFunction. - * @param {VolumeManagerWrapper} volumeManager The VolumeManager instance of - * the system. - * @class - * @constructor - */ -function Gallery(context, volumeManager) { - this.container_ = document.querySelector('.gallery'); - this.document_ = document; - this.context_ = context; - this.metadataCache_ = context.metadataCache; - this.volumeManager_ = volumeManager; - this.selectedEntry_ = null; - - this.dataModel_ = new cr.ui.ArrayDataModel([]); - this.selectionModel_ = new cr.ui.ListSelectionModel(); - this.displayStringFunction_ = context.displayStringFunction; - - this.initDom_(); - this.initListeners_(); -} - -/** - * Gallery extends cr.EventTarget. - */ -Gallery.prototype.__proto__ = cr.EventTarget.prototype; - -/** - * Creates and initializes a Gallery object based on a context. - * - * @param {Object} context Gallery context. - * @param {VolumeManagerWrapper} volumeManager VolumeManager of the system. - * @param {Array.<Entry>} entries Array of entries. - * @param {Array.<Entry>} selectedEntries Array of selected entries. - */ -Gallery.open = function(context, volumeManager, entries, selectedEntries) { - Gallery.instance = new Gallery(context, volumeManager); - Gallery.instance.load(entries, selectedEntries); -}; - -/** - * Tools fade-out timeout im milliseconds. - * @const - * @type {number} - */ -Gallery.FADE_TIMEOUT = 3000; - -/** - * First time tools fade-out timeout im milliseconds. - * @const - * @type {number} - */ -Gallery.FIRST_FADE_TIMEOUT = 1000; - -/** - * Time until mosaic is initialized in the background. Used to make gallery - * in the slide mode load faster. In miiliseconds. - * @const - * @type {number} - */ -Gallery.MOSAIC_BACKGROUND_INIT_DELAY = 1000; - -/** - * Types of metadata Gallery uses (to query the metadata cache). - * @const - * @type {string} - */ -Gallery.METADATA_TYPE = 'thumbnail|filesystem|media|streaming|drive'; - -/** - * Initializes listeners. - * @private - */ -Gallery.prototype.initListeners_ = function() { - this.document_.oncontextmenu = function(e) { e.preventDefault(); }; - this.keyDownBound_ = this.onKeyDown_.bind(this); - this.document_.body.addEventListener('keydown', this.keyDownBound_); - - this.inactivityWatcher_ = new MouseInactivityWatcher( - this.container_, Gallery.FADE_TIMEOUT, this.hasActiveTool.bind(this)); - - // Search results may contain files from different subdirectories so - // the observer is not going to work. - if (!this.context_.searchResults && this.context_.curDirEntry) { - this.thumbnailObserverId_ = this.metadataCache_.addObserver( - this.context_.curDirEntry, - MetadataCache.CHILDREN, - 'thumbnail', - this.updateThumbnails_.bind(this)); - } - - this.volumeManager_.addEventListener('externally-unmounted', - this.onExternallyUnmounted_.bind(this)); -}; - -/** - * Closes gallery when a volume containing the selected item is unmounted. - * @param {Event} event The unmount event. - * @private - */ -Gallery.prototype.onExternallyUnmounted_ = function(event) { - if (!this.selectedEntry_) - return; - - if (this.volumeManager_.getVolumeInfo(this.selectedEntry_) === - event.volumeInfo) { - this.onBack_(); - } -}; - -/** - * Beforeunload handler. - * @return {string?} User-visible message on null if it is OK to close. - */ -Gallery.prototype.onBeforeUnload = function() { - return this.slideMode_.onBeforeUnload(); -}; - -/** - * Unloads the Gallery. - * @param {boolean} exiting True if the app is exiting. - */ -Gallery.prototype.onUnload = function(exiting) { - if (!this.context_.searchResults) { - this.metadataCache_.removeObserver(this.thumbnailObserverId_); - } - this.slideMode_.onUnload(exiting); -}; - -/** - * Initializes DOM UI - * @private - */ -Gallery.prototype.initDom_ = function() { - var content = util.createChild(this.container_, 'content'); - content.addEventListener('click', this.onContentClick_.bind(this)); - - this.header_ = util.createChild(this.container_, 'header tool dimmable'); - this.toolbar_ = util.createChild(this.container_, 'toolbar tool dimmable'); - - var backButton = util.createChild(this.container_, - 'back-button tool dimmable'); - util.createChild(backButton); - backButton.addEventListener('click', this.onBack_.bind(this)); - - var preventDefault = function(event) { event.preventDefault(); }; - - var maximizeButton = util.createChild(this.header_, - 'maximize-button tool dimmable', - 'button'); - maximizeButton.tabIndex = -1; - maximizeButton.addEventListener('click', this.onMaximize_.bind(this)); - maximizeButton.addEventListener('mousedown', preventDefault); - - var closeButton = util.createChild(this.header_, - 'close-button tool dimmable', - 'button'); - closeButton.tabIndex = -1; - closeButton.addEventListener('click', this.onClose_.bind(this)); - closeButton.addEventListener('mousedown', preventDefault); - - this.filenameSpacer_ = util.createChild(this.toolbar_, 'filename-spacer'); - this.filenameEdit_ = util.createChild(this.filenameSpacer_, - 'namebox', 'input'); - - this.filenameEdit_.setAttribute('type', 'text'); - this.filenameEdit_.addEventListener('blur', - this.onFilenameEditBlur_.bind(this)); - - this.filenameEdit_.addEventListener('focus', - this.onFilenameFocus_.bind(this)); - - this.filenameEdit_.addEventListener('keydown', - this.onFilenameEditKeydown_.bind(this)); - - util.createChild(this.toolbar_, 'button-spacer'); - - this.prompt_ = new ImageEditor.Prompt( - this.container_, this.displayStringFunction_); - - this.modeButton_ = util.createChild(this.toolbar_, 'button mode', 'button'); - this.modeButton_.addEventListener('click', - this.toggleMode_.bind(this, null)); - - this.mosaicMode_ = new MosaicMode(content, - this.dataModel_, - this.selectionModel_, - this.metadataCache_, - this.toggleMode_.bind(this, null)); - - this.slideMode_ = new SlideMode(this.container_, - content, - this.toolbar_, - this.prompt_, - this.dataModel_, - this.selectionModel_, - this.context_, - this.toggleMode_.bind(this), - this.displayStringFunction_); - - this.slideMode_.addEventListener('image-displayed', function() { - cr.dispatchSimpleEvent(this, 'image-displayed'); - }.bind(this)); - this.slideMode_.addEventListener('image-saved', function() { - cr.dispatchSimpleEvent(this, 'image-saved'); - }.bind(this)); - - var deleteButton = this.createToolbarButton_('delete', 'GALLERY_DELETE'); - deleteButton.addEventListener('click', this.delete_.bind(this)); - - this.shareButton_ = this.createToolbarButton_('share', 'GALLERY_SHARE'); - this.shareButton_.setAttribute('disabled', ''); - this.shareButton_.addEventListener('click', this.toggleShare_.bind(this)); - - this.shareMenu_ = util.createChild(this.container_, 'share-menu'); - this.shareMenu_.hidden = true; - util.createChild(this.shareMenu_, 'bubble-point'); - - this.dataModel_.addEventListener('splice', this.onSplice_.bind(this)); - this.dataModel_.addEventListener('content', this.onContentChange_.bind(this)); - - this.selectionModel_.addEventListener('change', this.onSelection_.bind(this)); - this.slideMode_.addEventListener('useraction', this.onUserAction_.bind(this)); -}; - -/** - * Creates toolbar button. - * - * @param {string} className Class to add. - * @param {string} title Button title. - * @return {HTMLElement} Newly created button. - * @private - */ -Gallery.prototype.createToolbarButton_ = function(className, title) { - var button = util.createChild(this.toolbar_, className, 'button'); - button.title = this.displayStringFunction_(title); - return button; -}; - -/** - * Loads the content. - * - * @param {Array.<Entry>} entries Array of entries. - * @param {Array.<Entry>} selectedEntries Array of selected entries. Must be a - * subset of {@code entries}. - */ -Gallery.prototype.load = function(entries, selectedEntries) { - var items = []; - for (var index = 0; index < entries.length; ++index) { - items.push(new Gallery.Item(entries[index])); - } - this.dataModel_.push.apply(this.dataModel_, items); - - this.selectionModel_.adjustLength(this.dataModel_.length); - - for (var i = 0; i !== selectedEntries.length; i++) { - var selectedIndex = entries.indexOf(selectedEntries[i]); - if (selectedIndex >= 0) - this.selectionModel_.setIndexSelected(selectedIndex, true); - else - console.error('Cannot select ' + selectedEntries[i]); - } - - if (this.selectionModel_.selectedIndexes.length === 0) - this.onSelection_(); - - var mosaic = this.mosaicMode_ && this.mosaicMode_.getMosaic(); - - // Mosaic view should show up if most of the selected files are images. - var imagesCount = 0; - for (var i = 0; i !== selectedEntries.length; i++) { - if (FileType.getMediaType(selectedEntries[i]) === 'image') - imagesCount++; - } - var mostlyImages = imagesCount > (selectedEntries.length / 2.0); - - var forcedMosaic = (this.context_.pageState && - this.context_.pageState.gallery === 'mosaic'); - - var showMosaic = (mostlyImages && selectedEntries.length > 1) || forcedMosaic; - if (mosaic && showMosaic) { - this.setCurrentMode_(this.mosaicMode_); - mosaic.init(); - mosaic.show(); - this.inactivityWatcher_.check(); // Show the toolbar. - cr.dispatchSimpleEvent(this, 'loaded'); - } else { - this.setCurrentMode_(this.slideMode_); - var maybeLoadMosaic = function() { - if (mosaic) - mosaic.init(); - cr.dispatchSimpleEvent(this, 'loaded'); - }.bind(this); - /* TODO: consider nice blow-up animation for the first image */ - this.slideMode_.enter(null, function() { - // Flash the toolbar briefly to show it is there. - this.inactivityWatcher_.kick(Gallery.FIRST_FADE_TIMEOUT); - }.bind(this), - maybeLoadMosaic); - } -}; - -/** - * Closes the Gallery and go to Files.app. - * @private - */ -Gallery.prototype.back_ = function() { - if (util.isFullScreen(this.context_.appWindow)) { - util.toggleFullScreen(this.context_.appWindow, - false); // Leave the full screen mode. - } - this.context_.onBack(this.getSelectedEntries()); -}; - -/** - * Handles user's 'Back' action (Escape or a click on the X icon). - * @private - */ -Gallery.prototype.onBack_ = function() { - this.executeWhenReady(this.back_.bind(this)); -}; - -/** - * Handles user's 'Close' action. - * @private - */ -Gallery.prototype.onClose_ = function() { - this.executeWhenReady(this.context_.onClose); -}; - -/** - * Handles user's 'Maximize' action (Escape or a click on the X icon). - * @private - */ -Gallery.prototype.onMaximize_ = function() { - this.executeWhenReady(this.context_.onMaximize); -}; - -/** - * Executes a function when the editor is done with the modifications. - * @param {function} callback Function to execute. - */ -Gallery.prototype.executeWhenReady = function(callback) { - this.currentMode_.executeWhenReady(callback); -}; - -/** - * @return {Object} File browser private API. - */ -Gallery.getFileBrowserPrivate = function() { - return chrome.fileBrowserPrivate || window.top.chrome.fileBrowserPrivate; -}; - -/** - * @return {boolean} True if some tool is currently active. - */ -Gallery.prototype.hasActiveTool = function() { - return this.currentMode_.hasActiveTool() || - this.isSharing_() || this.isRenaming_(); -}; - -/** -* External user action event handler. -* @private -*/ -Gallery.prototype.onUserAction_ = function() { - this.closeShareMenu_(); - // Show the toolbar and hide it after the default timeout. - this.inactivityWatcher_.kick(); -}; - -/** - * Sets the current mode, update the UI. - * @param {Object} mode Current mode. - * @private - */ -Gallery.prototype.setCurrentMode_ = function(mode) { - if (mode !== this.slideMode_ && mode !== this.mosaicMode_) - console.error('Invalid Gallery mode'); - - this.currentMode_ = mode; - this.container_.setAttribute('mode', this.currentMode_.getName()); - this.updateSelectionAndState_(); - this.updateButtons_(); -}; - -/** - * Mode toggle event handler. - * @param {function=} opt_callback Callback. - * @param {Event=} opt_event Event that caused this call. - * @private - */ -Gallery.prototype.toggleMode_ = function(opt_callback, opt_event) { - if (!this.modeButton_) - return; - - if (this.changingMode_) // Do not re-enter while changing the mode. - return; - - if (opt_event) - this.onUserAction_(); - - this.changingMode_ = true; - - var onModeChanged = function() { - this.changingMode_ = false; - if (opt_callback) opt_callback(); - }.bind(this); - - var tileIndex = Math.max(0, this.selectionModel_.selectedIndex); - - var mosaic = this.mosaicMode_.getMosaic(); - var tileRect = mosaic.getTileRect(tileIndex); - - if (this.currentMode_ === this.slideMode_) { - this.setCurrentMode_(this.mosaicMode_); - mosaic.transform( - tileRect, this.slideMode_.getSelectedImageRect(), true /* instant */); - this.slideMode_.leave(tileRect, - function() { - // Animate back to normal position. - mosaic.transform(); - mosaic.show(); - onModeChanged(); - }.bind(this)); - } else { - this.setCurrentMode_(this.slideMode_); - this.slideMode_.enter(tileRect, - function() { - // Animate to zoomed position. - mosaic.transform(tileRect, this.slideMode_.getSelectedImageRect()); - mosaic.hide(); - }.bind(this), - onModeChanged); - } -}; - -/** - * Deletes the selected items. - * @private - */ -Gallery.prototype.delete_ = function() { - this.onUserAction_(); - - // Clone the sorted selected indexes array. - var indexesToRemove = this.selectionModel_.selectedIndexes.slice(); - if (!indexesToRemove.length) - return; - - /* TODO(dgozman): Implement Undo delete, Remove the confirmation dialog. */ - - var itemsToRemove = this.getSelectedItems(); - var plural = itemsToRemove.length > 1; - var param = plural ? itemsToRemove.length : itemsToRemove[0].getFileName(); - - function deleteNext() { - if (!itemsToRemove.length) - return; // All deleted. - - // TODO(hirono): Use fileOperationManager. - var entry = itemsToRemove.pop().getEntry(); - entry.remove(deleteNext, function() { - util.flog('Error deleting: ' + entry.fullPath, deleteNext); - }); - } - - // Prevent the Gallery from handling Esc and Enter. - this.document_.body.removeEventListener('keydown', this.keyDownBound_); - var restoreListener = function() { - this.document_.body.addEventListener('keydown', this.keyDownBound_); - }.bind(this); - - cr.ui.dialogs.BaseDialog.OK_LABEL = this.displayStringFunction_( - 'GALLERY_OK_LABEL'); - cr.ui.dialogs.BaseDialog.CANCEL_LABEL = - this.displayStringFunction_('GALLERY_CANCEL_LABEL'); - var confirm = new cr.ui.dialogs.ConfirmDialog(this.container_); - confirm.show( - this.displayStringFunction_(plural ? 'GALLERY_CONFIRM_DELETE_SOME' : - 'GALLERY_CONFIRM_DELETE_ONE', param), - function() { - restoreListener(); - this.selectionModel_.unselectAll(); - this.selectionModel_.leadIndex = -1; - // Remove items from the data model, starting from the highest index. - while (indexesToRemove.length) - this.dataModel_.splice(indexesToRemove.pop(), 1); - // Delete actual files. - deleteNext(); - }.bind(this), - function() { - // Restore the listener after a timeout so that ESC is processed. - setTimeout(restoreListener, 0); - }); -}; - -/** - * @return {Array.<Gallery.Item>} Current selection. - */ -Gallery.prototype.getSelectedItems = function() { - return this.selectionModel_.selectedIndexes.map( - this.dataModel_.item.bind(this.dataModel_)); -}; - -/** - * @return {Array.<Entry>} Array of currently selected entries. - */ -Gallery.prototype.getSelectedEntries = function() { - return this.selectionModel_.selectedIndexes.map(function(index) { - return this.dataModel_.item(index).getEntry(); - }.bind(this)); -}; - -/** - * @return {Gallery.Item} Current single selection. - */ -Gallery.prototype.getSingleSelectedItem = function() { - var items = this.getSelectedItems(); - if (items.length > 1) - throw new Error('Unexpected multiple selection'); - return items[0]; -}; - -/** - * Selection change event handler. - * @private - */ -Gallery.prototype.onSelection_ = function() { - this.updateSelectionAndState_(); - this.updateShareMenu_(); -}; - -/** - * Data model splice event handler. - * @private - */ -Gallery.prototype.onSplice_ = function() { - this.selectionModel_.adjustLength(this.dataModel_.length); -}; - -/** - * Content change event handler. - * @param {Event} event Event. - * @private -*/ -Gallery.prototype.onContentChange_ = function(event) { - var index = this.dataModel_.indexOf(event.item); - if (index !== this.selectionModel_.selectedIndex) - console.error('Content changed for unselected item'); - this.updateSelectionAndState_(); -}; - -/** - * Keydown handler. - * - * @param {Event} event Event. - * @private - */ -Gallery.prototype.onKeyDown_ = function(event) { - var wasSharing = this.isSharing_(); - this.closeShareMenu_(); - - if (this.currentMode_.onKeyDown(event)) - return; - - switch (util.getKeyModifiers(event) + event.keyIdentifier) { - case 'U+0008': // Backspace. - // The default handler would call history.back and close the Gallery. - event.preventDefault(); - break; - - case 'U+001B': // Escape - // Swallow Esc if it closed the Share menu, otherwise close the Gallery. - if (!wasSharing) - this.onBack_(); - break; - - case 'U+004D': // 'm' switches between Slide and Mosaic mode. - this.toggleMode_(null, event); - break; - - case 'U+0056': // 'v' - this.slideMode_.startSlideshow(SlideMode.SLIDESHOW_INTERVAL_FIRST, event); - break; - - case 'U+007F': // Delete - case 'Shift-U+0033': // Shift+'3' (Delete key might be missing). - this.delete_(); - break; - } -}; - -// Name box and rename support. - -/** - * Updates the UI related to the selected item and the persistent state. - * - * @private - */ -Gallery.prototype.updateSelectionAndState_ = function() { - var path; - var displayName = ''; - - var selectedItems = this.getSelectedItems(); - if (selectedItems.length === 1) { - var item = selectedItems[0]; - var entry = item.getEntry(); - window.top.document.title = entry.name; - displayName = ImageUtil.getDisplayNameFromName(entry.name); - } else if (selectedItems.length > 1 && this.context_.curDirEntry) { - // If the Gallery was opened on search results the search query will not be - // recorded in the app state and the relaunch will just open the gallery - // in the curDirEntry directory. - path = this.context_.curDirEntry.fullPath; - window.top.document.title = this.context_.curDirEntry.name; - displayName = - this.displayStringFunction_('GALLERY_ITEMS_SELECTED', - selectedItems.length); - } - - window.top.util.updateAppState(path, - {gallery: (this.currentMode_ === this.mosaicMode_ ? 'mosaic' : 'slide')}); - - // We can't rename files in readonly directory. - // We can only rename a single file. - this.filenameEdit_.disabled = selectedItems.length !== 1 || - this.context_.readonlyDirName; - - this.filenameEdit_.value = displayName; - - // Resolve real filesystem path of the current file. - if (this.selectionModel_.selectedIndexes.length) { - var selectedIndex = this.selectionModel_.selectedIndex; - var selectedItem = - this.dataModel_.item(this.selectionModel_.selectedIndex); - this.selectedEntry_ = selectedItem.getEntry(); - } -}; - -/** - * Click event handler on filename edit box - * @private - */ -Gallery.prototype.onFilenameFocus_ = function() { - ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', true); - this.filenameEdit_.originalValue = this.filenameEdit_.value; - setTimeout(this.filenameEdit_.select.bind(this.filenameEdit_), 0); - this.onUserAction_(); -}; - -/** - * Blur event handler on filename edit box. - * - * @param {Event} event Blur event. - * @return {boolean} if default action should be prevented. - * @private - */ -Gallery.prototype.onFilenameEditBlur_ = function(event) { - if (this.filenameEdit_.value && this.filenameEdit_.value[0] === '.') { - this.prompt_.show('GALLERY_FILE_HIDDEN_NAME', 5000); - this.filenameEdit_.focus(); - event.stopPropagation(); - event.preventDefault(); - return false; - } - - var item = this.getSingleSelectedItem(); - var oldEntry = item.getEntry(); - - var onFileExists = function() { - this.prompt_.show('GALLERY_FILE_EXISTS', 3000); - this.filenameEdit_.value = name; - this.filenameEdit_.focus(); - }.bind(this); - - var onSuccess = function() { - var event = new Event('content'); - event.item = item; - event.oldEntry = oldEntry; - event.metadata = null; // Metadata unchanged. - this.dataModel_.dispatchEvent(event); - }.bind(this); - - if (this.filenameEdit_.value) { - this.getSingleSelectedItem().rename( - this.filenameEdit_.value, onSuccess, onFileExists); - } - - ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', false); - this.onUserAction_(); -}; - -/** - * Keydown event handler on filename edit box - * @private - */ -Gallery.prototype.onFilenameEditKeydown_ = function() { - switch (event.keyCode) { - case 27: // Escape - this.filenameEdit_.value = this.filenameEdit_.originalValue; - this.filenameEdit_.blur(); - break; - - case 13: // Enter - this.filenameEdit_.blur(); - break; - } - event.stopPropagation(); -}; - -/** - * @return {boolean} True if file renaming is currently in progress. - * @private - */ -Gallery.prototype.isRenaming_ = function() { - return this.filenameSpacer_.hasAttribute('renaming'); -}; - -/** - * Content area click handler. - * @private - */ -Gallery.prototype.onContentClick_ = function() { - this.closeShareMenu_(); - this.filenameEdit_.blur(); -}; - -// Share button support. - -/** - * @return {boolean} True if the Share menu is active. - * @private - */ -Gallery.prototype.isSharing_ = function() { - return !this.shareMenu_.hidden; -}; - -/** - * Close Share menu if it is open. - * @private - */ -Gallery.prototype.closeShareMenu_ = function() { - if (this.isSharing_()) - this.toggleShare_(); -}; - -/** - * Share button handler. - * @private - */ -Gallery.prototype.toggleShare_ = function() { - if (!this.shareButton_.hasAttribute('disabled')) - this.shareMenu_.hidden = !this.shareMenu_.hidden; - this.inactivityWatcher_.check(); -}; - -/** - * Updates available actions list based on the currently selected urls. - * @private. - */ -Gallery.prototype.updateShareMenu_ = function() { - var entries = this.getSelectedEntries(); - - function isShareAction(task) { - var taskParts = task.taskId.split('|'); - return taskParts[0] !== chrome.runtime.id; - } - - var api = Gallery.getFileBrowserPrivate(); - var mimeTypes = []; // TODO(kaznacheev) Collect mime types properly. - - var createShareMenu = function(tasks) { - var wasHidden = this.shareMenu_.hidden; - this.shareMenu_.hidden = true; - var items = this.shareMenu_.querySelectorAll('.item'); - for (var i = 0; i !== items.length; i++) { - items[i].parentNode.removeChild(items[i]); - } - - for (var t = 0; t !== tasks.length; t++) { - var task = tasks[t]; - if (!isShareAction(task)) continue; - - var item = util.createChild(this.shareMenu_, 'item'); - item.textContent = task.title; - item.style.backgroundImage = 'url(' + task.iconUrl + ')'; - item.addEventListener('click', function(taskId) { - this.toggleShare_(); // Hide the menu. - this.executeWhenReady(api.executeTask.bind(api, taskId, entries)); - }.bind(this, task.taskId)); - } - - var empty = this.shareMenu_.querySelector('.item') === null; - ImageUtil.setAttribute(this.shareButton_, 'disabled', empty); - this.shareMenu_.hidden = wasHidden || empty; - }.bind(this); - - // Create or update the share menu with a list of sharing tasks and show - // or hide the share button. - // TODO(mtomasz): Pass Entries directly, instead of URLs. - if (!entries.length) - createShareMenu([]); // Empty list of tasks, since there is no selection. - else - api.getFileTasks(util.entriesToURLs(entries), mimeTypes, createShareMenu); -}; - -/** - * Updates thumbnails. - * @private - */ -Gallery.prototype.updateThumbnails_ = function() { - if (this.currentMode_ === this.slideMode_) - this.slideMode_.updateThumbnails(); - - if (this.mosaicMode_) { - var mosaic = this.mosaicMode_.getMosaic(); - if (mosaic.isInitialized()) - mosaic.reload(); - } -}; - -/** - * Updates buttons. - * @private - */ -Gallery.prototype.updateButtons_ = function() { - if (this.modeButton_) { - var oppositeMode = - this.currentMode_ === this.slideMode_ ? this.mosaicMode_ : - this.slideMode_; - this.modeButton_.title = - this.displayStringFunction_(oppositeMode.getTitle()); - } -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/photo/gallery_item.js b/chromium/chrome/browser/resources/file_manager/foreground/js/photo/gallery_item.js deleted file mode 100644 index 2ae80c92dd7..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/photo/gallery_item.js +++ /dev/null @@ -1,227 +0,0 @@ -// 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. - -'use strict'; - -/** - * Object representing an image item (a photo or a video). - * - * @param {FileEntry} entry Image entry. - * @constructor - */ -Gallery.Item = function(entry) { - this.entry_ = entry; - this.original_ = true; -}; - -/** - * @return {FileEntry} Image entry. - */ -Gallery.Item.prototype.getEntry = function() { return this.entry_ }; - -/** - * @return {string} File name. - */ -Gallery.Item.prototype.getFileName = function() { - return this.entry_.name; -}; - -/** - * @return {boolean} True if this image has not been created in this session. - */ -Gallery.Item.prototype.isOriginal = function() { return this.original_ }; - -// TODO: Localize? -/** - * @type {string} Suffix for a edited copy file name. - */ -Gallery.Item.COPY_SIGNATURE = ' - Edited'; - -/** - * Regular expression to match '... - Edited'. - * @type {RegExp} - */ -Gallery.Item.REGEXP_COPY_0 = - new RegExp('^(.+)' + Gallery.Item.COPY_SIGNATURE + '$'); - -/** - * Regular expression to match '... - Edited (N)'. - * @type {RegExp} - */ -Gallery.Item.REGEXP_COPY_N = - new RegExp('^(.+)' + Gallery.Item.COPY_SIGNATURE + ' \\((\\d+)\\)$'); - -/** - * Creates a name for an edited copy of the file. - * - * @param {Entry} dirEntry Entry. - * @param {function} callback Callback. - * @private - */ -Gallery.Item.prototype.createCopyName_ = function(dirEntry, callback) { - var name = this.getFileName(); - - // If the item represents a file created during the current Gallery session - // we reuse it for subsequent saves instead of creating multiple copies. - if (!this.original_) { - callback(name); - return; - } - - var ext = ''; - var index = name.lastIndexOf('.'); - if (index != -1) { - ext = name.substr(index); - name = name.substr(0, index); - } - - if (!ext.match(/jpe?g/i)) { - // Chrome can natively encode only two formats: JPEG and PNG. - // All non-JPEG images are saved in PNG, hence forcing the file extension. - ext = '.png'; - } - - function tryNext(tries) { - // All the names are used. Let's overwrite the last one. - if (tries == 0) { - setTimeout(callback, 0, name + ext); - return; - } - - // If the file name contains the copy signature add/advance the sequential - // number. - var matchN = Gallery.Item.REGEXP_COPY_N.exec(name); - var match0 = Gallery.Item.REGEXP_COPY_0.exec(name); - if (matchN && matchN[1] && matchN[2]) { - var copyNumber = parseInt(matchN[2], 10) + 1; - name = matchN[1] + Gallery.Item.COPY_SIGNATURE + ' (' + copyNumber + ')'; - } else if (match0 && match0[1]) { - name = match0[1] + Gallery.Item.COPY_SIGNATURE + ' (1)'; - } else { - name += Gallery.Item.COPY_SIGNATURE; - } - - dirEntry.getFile(name + ext, {create: false, exclusive: false}, - tryNext.bind(null, tries - 1), - callback.bind(null, name + ext)); - } - - tryNext(10); -}; - -/** - * Writes the new item content to the file. - * - * @param {Entry} overrideDir Directory to save to. If null, save to the same - * directory as the original. - * @param {boolean} overwrite True if overwrite, false if copy. - * @param {HTMLCanvasElement} canvas Source canvas. - * @param {ImageEncoder.MetadataEncoder} metadataEncoder MetadataEncoder. - * @param {function(boolean)=} opt_callback Callback accepting true for success. - */ -Gallery.Item.prototype.saveToFile = function( - overrideDir, overwrite, canvas, metadataEncoder, opt_callback) { - ImageUtil.metrics.startInterval(ImageUtil.getMetricName('SaveTime')); - - var name = this.getFileName(); - - var onSuccess = function(entry) { - ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 1, 2); - ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('SaveTime')); - this.entry_ = entry; - if (opt_callback) opt_callback(true); - }.bind(this); - - function onError(error) { - console.error('Error saving from gallery', name, error); - ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 0, 2); - if (opt_callback) opt_callback(false); - } - - function doSave(newFile, fileEntry) { - fileEntry.createWriter(function(fileWriter) { - function writeContent() { - fileWriter.onwriteend = onSuccess.bind(null, fileEntry); - fileWriter.write(ImageEncoder.getBlob(canvas, metadataEncoder)); - } - fileWriter.onerror = function(error) { - onError(error); - // Disable all callbacks on the first error. - fileWriter.onerror = null; - fileWriter.onwriteend = null; - }; - if (newFile) { - writeContent(); - } else { - fileWriter.onwriteend = writeContent; - fileWriter.truncate(0); - } - }, onError); - } - - function getFile(dir, newFile) { - dir.getFile(name, {create: newFile, exclusive: newFile}, - doSave.bind(null, newFile), onError); - } - - function checkExistence(dir) { - dir.getFile(name, {create: false, exclusive: false}, - getFile.bind(null, dir, false /* existing file */), - getFile.bind(null, dir, true /* create new file */)); - } - - var saveToDir = function(dir) { - if (overwrite) { - checkExistence(dir); - } else { - this.createCopyName_(dir, function(copyName) { - this.original_ = false; - name = copyName; - checkExistence(dir); - }.bind(this)); - } - }.bind(this); - - if (overrideDir) { - saveToDir(overrideDir); - } else { - this.entry_.getParent(saveToDir, onError); - } -}; - -/** - * Renames the file. - * - * @param {string} displayName New display name (without the extension). - * @param {function()} onSuccess Success callback. - * @param {function()} onExists Called if the file with the new name exists. - */ -Gallery.Item.prototype.rename = function(displayName, onSuccess, onExists) { - var fileName = this.entry_.name.replace( - ImageUtil.getDisplayNameFromName(this.entry_.name), displayName); - - if (name === this.entry_.name) - return; - - var onRenamed = function(entry) { - this.entry_ = entry; - onSuccess(); - }.bind(this); - - var onError = function() { - console.error('Rename error: "' + oldName + '" to "' + newName + '"'); - }; - - var moveIfDoesNotExist = function(parentDir) { - parentDir.getFile( - fileName, - {create: false, exclusive: false}, - onExists, - function() { - this.entry_.moveTo(parentDir, fileName, onRenamed, onError); - }.bind(this)); - }.bind(this); - - this.entry_.getParent(moveIfDoesNotExist, onError); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/photo/gallery_scripts.js b/chromium/chrome/browser/resources/file_manager/foreground/js/photo/gallery_scripts.js deleted file mode 100644 index 336fa207938..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/photo/gallery_scripts.js +++ /dev/null @@ -1,70 +0,0 @@ -// 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. - -// The include directives are put into Javascript-style comments to prevent -// parsing errors in non-flattened mode. The flattener still sees them. -// Note that this makes the flattener to comment out the first line of the -// included file but that's all right since any javascript file should start -// with a copyright comment anyway. - -//<include src="../metrics.js"> - -//<include src="../../../../image_loader/image_loader_client.js"/> - -//<include src="../../../../../../../ui/webui/resources/js/cr.js"> -//<include src="../../../../../../../ui/webui/resources/js/event_tracker.js"> -//<include src="../../../../../../../ui/webui/resources/js/load_time_data.js"> - -//<include src="../../../../../../../ui/webui/resources/js/cr/ui.js"> -//<include src="../../../../../../../ui/webui/resources/js/cr/event_target.js"> -//<include src="../../../../../../../ui/webui/resources/js/cr/ui/touch_handler.js"> -//<include src="../../../../../../../ui/webui/resources/js/cr/ui/array_data_model.js"> -//<include src="../../../../../../../ui/webui/resources/js/cr/ui/dialogs.js"> -//<include src="../../../../../../../ui/webui/resources/js/cr/ui/list_item.js"> -//<include src="../../../../../../../ui/webui/resources/js/cr/ui/list_selection_model.js"> -//<include src="../../../../../../../ui/webui/resources/js/cr/ui/list_single_selection_model.js"> -//<include src="../../../../../../../ui/webui/resources/js/cr/ui/list_selection_controller.js"> -//<include src="../../../../../../../ui/webui/resources/js/cr/ui/list.js"> -//<include src="../../../../../../../ui/webui/resources/js/cr/ui/grid.js"> - -(function() { -// 'strict mode' is invoked for this scope. - -//<include src="../../../common/js/async_util.js"> -//<include src="../../../common/js/util.js"> -//<include src="../../../common/js/path_util.js"> -//<include src="../file_type.js"> -//<include src="../volume_manager_wrapper.js"> - -//<include src="../image_editor/image_util.js"/> -//<include src="../image_editor/viewport.js"/> -//<include src="../image_editor/image_buffer.js"/> -//<include src="../image_editor/image_view.js"/> -//<include src="../image_editor/commands.js"/> -//<include src="../image_editor/image_editor.js"/> -//<include src="../image_editor/image_transform.js"/> -//<include src="../image_editor/image_adjust.js"/> -//<include src="../image_editor/filter.js"/> -//<include src="../image_editor/image_encoder.js"/> -//<include src="../image_editor/exif_encoder.js"/> - -//<include src="../media/media_controls.js"/> -//<include src="../media/media_util.js"/> -//<include src="../media/util.js"/> - -//<include src="../metadata/metadata_cache.js"/> - -//<include src="gallery.js"> -//<include src="gallery_item.js"> -//<include src="mosaic_mode.js"> -//<include src="slide_mode.js"> -//<include src="ribbon.js"> - -// Exports -window.ImageUtil = ImageUtil; -window.Gallery = Gallery; -window.beforeunload = beforeunload; -window.unload = unload; - -})(); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/photo/mosaic_mode.js b/chromium/chrome/browser/resources/file_manager/foreground/js/photo/mosaic_mode.js deleted file mode 100644 index 6231864bbd8..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/photo/mosaic_mode.js +++ /dev/null @@ -1,2012 +0,0 @@ -// 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. - -'use strict'; - -/** - * @param {Element} container Content container. - * @param {cr.ui.ArrayDataModel} dataModel Data model. - * @param {cr.ui.ListSelectionModel} selectionModel Selection model. - * @param {MetadataCache} metadataCache Metadata cache. - * @param {function} toggleMode Function to switch to the Slide mode. - * @constructor - */ -function MosaicMode( - container, dataModel, selectionModel, metadataCache, toggleMode) { - this.mosaic_ = new Mosaic( - container.ownerDocument, dataModel, selectionModel, metadataCache); - container.appendChild(this.mosaic_); - - this.toggleMode_ = toggleMode; - this.mosaic_.addEventListener('dblclick', this.toggleMode_); - this.showingTimeoutID_ = null; -} - -/** - * @return {Mosaic} The mosaic control. - */ -MosaicMode.prototype.getMosaic = function() { return this.mosaic_ }; - -/** - * @return {string} Mode name. - */ -MosaicMode.prototype.getName = function() { return 'mosaic' }; - -/** - * @return {string} Mode title. - */ -MosaicMode.prototype.getTitle = function() { return 'GALLERY_MOSAIC' }; - -/** - * Execute an action (this mode has no busy state). - * @param {function} action Action to execute. - */ -MosaicMode.prototype.executeWhenReady = function(action) { action() }; - -/** - * @return {boolean} Always true (no toolbar fading in this mode). - */ -MosaicMode.prototype.hasActiveTool = function() { return true }; - -/** - * Keydown handler. - * - * @param {Event} event Event. - * @return {boolean} True if processed. - */ -MosaicMode.prototype.onKeyDown = function(event) { - switch (util.getKeyModifiers(event) + event.keyIdentifier) { - case 'Enter': - this.toggleMode_(); - return true; - } - return this.mosaic_.onKeyDown(event); -}; - -//////////////////////////////////////////////////////////////////////////////// - -/** - * Mosaic control. - * - * @param {Document} document Document. - * @param {cr.ui.ArrayDataModel} dataModel Data model. - * @param {cr.ui.ListSelectionModel} selectionModel Selection model. - * @param {MetadataCache} metadataCache Metadata cache. - * @return {Element} Mosaic element. - * @constructor - */ -function Mosaic(document, dataModel, selectionModel, metadataCache) { - var self = document.createElement('div'); - Mosaic.decorate(self, dataModel, selectionModel, metadataCache); - return self; -} - -/** - * Inherit from HTMLDivElement. - */ -Mosaic.prototype.__proto__ = HTMLDivElement.prototype; - -/** - * Default layout delay in ms. - * @const - * @type {number} - */ -Mosaic.LAYOUT_DELAY = 200; - -/** - * Smooth scroll animation duration when scrolling using keyboard or - * clicking on a partly visible tile. In ms. - * @const - * @type {number} - */ -Mosaic.ANIMATED_SCROLL_DURATION = 500; - -/** - * Decorate a Mosaic instance. - * - * @param {Mosaic} self Self pointer. - * @param {cr.ui.ArrayDataModel} dataModel Data model. - * @param {cr.ui.ListSelectionModel} selectionModel Selection model. - * @param {MetadataCache} metadataCache Metadata cache. - */ -Mosaic.decorate = function(self, dataModel, selectionModel, metadataCache) { - self.__proto__ = Mosaic.prototype; - self.className = 'mosaic'; - - self.dataModel_ = dataModel; - self.selectionModel_ = selectionModel; - self.metadataCache_ = metadataCache; - - // Initialization is completed lazily on the first call to |init|. -}; - -/** - * Initialize the mosaic element. - */ -Mosaic.prototype.init = function() { - if (this.tiles_) - return; // Already initialized, nothing to do. - - this.layoutModel_ = new Mosaic.Layout(); - this.onResize_(); - - this.selectionController_ = - new Mosaic.SelectionController(this.selectionModel_, this.layoutModel_); - - this.tiles_ = []; - for (var i = 0; i != this.dataModel_.length; i++) - this.tiles_.push(new Mosaic.Tile(this, this.dataModel_.item(i))); - - this.selectionModel_.selectedIndexes.forEach(function(index) { - this.tiles_[index].select(true); - }.bind(this)); - - this.initTiles_(this.tiles_); - - // The listeners might be called while some tiles are still loading. - this.initListeners_(); -}; - -/** - * @return {boolean} Whether mosaic is initialized. - */ -Mosaic.prototype.isInitialized = function() { - return !!this.tiles_; -}; - -/** - * Start listening to events. - * - * We keep listening to events even when the mosaic is hidden in order to - * keep the layout up to date. - * - * @private - */ -Mosaic.prototype.initListeners_ = function() { - this.ownerDocument.defaultView.addEventListener( - 'resize', this.onResize_.bind(this)); - - var mouseEventBound = this.onMouseEvent_.bind(this); - this.addEventListener('mousemove', mouseEventBound); - this.addEventListener('mousedown', mouseEventBound); - this.addEventListener('mouseup', mouseEventBound); - this.addEventListener('scroll', this.onScroll_.bind(this)); - - this.selectionModel_.addEventListener('change', this.onSelection_.bind(this)); - this.selectionModel_.addEventListener('leadIndexChange', - this.onLeadChange_.bind(this)); - - this.dataModel_.addEventListener('splice', this.onSplice_.bind(this)); - this.dataModel_.addEventListener('content', this.onContentChange_.bind(this)); -}; - -/** - * Smoothly scrolls the container to the specified position using - * f(x) = sqrt(x) speed function normalized to animation duration. - * @param {number} targetPosition Horizontal scroll position in pixels. - */ -Mosaic.prototype.animatedScrollTo = function(targetPosition) { - if (this.scrollAnimation_) { - webkitCancelAnimationFrame(this.scrollAnimation_); - this.scrollAnimation_ = null; - } - - // Mouse move events are fired without touching the mouse because of scrolling - // the container. Therefore, these events have to be suppressed. - this.suppressHovering_ = true; - - // Calculates integral area from t1 to t2 of f(x) = sqrt(x) dx. - var integral = function(t1, t2) { - return 2.0 / 3.0 * Math.pow(t2, 3.0 / 2.0) - - 2.0 / 3.0 * Math.pow(t1, 3.0 / 2.0); - }; - - var delta = targetPosition - this.scrollLeft; - var factor = delta / integral(0, Mosaic.ANIMATED_SCROLL_DURATION); - var startTime = Date.now(); - var lastPosition = 0; - var scrollOffset = this.scrollLeft; - - var animationFrame = function() { - var position = Date.now() - startTime; - var step = factor * - integral(Math.max(0, Mosaic.ANIMATED_SCROLL_DURATION - position), - Math.max(0, Mosaic.ANIMATED_SCROLL_DURATION - lastPosition)); - scrollOffset += step; - - var oldScrollLeft = this.scrollLeft; - var newScrollLeft = Math.round(scrollOffset); - - if (oldScrollLeft != newScrollLeft) - this.scrollLeft = newScrollLeft; - - if (step == 0 || this.scrollLeft != newScrollLeft) { - this.scrollAnimation_ = null; - // Release the hovering lock after a safe delay to avoid hovering - // a tile because of altering |this.scrollLeft|. - setTimeout(function() { - if (!this.scrollAnimation_) - this.suppressHovering_ = false; - }.bind(this), 100); - } else { - // Continue the animation. - this.scrollAnimation_ = requestAnimationFrame(animationFrame); - } - - lastPosition = position; - }.bind(this); - - // Start the animation. - this.scrollAnimation_ = requestAnimationFrame(animationFrame); -}; - -/** - * @return {Mosaic.Tile} Selected tile or undefined if no selection. - */ -Mosaic.prototype.getSelectedTile = function() { - return this.tiles_ && this.tiles_[this.selectionModel_.selectedIndex]; -}; - -/** - * @param {number} index Tile index. - * @return {Rect} Tile's image rectangle. - */ -Mosaic.prototype.getTileRect = function(index) { - var tile = this.tiles_[index]; - return tile && tile.getImageRect(); -}; - -/** - * @param {number} index Tile index. - * Scroll the given tile into the viewport. - */ -Mosaic.prototype.scrollIntoView = function(index) { - var tile = this.tiles_[index]; - if (tile) tile.scrollIntoView(); -}; - -/** - * Initializes multiple tiles. - * - * @param {Array.<Mosaic.Tile>} tiles Array of tiles. - * @param {function()=} opt_callback Completion callback. - * @private - */ -Mosaic.prototype.initTiles_ = function(tiles, opt_callback) { - // We do not want to use tile indices in asynchronous operations because they - // do not survive data model splices. Copy tile references instead. - tiles = tiles.slice(); - - // Throttle the metadata access so that we do not overwhelm the file system. - var MAX_CHUNK_SIZE = 10; - - var loadChunk = function() { - if (!tiles.length) { - if (opt_callback) opt_callback(); - return; - } - var chunkSize = Math.min(tiles.length, MAX_CHUNK_SIZE); - var loaded = 0; - for (var i = 0; i != chunkSize; i++) { - this.initTile_(tiles.shift(), function() { - if (++loaded == chunkSize) { - this.layout(); - loadChunk(); - } - }.bind(this)); - } - }.bind(this); - - loadChunk(); -}; - -/** - * Initializes a single tile. - * - * @param {Mosaic.Tile} tile Tile. - * @param {function()} callback Completion callback. - * @private - */ -Mosaic.prototype.initTile_ = function(tile, callback) { - var onImageMeasured = callback; - this.metadataCache_.get(tile.getItem().getEntry(), Gallery.METADATA_TYPE, - function(metadata) { - tile.init(metadata, onImageMeasured); - }); -}; - -/** - * Reload all tiles. - */ -Mosaic.prototype.reload = function() { - this.layoutModel_.reset_(); - this.tiles_.forEach(function(t) { t.markUnloaded() }); - this.initTiles_(this.tiles_); -}; - -/** - * Layout the tiles in the order of their indices. - * - * Starts where it last stopped (at #0 the first time). - * Stops when all tiles are processed or when the next tile is still loading. - */ -Mosaic.prototype.layout = function() { - if (this.layoutTimer_) { - clearTimeout(this.layoutTimer_); - this.layoutTimer_ = null; - } - while (true) { - var index = this.layoutModel_.getTileCount(); - if (index == this.tiles_.length) - break; // All tiles done. - var tile = this.tiles_[index]; - if (!tile.isInitialized()) - break; // Next layout will try to restart from here. - this.layoutModel_.add(tile, index + 1 == this.tiles_.length); - } - this.loadVisibleTiles_(); -}; - -/** - * Schedule the layout. - * - * @param {number=} opt_delay Delay in ms. - */ -Mosaic.prototype.scheduleLayout = function(opt_delay) { - if (!this.layoutTimer_) { - this.layoutTimer_ = setTimeout(function() { - this.layoutTimer_ = null; - this.layout(); - }.bind(this), opt_delay || 0); - } -}; - -/** - * Resize handler. - * - * @private - */ -Mosaic.prototype.onResize_ = function() { - this.layoutModel_.setViewportSize(this.clientWidth, this.clientHeight - - (Mosaic.Layout.PADDING_TOP + Mosaic.Layout.PADDING_BOTTOM)); - this.scheduleLayout(); -}; - -/** - * Mouse event handler. - * - * @param {Event} event Event. - * @private - */ -Mosaic.prototype.onMouseEvent_ = function(event) { - // Navigating with mouse, enable hover state. - if (!this.suppressHovering_) - this.classList.add('hover-visible'); - - if (event.type == 'mousemove') - return; - - var index = -1; - for (var target = event.target; - target && (target != this); - target = target.parentNode) { - if (target.classList.contains('mosaic-tile')) { - index = this.dataModel_.indexOf(target.getItem()); - break; - } - } - this.selectionController_.handlePointerDownUp(event, index); -}; - -/** - * Scroll handler. - * @private - */ -Mosaic.prototype.onScroll_ = function() { - requestAnimationFrame(function() { - this.loadVisibleTiles_(); - }.bind(this)); -}; - -/** - * Selection change handler. - * - * @param {Event} event Event. - * @private - */ -Mosaic.prototype.onSelection_ = function(event) { - for (var i = 0; i != event.changes.length; i++) { - var change = event.changes[i]; - var tile = this.tiles_[change.index]; - if (tile) tile.select(change.selected); - } -}; - -/** - * Lead item change handler. - * - * @param {Event} event Event. - * @private - */ -Mosaic.prototype.onLeadChange_ = function(event) { - var index = event.newValue; - if (index >= 0) { - var tile = this.tiles_[index]; - if (tile) tile.scrollIntoView(); - } -}; - -/** - * Splice event handler. - * - * @param {Event} event Event. - * @private - */ -Mosaic.prototype.onSplice_ = function(event) { - var index = event.index; - this.layoutModel_.invalidateFromTile_(index); - - if (event.removed.length) { - for (var t = 0; t != event.removed.length; t++) - this.removeChild(this.tiles_[index + t]); - - this.tiles_.splice(index, event.removed.length); - this.scheduleLayout(Mosaic.LAYOUT_DELAY); - } - - if (event.added.length) { - var newTiles = []; - for (var t = 0; t != event.added.length; t++) - newTiles.push(new Mosaic.Tile(this, this.dataModel_.item(index + t))); - - this.tiles_.splice.apply(this.tiles_, [index, 0].concat(newTiles)); - this.initTiles_(newTiles); - } - - if (this.tiles_.length != this.dataModel_.length) - console.error('Mosaic is out of sync'); -}; - -/** - * Content change handler. - * - * @param {Event} event Event. - * @private - */ -Mosaic.prototype.onContentChange_ = function(event) { - if (!this.tiles_) - return; - - if (!event.metadata) - return; // Thumbnail unchanged, nothing to do. - - var index = this.dataModel_.indexOf(event.item); - if (index != this.selectionModel_.selectedIndex) - console.error('Content changed for unselected item'); - - this.layoutModel_.invalidateFromTile_(index); - this.tiles_[index].init(event.metadata, function() { - this.tiles_[index].unload(); - this.tiles_[index].load( - Mosaic.Tile.LoadMode.HIGH_DPI, - this.scheduleLayout.bind(this, Mosaic.LAYOUT_DELAY)); - }.bind(this)); -}; - -/** - * Keydown event handler. - * - * @param {Event} event Event. - * @return {boolean} True if the event has been consumed. - */ -Mosaic.prototype.onKeyDown = function(event) { - this.selectionController_.handleKeyDown(event); - if (event.defaultPrevented) // Navigating with keyboard, hide hover state. - this.classList.remove('hover-visible'); - return event.defaultPrevented; -}; - -/** - * @return {boolean} True if the mosaic zoom effect can be applied. It is - * too slow if there are to many images. - * TODO(kaznacheev): Consider unloading the images that are out of the viewport. - */ -Mosaic.prototype.canZoom = function() { - return this.tiles_.length < 100; -}; - -/** - * Show the mosaic. - */ -Mosaic.prototype.show = function() { - var duration = ImageView.MODE_TRANSITION_DURATION; - if (this.canZoom()) { - // Fade in in parallel with the zoom effect. - this.setAttribute('visible', 'zooming'); - } else { - // Mosaic is not animating but the large image is. Fade in the mosaic - // shortly before the large image animation is done. - duration -= 100; - } - this.showingTimeoutID_ = setTimeout(function() { - this.showingTimeoutID_ = null; - // Make the selection visible. - // If the mosaic is not animated it will start fading in now. - this.setAttribute('visible', 'normal'); - this.loadVisibleTiles_(); - }.bind(this), duration); -}; - -/** - * Hide the mosaic. - */ -Mosaic.prototype.hide = function() { - if (this.showingTimeoutID_ != null) { - clearTimeout(this.showingTimeoutID_); - this.showingTimeoutID_ = null; - } - this.removeAttribute('visible'); -}; - -/** - * Checks if the mosaic view is visible. - * @return {boolean} True if visible, false otherwise. - * @private - */ -Mosaic.prototype.isVisible_ = function() { - return this.hasAttribute('visible'); -}; - -/** - * Loads visible tiles. Ignores consecutive calls. Does not reload already - * loaded images. - * @private - */ -Mosaic.prototype.loadVisibleTiles_ = function() { - if (this.loadVisibleTilesSuppressed_) { - this.loadVisibleTilesScheduled_ = true; - return; - } - - this.loadVisibleTilesSuppressed_ = true; - this.loadVisibleTilesScheduled_ = false; - setTimeout(function() { - this.loadVisibleTilesSuppressed_ = false; - if (this.loadVisibleTilesScheduled_) - this.loadVisibleTiles_(); - }.bind(this), 100); - - // Tiles only in the viewport (visible). - var visibleRect = new Rect(0, - 0, - this.clientWidth, - this.clientHeight); - - // Tiles in the viewport and also some distance on the left and right. - var renderableRect = new Rect(-this.clientWidth, - 0, - 3 * this.clientWidth, - this.clientHeight); - - // Unload tiles out of scope. - for (var index = 0; index < this.tiles_.length; index++) { - var tile = this.tiles_[index]; - var imageRect = tile.getImageRect(); - // Unload a thumbnail. - if (imageRect && !imageRect.intersects(renderableRect)) - tile.unload(); - } - - // Load the visible tiles first. - var allVisibleLoaded = true; - // Show high-dpi only when the mosaic view is visible. - var loadMode = this.isVisible_() ? Mosaic.Tile.LoadMode.HIGH_DPI : - Mosaic.Tile.LoadMode.LOW_DPI; - for (var index = 0; index < this.tiles_.length; index++) { - var tile = this.tiles_[index]; - var imageRect = tile.getImageRect(); - // Load a thumbnail. - if (!tile.isLoading(loadMode) && !tile.isLoaded(loadMode) && imageRect && - imageRect.intersects(visibleRect)) { - tile.load(loadMode, function() {}); - allVisibleLoaded = false; - } - } - - // Load also another, nearby, if the visible has been already loaded. - if (allVisibleLoaded) { - for (var index = 0; index < this.tiles_.length; index++) { - var tile = this.tiles_[index]; - var imageRect = tile.getImageRect(); - // Load a thumbnail. - if (!tile.isLoading() && !tile.isLoaded() && imageRect && - imageRect.intersects(renderableRect)) { - tile.load(Mosaic.Tile.LoadMode.LOW_DPI, function() {}); - } - } - } -}; - -/** - * Apply or reset the zoom transform. - * - * @param {Rect} tileRect Tile rectangle. Reset the transform if null. - * @param {Rect} imageRect Large image rectangle. Reset the transform if null. - * @param {boolean=} opt_instant True of the transition should be instant. - */ -Mosaic.prototype.transform = function(tileRect, imageRect, opt_instant) { - if (opt_instant) { - this.style.webkitTransitionDuration = '0'; - } else { - this.style.webkitTransitionDuration = - ImageView.MODE_TRANSITION_DURATION + 'ms'; - } - - if (this.canZoom() && tileRect && imageRect) { - var scaleX = imageRect.width / tileRect.width; - var scaleY = imageRect.height / tileRect.height; - var shiftX = (imageRect.left + imageRect.width / 2) - - (tileRect.left + tileRect.width / 2); - var shiftY = (imageRect.top + imageRect.height / 2) - - (tileRect.top + tileRect.height / 2); - this.style.webkitTransform = - 'translate(' + shiftX * scaleX + 'px, ' + shiftY * scaleY + 'px)' + - 'scaleX(' + scaleX + ') scaleY(' + scaleY + ')'; - } else { - this.style.webkitTransform = ''; - } -}; - -//////////////////////////////////////////////////////////////////////////////// - -/** - * Creates a selection controller that is to be used with grid. - * @param {cr.ui.ListSelectionModel} selectionModel The selection model to - * interact with. - * @param {Mosaic.Layout} layoutModel The layout model to use. - * @constructor - * @extends {!cr.ui.ListSelectionController} - */ -Mosaic.SelectionController = function(selectionModel, layoutModel) { - cr.ui.ListSelectionController.call(this, selectionModel); - this.layoutModel_ = layoutModel; -}; - -/** - * Extends cr.ui.ListSelectionController. - */ -Mosaic.SelectionController.prototype.__proto__ = - cr.ui.ListSelectionController.prototype; - -/** @override */ -Mosaic.SelectionController.prototype.getLastIndex = function() { - return this.layoutModel_.getLaidOutTileCount() - 1; -}; - -/** @override */ -Mosaic.SelectionController.prototype.getIndexBefore = function(index) { - return this.layoutModel_.getHorizontalAdjacentIndex(index, -1); -}; - -/** @override */ -Mosaic.SelectionController.prototype.getIndexAfter = function(index) { - return this.layoutModel_.getHorizontalAdjacentIndex(index, 1); -}; - -/** @override */ -Mosaic.SelectionController.prototype.getIndexAbove = function(index) { - return this.layoutModel_.getVerticalAdjacentIndex(index, -1); -}; - -/** @override */ -Mosaic.SelectionController.prototype.getIndexBelow = function(index) { - return this.layoutModel_.getVerticalAdjacentIndex(index, 1); -}; - -//////////////////////////////////////////////////////////////////////////////// - -/** - * Mosaic layout. - * - * @param {string=} opt_mode Layout mode. - * @param {Mosaic.Density=} opt_maxDensity Layout density. - * @constructor - */ -Mosaic.Layout = function(opt_mode, opt_maxDensity) { - this.mode_ = opt_mode || Mosaic.Layout.MODE_TENTATIVE; - this.maxDensity_ = opt_maxDensity || Mosaic.Density.createHighest(); - this.reset_(); -}; - -/** - * Blank space at the top of the mosaic element. We do not do that in CSS - * to make transition effects easier. - */ -Mosaic.Layout.PADDING_TOP = 50; - -/** - * Blank space at the bottom of the mosaic element. - */ -Mosaic.Layout.PADDING_BOTTOM = 50; - -/** - * Horizontal and vertical spacing between images. Should be kept in sync - * with the style of .mosaic-item in gallery.css (= 2 * ( 4 + 1)) - */ -Mosaic.Layout.SPACING = 10; - -/** - * Margin for scrolling using keyboard. Distance between a selected tile - * and window border. - */ -Mosaic.Layout.SCROLL_MARGIN = 30; - -/** - * Layout mode: commit to DOM immediately. - */ -Mosaic.Layout.MODE_FINAL = 'final'; - -/** - * Layout mode: do not commit layout to DOM until it is complete or the viewport - * overflows. - */ -Mosaic.Layout.MODE_TENTATIVE = 'tentative'; - -/** - * Layout mode: never commit layout to DOM. - */ -Mosaic.Layout.MODE_DRY_RUN = 'dry_run'; - -/** - * Reset the layout. - * - * @private - */ -Mosaic.Layout.prototype.reset_ = function() { - this.columns_ = []; - this.newColumn_ = null; - this.density_ = Mosaic.Density.createLowest(); - if (this.mode_ != Mosaic.Layout.MODE_DRY_RUN) // DRY_RUN is sticky. - this.mode_ = Mosaic.Layout.MODE_TENTATIVE; -}; - -/** - * @param {number} width Viewport width. - * @param {number} height Viewport height. - */ -Mosaic.Layout.prototype.setViewportSize = function(width, height) { - this.viewportWidth_ = width; - this.viewportHeight_ = height; - this.reset_(); -}; - -/** - * @return {number} Total width of the layout. - */ -Mosaic.Layout.prototype.getWidth = function() { - var lastColumn = this.getLastColumn_(); - return lastColumn ? lastColumn.getRight() : 0; -}; - -/** - * @return {number} Total height of the layout. - */ -Mosaic.Layout.prototype.getHeight = function() { - var firstColumn = this.columns_[0]; - return firstColumn ? firstColumn.getHeight() : 0; -}; - -/** - * @return {Array.<Mosaic.Tile>} All tiles in the layout. - */ -Mosaic.Layout.prototype.getTiles = function() { - return Array.prototype.concat.apply([], - this.columns_.map(function(c) { return c.getTiles() })); -}; - -/** - * @return {number} Total number of tiles added to the layout. - */ -Mosaic.Layout.prototype.getTileCount = function() { - return this.getLaidOutTileCount() + - (this.newColumn_ ? this.newColumn_.getTileCount() : 0); -}; - -/** - * @return {Mosaic.Column} The last column or null for empty layout. - * @private - */ -Mosaic.Layout.prototype.getLastColumn_ = function() { - return this.columns_.length ? this.columns_[this.columns_.length - 1] : null; -}; - -/** - * @return {number} Total number of tiles in completed columns. - */ -Mosaic.Layout.prototype.getLaidOutTileCount = function() { - var lastColumn = this.getLastColumn_(); - return lastColumn ? lastColumn.getNextTileIndex() : 0; -}; - -/** - * Add a tile to the layout. - * - * @param {Mosaic.Tile} tile The tile to be added. - * @param {boolean} isLast True if this tile is the last. - */ -Mosaic.Layout.prototype.add = function(tile, isLast) { - var layoutQueue = [tile]; - - // There are two levels of backtracking in the layout algorithm. - // |Mosaic.Layout.density_| tracks the state of the 'global' backtracking - // which aims to use as much of the viewport space as possible. - // It starts with the lowest density and increases it until the layout - // fits into the viewport. If it does not fit even at the highest density, - // the layout continues with the highest density. - // - // |Mosaic.Column.density_| tracks the state of the 'local' backtracking - // which aims to avoid producing unnaturally looking columns. - // It starts with the current global density and decreases it until the column - // looks nice. - - while (layoutQueue.length) { - if (!this.newColumn_) { - var lastColumn = this.getLastColumn_(); - this.newColumn_ = new Mosaic.Column( - this.columns_.length, - lastColumn ? lastColumn.getNextRowIndex() : 0, - lastColumn ? lastColumn.getNextTileIndex() : 0, - lastColumn ? lastColumn.getRight() : 0, - this.viewportHeight_, - this.density_.clone()); - } - - this.newColumn_.add(layoutQueue.shift()); - - var isFinalColumn = isLast && !layoutQueue.length; - - if (!this.newColumn_.prepareLayout(isFinalColumn)) - continue; // Column is incomplete. - - if (this.newColumn_.isSuboptimal()) { - layoutQueue = this.newColumn_.getTiles().concat(layoutQueue); - this.newColumn_.retryWithLowerDensity(); - continue; - } - - this.columns_.push(this.newColumn_); - this.newColumn_ = null; - - if (this.mode_ == Mosaic.Layout.MODE_FINAL) { - this.getLastColumn_().layout(); - continue; - } - - if (this.getWidth() > this.viewportWidth_) { - // Viewport completely filled. - if (this.density_.equals(this.maxDensity_)) { - // Max density reached, commit if tentative, just continue if dry run. - if (this.mode_ == Mosaic.Layout.MODE_TENTATIVE) - this.commit_(); - continue; - } - - // Rollback the entire layout, retry with higher density. - layoutQueue = this.getTiles().concat(layoutQueue); - this.columns_ = []; - this.density_.increase(); - continue; - } - - if (isFinalColumn && this.mode_ == Mosaic.Layout.MODE_TENTATIVE) { - // The complete tentative layout fits into the viewport. - var stretched = this.findHorizontalLayout_(); - if (stretched) - this.columns_ = stretched.columns_; - // Center the layout in the viewport and commit. - this.commit_((this.viewportWidth_ - this.getWidth()) / 2, - (this.viewportHeight_ - this.getHeight()) / 2); - } - } -}; - -/** - * Commit the tentative layout. - * - * @param {number=} opt_offsetX Horizontal offset. - * @param {number=} opt_offsetY Vertical offset. - * @private - */ -Mosaic.Layout.prototype.commit_ = function(opt_offsetX, opt_offsetY) { - console.assert(this.mode_ != Mosaic.Layout.MODE_FINAL, - 'Did not expect final layout'); - for (var i = 0; i != this.columns_.length; i++) { - this.columns_[i].layout(opt_offsetX, opt_offsetY); - } - this.mode_ = Mosaic.Layout.MODE_FINAL; -}; - -/** - * Find the most horizontally stretched layout built from the same tiles. - * - * The main layout algorithm fills the entire available viewport height. - * If there is too few tiles this results in a layout that is unnaturally - * stretched in the vertical direction. - * - * This method tries a number of smaller heights and returns the most - * horizontally stretched layout that still fits into the viewport. - * - * @return {Mosaic.Layout} A horizontally stretched layout. - * @private - */ -Mosaic.Layout.prototype.findHorizontalLayout_ = function() { - // If the layout aspect ratio is not dramatically different from - // the viewport aspect ratio then there is no need to optimize. - if (this.getWidth() / this.getHeight() > - this.viewportWidth_ / this.viewportHeight_ * 0.9) - return null; - - var tiles = this.getTiles(); - if (tiles.length == 1) - return null; // Single tile layout is always the same. - - var tileHeights = tiles.map(function(t) { return t.getMaxContentHeight() }); - var minTileHeight = Math.min.apply(null, tileHeights); - - for (var h = minTileHeight; h < this.viewportHeight_; h += minTileHeight) { - var layout = new Mosaic.Layout( - Mosaic.Layout.MODE_DRY_RUN, this.density_.clone()); - layout.setViewportSize(this.viewportWidth_, h); - for (var t = 0; t != tiles.length; t++) - layout.add(tiles[t], t + 1 == tiles.length); - - if (layout.getWidth() <= this.viewportWidth_) - return layout; - } - - return null; -}; - -/** - * Invalidate the layout after the given tile was modified (added, deleted or - * changed dimensions). - * - * @param {number} index Tile index. - * @private - */ -Mosaic.Layout.prototype.invalidateFromTile_ = function(index) { - var columnIndex = this.getColumnIndexByTile_(index); - if (columnIndex < 0) - return; // Index not in the layout, probably already invalidated. - - if (this.columns_[columnIndex].getLeft() >= this.viewportWidth_) { - // The columns to the right cover the entire viewport width, so there is no - // chance that the modified layout would fit into the viewport. - // No point in restarting the entire layout, keep the columns to the right. - console.assert(this.mode_ == Mosaic.Layout.MODE_FINAL, - 'Expected FINAL layout mode'); - this.columns_ = this.columns_.slice(0, columnIndex); - this.newColumn_ = null; - } else { - // There is a chance that the modified layout would fit into the viewport. - this.reset_(); - this.mode_ = Mosaic.Layout.MODE_TENTATIVE; - } -}; - -/** - * Get the index of the tile to the left or to the right from the given tile. - * - * @param {number} index Tile index. - * @param {number} direction -1 for left, 1 for right. - * @return {number} Adjacent tile index. - */ -Mosaic.Layout.prototype.getHorizontalAdjacentIndex = function( - index, direction) { - var column = this.getColumnIndexByTile_(index); - if (column < 0) { - console.error('Cannot find column for tile #' + index); - return -1; - } - - var row = this.columns_[column].getRowByTileIndex(index); - if (!row) { - console.error('Cannot find row for tile #' + index); - return -1; - } - - var sameRowNeighbourIndex = index + direction; - if (row.hasTile(sameRowNeighbourIndex)) - return sameRowNeighbourIndex; - - var adjacentColumn = column + direction; - if (adjacentColumn < 0 || adjacentColumn == this.columns_.length) - return -1; - - return this.columns_[adjacentColumn]. - getEdgeTileIndex_(row.getCenterY(), -direction); -}; - -/** - * Get the index of the tile to the top or to the bottom from the given tile. - * - * @param {number} index Tile index. - * @param {number} direction -1 for above, 1 for below. - * @return {number} Adjacent tile index. - */ -Mosaic.Layout.prototype.getVerticalAdjacentIndex = function( - index, direction) { - var column = this.getColumnIndexByTile_(index); - if (column < 0) { - console.error('Cannot find column for tile #' + index); - return -1; - } - - var row = this.columns_[column].getRowByTileIndex(index); - if (!row) { - console.error('Cannot find row for tile #' + index); - return -1; - } - - // Find the first item in the next row, or the last item in the previous row. - var adjacentRowNeighbourIndex = - row.getEdgeTileIndex_(direction) + direction; - - if (adjacentRowNeighbourIndex < 0 || - adjacentRowNeighbourIndex > this.getTileCount() - 1) - return -1; - - if (!this.columns_[column].hasTile(adjacentRowNeighbourIndex)) { - // It is not in the current column, so return it. - return adjacentRowNeighbourIndex; - } else { - // It is in the current column, so we have to find optically the closest - // tile in the adjacent row. - var adjacentRow = this.columns_[column].getRowByTileIndex( - adjacentRowNeighbourIndex); - var previousTileCenterX = row.getTileByIndex(index).getCenterX(); - - // Find the closest one. - var closestIndex = -1; - var closestDistance; - var adjacentRowTiles = adjacentRow.getTiles(); - for (var t = 0; t != adjacentRowTiles.length; t++) { - var distance = - Math.abs(adjacentRowTiles[t].getCenterX() - previousTileCenterX); - if (closestIndex == -1 || distance < closestDistance) { - closestIndex = adjacentRow.getEdgeTileIndex_(-1) + t; - closestDistance = distance; - } - } - return closestIndex; - } -}; - -/** - * @param {number} index Tile index. - * @return {number} Index of the column containing the given tile. - * @private - */ -Mosaic.Layout.prototype.getColumnIndexByTile_ = function(index) { - for (var c = 0; c != this.columns_.length; c++) { - if (this.columns_[c].hasTile(index)) - return c; - } - return -1; -}; - -/** - * Scale the given array of size values to satisfy 3 conditions: - * 1. The new sizes must be integer. - * 2. The new sizes must sum up to the given |total| value. - * 3. The relative proportions of the sizes should be as close to the original - * as possible. - * - * @param {Array.<number>} sizes Array of sizes. - * @param {number} newTotal New total size. - */ -Mosaic.Layout.rescaleSizesToNewTotal = function(sizes, newTotal) { - var total = 0; - - var partialTotals = [0]; - for (var i = 0; i != sizes.length; i++) { - total += sizes[i]; - partialTotals.push(total); - } - - var scale = newTotal / total; - - for (i = 0; i != sizes.length; i++) { - sizes[i] = Math.round(partialTotals[i + 1] * scale) - - Math.round(partialTotals[i] * scale); - } -}; - -//////////////////////////////////////////////////////////////////////////////// - -/** - * Representation of the layout density. - * - * @param {number} horizontal Horizontal density, number tiles per row. - * @param {number} vertical Vertical density, frequency of rows forced to - * contain a single tile. - * @constructor - */ -Mosaic.Density = function(horizontal, vertical) { - this.horizontal = horizontal; - this.vertical = vertical; -}; - -/** - * Minimal horizontal density (tiles per row). - */ -Mosaic.Density.MIN_HORIZONTAL = 1; - -/** - * Minimal horizontal density (tiles per row). - */ -Mosaic.Density.MAX_HORIZONTAL = 3; - -/** - * Minimal vertical density: force 1 out of 2 rows to containt a single tile. - */ -Mosaic.Density.MIN_VERTICAL = 2; - -/** - * Maximal vertical density: force 1 out of 3 rows to containt a single tile. - */ -Mosaic.Density.MAX_VERTICAL = 3; - -/** - * @return {Mosaic.Density} Lowest density. - */ -Mosaic.Density.createLowest = function() { - return new Mosaic.Density( - Mosaic.Density.MIN_HORIZONTAL, - Mosaic.Density.MIN_VERTICAL /* ignored when horizontal is at min */); -}; - -/** - * @return {Mosaic.Density} Highest density. - */ -Mosaic.Density.createHighest = function() { - return new Mosaic.Density( - Mosaic.Density.MAX_HORIZONTAL, - Mosaic.Density.MAX_VERTICAL); -}; - -/** - * @return {Mosaic.Density} A clone of this density object. - */ -Mosaic.Density.prototype.clone = function() { - return new Mosaic.Density(this.horizontal, this.vertical); -}; - -/** - * @param {Mosaic.Density} that The other object. - * @return {boolean} True if equal. - */ -Mosaic.Density.prototype.equals = function(that) { - return this.horizontal == that.horizontal && - this.vertical == that.vertical; -}; - -/** - * Increase the density to the next level. - */ -Mosaic.Density.prototype.increase = function() { - if (this.horizontal == Mosaic.Density.MIN_HORIZONTAL || - this.vertical == Mosaic.Density.MAX_VERTICAL) { - console.assert(this.horizontal < Mosaic.Density.MAX_HORIZONTAL); - this.horizontal++; - this.vertical = Mosaic.Density.MIN_VERTICAL; - } else { - this.vertical++; - } -}; - -/** - * Decrease horizontal density. - */ -Mosaic.Density.prototype.decreaseHorizontal = function() { - console.assert(this.horizontal > Mosaic.Density.MIN_HORIZONTAL); - this.horizontal--; -}; - -/** - * @param {number} tileCount Number of tiles in the row. - * @param {number} rowIndex Global row index. - * @return {boolean} True if the row is complete. - */ -Mosaic.Density.prototype.isRowComplete = function(tileCount, rowIndex) { - return (tileCount == this.horizontal) || (rowIndex % this.vertical) == 0; -}; - -//////////////////////////////////////////////////////////////////////////////// - -/** - * A column in a mosaic layout. Contains rows. - * - * @param {number} index Column index. - * @param {number} firstRowIndex Global row index. - * @param {number} firstTileIndex Index of the first tile in the column. - * @param {number} left Left edge coordinate. - * @param {number} maxHeight Maximum height. - * @param {Mosaic.Density} density Layout density. - * @constructor - */ -Mosaic.Column = function(index, firstRowIndex, firstTileIndex, left, maxHeight, - density) { - this.index_ = index; - this.firstRowIndex_ = firstRowIndex; - this.firstTileIndex_ = firstTileIndex; - this.left_ = left; - this.maxHeight_ = maxHeight; - this.density_ = density; - - this.reset_(); -}; - -/** - * Reset the layout. - * @private - */ -Mosaic.Column.prototype.reset_ = function() { - this.tiles_ = []; - this.rows_ = []; - this.newRow_ = null; -}; - -/** - * @return {number} Number of tiles in the column. - */ -Mosaic.Column.prototype.getTileCount = function() { return this.tiles_.length }; - -/** - * @return {number} Index of the last tile + 1. - */ -Mosaic.Column.prototype.getNextTileIndex = function() { - return this.firstTileIndex_ + this.getTileCount(); -}; - -/** - * @return {number} Global index of the last row + 1. - */ -Mosaic.Column.prototype.getNextRowIndex = function() { - return this.firstRowIndex_ + this.rows_.length; -}; - -/** - * @return {Array.<Mosaic.Tile>} Array of tiles in the column. - */ -Mosaic.Column.prototype.getTiles = function() { return this.tiles_ }; - -/** - * @param {number} index Tile index. - * @return {boolean} True if this column contains the tile with the given index. - */ -Mosaic.Column.prototype.hasTile = function(index) { - return this.firstTileIndex_ <= index && - index < (this.firstTileIndex_ + this.getTileCount()); -}; - -/** - * @param {number} y Y coordinate. - * @param {number} direction -1 for left, 1 for right. - * @return {number} Index of the tile lying on the edge of the column at the - * given y coordinate. - * @private - */ -Mosaic.Column.prototype.getEdgeTileIndex_ = function(y, direction) { - for (var r = 0; r < this.rows_.length; r++) { - if (this.rows_[r].coversY(y)) - return this.rows_[r].getEdgeTileIndex_(direction); - } - return -1; -}; - -/** - * @param {number} index Tile index. - * @return {Mosaic.Row} The row containing the tile with a given index. - */ -Mosaic.Column.prototype.getRowByTileIndex = function(index) { - for (var r = 0; r != this.rows_.length; r++) - if (this.rows_[r].hasTile(index)) - return this.rows_[r]; - - return null; -}; - -/** - * Add a tile to the column. - * - * @param {Mosaic.Tile} tile The tile to add. - */ -Mosaic.Column.prototype.add = function(tile) { - var rowIndex = this.getNextRowIndex(); - - if (!this.newRow_) - this.newRow_ = new Mosaic.Row(this.getNextTileIndex()); - - this.tiles_.push(tile); - this.newRow_.add(tile); - - if (this.density_.isRowComplete(this.newRow_.getTileCount(), rowIndex)) { - this.rows_.push(this.newRow_); - this.newRow_ = null; - } -}; - -/** - * Prepare the column layout. - * - * @param {boolean=} opt_force True if the layout must be performed even for an - * incomplete column. - * @return {boolean} True if the layout was performed. - */ -Mosaic.Column.prototype.prepareLayout = function(opt_force) { - if (opt_force && this.newRow_) { - this.rows_.push(this.newRow_); - this.newRow_ = null; - } - - if (this.rows_.length == 0) - return false; - - this.width_ = Math.min.apply( - null, this.rows_.map(function(row) { return row.getMaxWidth() })); - - this.height_ = 0; - - this.rowHeights_ = []; - for (var r = 0; r != this.rows_.length; r++) { - var rowHeight = this.rows_[r].getHeightForWidth(this.width_); - this.height_ += rowHeight; - this.rowHeights_.push(rowHeight); - } - - var overflow = this.height_ / this.maxHeight_; - if (!opt_force && (overflow < 1)) - return false; - - if (overflow > 1) { - // Scale down the column width and height. - this.width_ = Math.round(this.width_ / overflow); - this.height_ = this.maxHeight_; - Mosaic.Layout.rescaleSizesToNewTotal(this.rowHeights_, this.maxHeight_); - } - - return true; -}; - -/** - * Retry the column layout with less tiles per row. - */ -Mosaic.Column.prototype.retryWithLowerDensity = function() { - this.density_.decreaseHorizontal(); - this.reset_(); -}; - -/** - * @return {number} Column left edge coordinate. - */ -Mosaic.Column.prototype.getLeft = function() { return this.left_ }; - -/** - * @return {number} Column right edge coordinate after the layout. - */ -Mosaic.Column.prototype.getRight = function() { - return this.left_ + this.width_; -}; - -/** - * @return {number} Column height after the layout. - */ -Mosaic.Column.prototype.getHeight = function() { return this.height_ }; - -/** - * Perform the column layout. - * @param {number=} opt_offsetX Horizontal offset. - * @param {number=} opt_offsetY Vertical offset. - */ -Mosaic.Column.prototype.layout = function(opt_offsetX, opt_offsetY) { - opt_offsetX = opt_offsetX || 0; - opt_offsetY = opt_offsetY || 0; - var rowTop = Mosaic.Layout.PADDING_TOP; - for (var r = 0; r != this.rows_.length; r++) { - this.rows_[r].layout( - opt_offsetX + this.left_, - opt_offsetY + rowTop, - this.width_, - this.rowHeights_[r]); - rowTop += this.rowHeights_[r]; - } -}; - -/** - * Check if the column layout is too ugly to be displayed. - * - * @return {boolean} True if the layout is suboptimal. - */ -Mosaic.Column.prototype.isSuboptimal = function() { - var tileCounts = - this.rows_.map(function(row) { return row.getTileCount() }); - - var maxTileCount = Math.max.apply(null, tileCounts); - if (maxTileCount == 1) - return false; // Every row has exactly 1 tile, as optimal as it gets. - - var sizes = - this.tiles_.map(function(tile) { return tile.getMaxContentHeight() }); - - // Ugly layout #1: all images are small and some are one the same row. - var allSmall = Math.max.apply(null, sizes) <= Mosaic.Tile.SMALL_IMAGE_SIZE; - if (allSmall) - return true; - - // Ugly layout #2: all images are large and none occupies an entire row. - var allLarge = Math.min.apply(null, sizes) > Mosaic.Tile.SMALL_IMAGE_SIZE; - var allCombined = Math.min.apply(null, tileCounts) != 1; - if (allLarge && allCombined) - return true; - - // Ugly layout #3: some rows have too many tiles for the resulting width. - if (this.width_ / maxTileCount < 100) - return true; - - return false; -}; - -//////////////////////////////////////////////////////////////////////////////// - -/** - * A row in a mosaic layout. Contains tiles. - * - * @param {number} firstTileIndex Index of the first tile in the row. - * @constructor - */ -Mosaic.Row = function(firstTileIndex) { - this.firstTileIndex_ = firstTileIndex; - this.tiles_ = []; -}; - -/** - * @param {Mosaic.Tile} tile The tile to add. - */ -Mosaic.Row.prototype.add = function(tile) { - console.assert(this.getTileCount() < Mosaic.Density.MAX_HORIZONTAL); - this.tiles_.push(tile); -}; - -/** - * @return {Array.<Mosaic.Tile>} Array of tiles in the row. - */ -Mosaic.Row.prototype.getTiles = function() { return this.tiles_ }; - -/** - * Get a tile by index. - * @param {number} index Tile index. - * @return {Mosaic.Tile} Requested tile or null if not found. - */ -Mosaic.Row.prototype.getTileByIndex = function(index) { - if (!this.hasTile(index)) - return null; - return this.tiles_[index - this.firstTileIndex_]; -}; - -/** - * - * @return {number} Number of tiles in the row. - */ -Mosaic.Row.prototype.getTileCount = function() { return this.tiles_.length }; - -/** - * @param {number} index Tile index. - * @return {boolean} True if this row contains the tile with the given index. - */ -Mosaic.Row.prototype.hasTile = function(index) { - return this.firstTileIndex_ <= index && - index < (this.firstTileIndex_ + this.tiles_.length); -}; - -/** - * @param {number} y Y coordinate. - * @return {boolean} True if this row covers the given Y coordinate. - */ -Mosaic.Row.prototype.coversY = function(y) { - return this.top_ <= y && y < (this.top_ + this.height_); -}; - -/** - * @return {number} Y coordinate of the tile center. - */ -Mosaic.Row.prototype.getCenterY = function() { - return this.top_ + Math.round(this.height_ / 2); -}; - -/** - * Get the first or the last tile. - * - * @param {number} direction -1 for the first tile, 1 for the last tile. - * @return {number} Tile index. - * @private - */ -Mosaic.Row.prototype.getEdgeTileIndex_ = function(direction) { - if (direction < 0) - return this.firstTileIndex_; - else - return this.firstTileIndex_ + this.getTileCount() - 1; -}; - -/** - * @return {number} Aspect ration of the combined content box of this row. - * @private - */ -Mosaic.Row.prototype.getTotalContentAspectRatio_ = function() { - var sum = 0; - for (var t = 0; t != this.tiles_.length; t++) - sum += this.tiles_[t].getAspectRatio(); - return sum; -}; - -/** - * @return {number} Total horizontal spacing in this row. This includes - * the spacing between the tiles and both left and right margins. - * - * @private - */ -Mosaic.Row.prototype.getTotalHorizontalSpacing_ = function() { - return Mosaic.Layout.SPACING * this.getTileCount(); -}; - -/** - * @return {number} Maximum width that this row may have without overscaling - * any of the tiles. - */ -Mosaic.Row.prototype.getMaxWidth = function() { - var contentHeight = Math.min.apply(null, - this.tiles_.map(function(tile) { return tile.getMaxContentHeight() })); - - var contentWidth = - Math.round(contentHeight * this.getTotalContentAspectRatio_()); - return contentWidth + this.getTotalHorizontalSpacing_(); -}; - -/** - * Compute the height that best fits the supplied row width given - * aspect ratios of the tiles in this row. - * - * @param {number} width Row width. - * @return {number} Height. - */ -Mosaic.Row.prototype.getHeightForWidth = function(width) { - var contentWidth = width - this.getTotalHorizontalSpacing_(); - var contentHeight = - Math.round(contentWidth / this.getTotalContentAspectRatio_()); - return contentHeight + Mosaic.Layout.SPACING; -}; - -/** - * Position the row in the mosaic. - * - * @param {number} left Left position. - * @param {number} top Top position. - * @param {number} width Width. - * @param {number} height Height. - */ -Mosaic.Row.prototype.layout = function(left, top, width, height) { - this.top_ = top; - this.height_ = height; - - var contentWidth = width - this.getTotalHorizontalSpacing_(); - var contentHeight = height - Mosaic.Layout.SPACING; - - var tileContentWidth = this.tiles_.map( - function(tile) { return tile.getAspectRatio() }); - - Mosaic.Layout.rescaleSizesToNewTotal(tileContentWidth, contentWidth); - - var tileLeft = left; - for (var t = 0; t != this.tiles_.length; t++) { - var tileWidth = tileContentWidth[t] + Mosaic.Layout.SPACING; - this.tiles_[t].layout(tileLeft, top, tileWidth, height); - tileLeft += tileWidth; - } -}; - -//////////////////////////////////////////////////////////////////////////////// - -/** - * A single tile of the image mosaic. - * - * @param {Element} container Container element. - * @param {Gallery.Item} item Gallery item associated with this tile. - * @return {Element} The new tile element. - * @constructor - */ -Mosaic.Tile = function(container, item) { - var self = container.ownerDocument.createElement('div'); - Mosaic.Tile.decorate(self, container, item); - return self; -}; - -/** - * @param {Element} self Self pointer. - * @param {Element} container Container element. - * @param {Gallery.Item} item Gallery item associated with this tile. - */ -Mosaic.Tile.decorate = function(self, container, item) { - self.__proto__ = Mosaic.Tile.prototype; - self.className = 'mosaic-tile'; - - self.container_ = container; - self.item_ = item; - self.left_ = null; // Mark as not laid out. -}; - -/** - * Load mode for the tile's image. - * @enum {number} - */ -Mosaic.Tile.LoadMode = { - LOW_DPI: 0, - HIGH_DPI: 1 -}; - -/** -* Inherit from HTMLDivElement. -*/ -Mosaic.Tile.prototype.__proto__ = HTMLDivElement.prototype; - -/** - * Minimum tile content size. - */ -Mosaic.Tile.MIN_CONTENT_SIZE = 64; - -/** - * Maximum tile content size. - */ -Mosaic.Tile.MAX_CONTENT_SIZE = 512; - -/** - * Default size for a tile with no thumbnail image. - */ -Mosaic.Tile.GENERIC_ICON_SIZE = 128; - -/** - * Max size of an image considered to be 'small'. - * Small images are laid out slightly differently. - */ -Mosaic.Tile.SMALL_IMAGE_SIZE = 160; - -/** - * @return {Gallery.Item} The Gallery item. - */ -Mosaic.Tile.prototype.getItem = function() { return this.item_ }; - -/** - * @return {number} Maximum content height that this tile can have. - */ -Mosaic.Tile.prototype.getMaxContentHeight = function() { - return this.maxContentHeight_; -}; - -/** - * @return {number} The aspect ratio of the tile image. - */ -Mosaic.Tile.prototype.getAspectRatio = function() { return this.aspectRatio_ }; - -/** - * @return {boolean} True if the tile is initialized. - */ -Mosaic.Tile.prototype.isInitialized = function() { - return !!this.maxContentHeight_; -}; - -/** - * Checks whether the image of specified (or better resolution) has been loaded. - * - * @param {Mosaic.Tile.LoadMode=} opt_loadMode Loading mode, default: LOW_DPI. - * @return {boolean} True if the tile is loaded with the specified dpi or - * better. - */ -Mosaic.Tile.prototype.isLoaded = function(opt_loadMode) { - var loadMode = opt_loadMode || Mosaic.Tile.LoadMode.LOW_DPI; - switch (loadMode) { - case Mosaic.Tile.LoadMode.LOW_DPI: - if (this.imagePreloaded_ || this.imageLoaded_) - return true; - break; - case Mosaic.Tile.LoadMode.HIGH_DPI: - if (this.imageLoaded_) - return true; - break; - } - return false; -}; - -/** - * Checks whether the image of specified (or better resolution) is being loaded. - * - * @param {Mosaic.Tile.LoadMode=} opt_loadMode Loading mode, default: LOW_DPI. - * @return {boolean} True if the tile is being loaded with the specified dpi or - * better. - */ -Mosaic.Tile.prototype.isLoading = function(opt_loadMode) { - var loadMode = opt_loadMode || Mosaic.Tile.LoadMode.LOW_DPI; - switch (loadMode) { - case Mosaic.Tile.LoadMode.LOW_DPI: - if (this.imagePreloading_ || this.imageLoading_) - return true; - break; - case Mosaic.Tile.LoadMode.HIGH_DPI: - if (this.imageLoading_) - return true; - break; - } - return false; -}; - -/** - * Mark the tile as not loaded to prevent it from participating in the layout. - */ -Mosaic.Tile.prototype.markUnloaded = function() { - this.maxContentHeight_ = 0; - if (this.thumbnailLoader_) { - this.thumbnailLoader_.cancel(); - this.imagePreloaded_ = false; - this.imagePreloading_ = false; - this.imageLoaded_ = false; - this.imageLoading_ = false; - } -}; - -/** - * Initializes the thumbnail in the tile. Does not load an image, but sets - * target dimensions using metadata. - * - * @param {Object} metadata Metadata object. - * @param {function()} onImageMeasured Image measured callback. - */ -Mosaic.Tile.prototype.init = function(metadata, onImageMeasured) { - this.markUnloaded(); - this.left_ = null; // Mark as not laid out. - - // Set higher priority for the selected elements to load them first. - var priority = this.getAttribute('selected') ? 2 : 3; - - // Use embedded thumbnails on Drive, since they have higher resolution. - var hidpiEmbedded = FileType.isOnDrive(this.getItem().getEntry()); - this.thumbnailLoader_ = new ThumbnailLoader( - this.getItem().getEntry().toURL(), - ThumbnailLoader.LoaderType.CANVAS, - metadata, - undefined, // Media type. - hidpiEmbedded ? ThumbnailLoader.UseEmbedded.USE_EMBEDDED : - ThumbnailLoader.UseEmbedded.NO_EMBEDDED, - priority); - - // If no hidpi embedded thumbnail available, then use the low resolution - // for preloading. - if (!hidpiEmbedded) { - this.thumbnailPreloader_ = new ThumbnailLoader( - this.getItem().getEntry().toURL(), - ThumbnailLoader.LoaderType.CANVAS, - metadata, - undefined, // Media type. - ThumbnailLoader.UseEmbedded.USE_EMBEDDED, - 2); // Preloaders have always higher priotity, so the preload images - // are loaded as soon as possible. - } - - var setDimensions = function(width, height) { - if (width > height) { - if (width > Mosaic.Tile.MAX_CONTENT_SIZE) { - height = Math.round(height * Mosaic.Tile.MAX_CONTENT_SIZE / width); - width = Mosaic.Tile.MAX_CONTENT_SIZE; - } - } else { - if (height > Mosaic.Tile.MAX_CONTENT_SIZE) { - width = Math.round(width * Mosaic.Tile.MAX_CONTENT_SIZE / height); - height = Mosaic.Tile.MAX_CONTENT_SIZE; - } - } - this.maxContentHeight_ = Math.max(Mosaic.Tile.MIN_CONTENT_SIZE, height); - this.aspectRatio_ = width / height; - onImageMeasured(); - }.bind(this); - - // Dimensions are always acquired from the metadata. For local files, it is - // extracted from headers. For Drive files, it is received via the Drive API. - // If the dimensions are not available, then the fallback dimensions will be - // used (same as for the generic icon). - if (metadata.media && metadata.media.width) { - setDimensions(metadata.media.width, metadata.media.height); - } else if (metadata.drive && metadata.drive.imageWidth && - metadata.drive.imageHeight) { - setDimensions(metadata.drive.imageWidth, metadata.drive.imageHeight); - } else { - // No dimensions in metadata, then use the generic dimensions. - setDimensions(Mosaic.Tile.GENERIC_ICON_SIZE, - Mosaic.Tile.GENERIC_ICON_SIZE); - } -}; - -/** - * Loads an image into the tile. - * - * The mode argument is a hint. Use low-dpi for faster response, and high-dpi - * for better output, but possibly affecting performance. - * - * If the mode is high-dpi, then a the high-dpi image is loaded, but also - * low-dpi image is loaded for preloading (if available). - * For the low-dpi mode, only low-dpi image is loaded. If not available, then - * the high-dpi image is loaded as a fallback. - * - * @param {Mosaic.Tile.LoadMode} loadMode Loading mode. - * @param {function(boolean)} onImageLoaded Callback when image is loaded. - * The argument is true for success, false for failure. - */ -Mosaic.Tile.prototype.load = function(loadMode, onImageLoaded) { - // Attaches the image to the tile and finalizes loading process for the - // specified loader. - var finalizeLoader = function(mode, success, loader) { - if (success && this.wrapper_) { - // Show the fade-in animation only when previously there was no image - // attached in this tile. - if (!this.imageLoaded_ && !this.imagePreloaded_) - this.wrapper_.classList.add('animated'); - else - this.wrapper_.classList.remove('animated'); - } - loader.attachImage(this.wrapper_, ThumbnailLoader.FillMode.OVER_FILL); - onImageLoaded(success); - switch (mode) { - case Mosaic.Tile.LoadMode.LOW_DPI: - this.imagePreloading_ = false; - this.imagePreloaded_ = true; - break; - case Mosaic.Tile.LoadMode.HIGH_DPI: - this.imageLoading_ = false; - this.imageLoaded_ = true; - break; - } - }.bind(this); - - // Always load the low-dpi image first if it is available for the fastest - // feedback. - if (!this.imagePreloading_ && this.thumbnailPreloader_) { - this.imagePreloading_ = true; - this.thumbnailPreloader_.loadDetachedImage(function(success) { - // Hi-dpi loaded first, ignore this call then. - if (this.imageLoaded_) - return; - finalizeLoader(Mosaic.Tile.LoadMode.LOW_DPI, - success, - this.thumbnailPreloader_); - }.bind(this)); - } - - // Load the high-dpi image only when it is requested, or the low-dpi is not - // available. - if (!this.imageLoading_ && - (loadMode == Mosaic.Tile.LoadMode.HIGH_DPI || !this.imagePreloading_)) { - this.imageLoading_ = true; - this.thumbnailLoader_.loadDetachedImage(function(success) { - // Cancel preloading, since the hi-dpi image is ready. - if (this.thumbnailPreloader_) - this.thumbnailPreloader_.cancel(); - finalizeLoader(Mosaic.Tile.LoadMode.HIGH_DPI, - success, - this.thumbnailLoader_); - }.bind(this)); - } -}; - -/** - * Unloads an image from the tile. - */ -Mosaic.Tile.prototype.unload = function() { - this.thumbnailLoader_.cancel(); - if (this.thumbnailPreloader_) - this.thumbnailPreloader_.cancel(); - this.imagePreloaded_ = false; - this.imageLoaded_ = false; - this.imagePreloading_ = false; - this.imageLoading_ = false; - this.wrapper_.innerText = ''; -}; - -/** - * Select/unselect the tile. - * - * @param {boolean} on True if selected. - */ -Mosaic.Tile.prototype.select = function(on) { - if (on) - this.setAttribute('selected', true); - else - this.removeAttribute('selected'); -}; - -/** - * Position the tile in the mosaic. - * - * @param {number} left Left position. - * @param {number} top Top position. - * @param {number} width Width. - * @param {number} height Height. - */ -Mosaic.Tile.prototype.layout = function(left, top, width, height) { - this.left_ = left; - this.top_ = top; - this.width_ = width; - this.height_ = height; - - this.style.left = left + 'px'; - this.style.top = top + 'px'; - this.style.width = width + 'px'; - this.style.height = height + 'px'; - - if (!this.wrapper_) { // First time, create DOM. - this.container_.appendChild(this); - var border = util.createChild(this, 'img-border'); - this.wrapper_ = util.createChild(border, 'img-wrapper'); - } - if (this.hasAttribute('selected')) - this.scrollIntoView(false); - - if (this.imageLoaded_) { - this.thumbnailLoader_.attachImage(this.wrapper_, - ThumbnailLoader.FillMode.FILL); - } -}; - -/** - * If the tile is not fully visible scroll the parent to make it fully visible. - * @param {boolean=} opt_animated True, if scroll should be animated, - * default: true. - */ -Mosaic.Tile.prototype.scrollIntoView = function(opt_animated) { - if (this.left_ == null) // Not laid out. - return; - - var targetPosition; - var tileLeft = this.left_ - Mosaic.Layout.SCROLL_MARGIN; - if (tileLeft < this.container_.scrollLeft) { - targetPosition = tileLeft; - } else { - var tileRight = this.left_ + this.width_ + Mosaic.Layout.SCROLL_MARGIN; - var scrollRight = this.container_.scrollLeft + this.container_.clientWidth; - if (tileRight > scrollRight) - targetPosition = tileRight - this.container_.clientWidth; - } - - if (targetPosition) { - if (opt_animated === false) - this.container_.scrollLeft = targetPosition; - else - this.container_.animatedScrollTo(targetPosition); - } -}; - -/** - * @return {Rect} Rectangle occupied by the tile's image, - * relative to the viewport. - */ -Mosaic.Tile.prototype.getImageRect = function() { - if (this.left_ == null) // Not laid out. - return null; - - var margin = Mosaic.Layout.SPACING / 2; - return new Rect(this.left_ - this.container_.scrollLeft, this.top_, - this.width_, this.height_).inflate(-margin, -margin); -}; - -/** - * @return {number} X coordinate of the tile center. - */ -Mosaic.Tile.prototype.getCenterX = function() { - return this.left_ + Math.round(this.width_ / 2); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/photo/ribbon.js b/chromium/chrome/browser/resources/file_manager/foreground/js/photo/ribbon.js deleted file mode 100644 index 4d1c81c6c3c..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/photo/ribbon.js +++ /dev/null @@ -1,366 +0,0 @@ -// 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. - -'use strict'; - -/** - * Scrollable thumbnail ribbon at the bottom of the Gallery in the Slide mode. - * - * @param {Document} document Document. - * @param {MetadataCache} metadataCache MetadataCache instance. - * @param {cr.ui.ArrayDataModel} dataModel Data model. - * @param {cr.ui.ListSelectionModel} selectionModel Selection model. - * @return {Element} Ribbon element. - * @constructor - */ -function Ribbon(document, metadataCache, dataModel, selectionModel) { - var self = document.createElement('div'); - Ribbon.decorate(self, metadataCache, dataModel, selectionModel); - return self; -} - -/** - * Inherit from HTMLDivElement. - */ -Ribbon.prototype.__proto__ = HTMLDivElement.prototype; - -/** - * Decorate a Ribbon instance. - * - * @param {Ribbon} self Self pointer. - * @param {MetadataCache} metadataCache MetadataCache instance. - * @param {cr.ui.ArrayDataModel} dataModel Data model. - * @param {cr.ui.ListSelectionModel} selectionModel Selection model. - */ -Ribbon.decorate = function(self, metadataCache, dataModel, selectionModel) { - self.__proto__ = Ribbon.prototype; - self.metadataCache_ = metadataCache; - self.dataModel_ = dataModel; - self.selectionModel_ = selectionModel; - - self.className = 'ribbon'; -}; - -/** - * Max number of thumbnails in the ribbon. - * @type {number} - */ -Ribbon.ITEMS_COUNT = 5; - -/** - * Force redraw the ribbon. - */ -Ribbon.prototype.redraw = function() { - this.onSelection_(); -}; - -/** - * Clear all cached data to force full redraw on the next selection change. - */ -Ribbon.prototype.reset = function() { - this.renderCache_ = {}; - this.firstVisibleIndex_ = 0; - this.lastVisibleIndex_ = -1; // Zero thumbnails -}; - -/** - * Enable the ribbon. - */ -Ribbon.prototype.enable = function() { - this.onContentBound_ = this.onContentChange_.bind(this); - this.dataModel_.addEventListener('content', this.onContentBound_); - - this.onSpliceBound_ = this.onSplice_.bind(this); - this.dataModel_.addEventListener('splice', this.onSpliceBound_); - - this.onSelectionBound_ = this.onSelection_.bind(this); - this.selectionModel_.addEventListener('change', this.onSelectionBound_); - - this.reset(); - this.redraw(); -}; - -/** - * Disable ribbon. - */ -Ribbon.prototype.disable = function() { - this.dataModel_.removeEventListener('content', this.onContentBound_); - this.dataModel_.removeEventListener('splice', this.onSpliceBound_); - this.selectionModel_.removeEventListener('change', this.onSelectionBound_); - - this.removeVanishing_(); - this.textContent = ''; -}; - -/** - * Data model splice handler. - * @param {Event} event Event. - * @private - */ -Ribbon.prototype.onSplice_ = function(event) { - if (event.removed.length == 0) - return; - - if (event.removed.length > 1) { - console.error('Cannot remove multiple items'); - return; - } - - var removed = this.renderCache_[event.removed[0].getEntry().toURL()]; - if (!removed || !removed.parentNode || !removed.hasAttribute('selected')) { - console.error('Can only remove the selected item'); - return; - } - - var persistentNodes = this.querySelectorAll('.ribbon-image:not([vanishing])'); - if (this.lastVisibleIndex_ < this.dataModel_.length) { // Not at the end. - var lastNode = persistentNodes[persistentNodes.length - 1]; - if (lastNode.nextSibling) { - // Pull back a vanishing node from the right. - lastNode.nextSibling.removeAttribute('vanishing'); - } else { - // Push a new item at the right end. - this.appendChild(this.renderThumbnail_(this.lastVisibleIndex_)); - } - } else { - // No items to the right, move the window to the left. - this.lastVisibleIndex_--; - if (this.firstVisibleIndex_) { - this.firstVisibleIndex_--; - var firstNode = persistentNodes[0]; - if (firstNode.previousSibling) { - // Pull back a vanishing node from the left. - firstNode.previousSibling.removeAttribute('vanishing'); - } else { - // Push a new item at the left end. - var newThumbnail = this.renderThumbnail_(this.firstVisibleIndex_); - newThumbnail.style.marginLeft = -(this.clientHeight - 2) + 'px'; - this.insertBefore(newThumbnail, this.firstChild); - setTimeout(function() { - newThumbnail.style.marginLeft = '0'; - }, 0); - } - } - } - - removed.removeAttribute('selected'); - removed.setAttribute('vanishing', 'smooth'); - this.scheduleRemove_(); -}; - -/** - * Selection change handler. - * @private - */ -Ribbon.prototype.onSelection_ = function() { - var indexes = this.selectionModel_.selectedIndexes; - if (indexes.length == 0) - return; // Ignore temporary empty selection. - var selectedIndex = indexes[0]; - - var length = this.dataModel_.length; - - // TODO(dgozman): use margin instead of 2 here. - var itemWidth = this.clientHeight - 2; - var fullItems = Ribbon.ITEMS_COUNT; - fullItems = Math.min(fullItems, length); - var right = Math.floor((fullItems - 1) / 2); - - var fullWidth = fullItems * itemWidth; - this.style.width = fullWidth + 'px'; - - var lastIndex = selectedIndex + right; - lastIndex = Math.max(lastIndex, fullItems - 1); - lastIndex = Math.min(lastIndex, length - 1); - var firstIndex = lastIndex - fullItems + 1; - - if (this.firstVisibleIndex_ != firstIndex || - this.lastVisibleIndex_ != lastIndex) { - - if (this.lastVisibleIndex_ == -1) { - this.firstVisibleIndex_ = firstIndex; - this.lastVisibleIndex_ = lastIndex; - } - - this.removeVanishing_(); - - this.textContent = ''; - var startIndex = Math.min(firstIndex, this.firstVisibleIndex_); - // All the items except the first one treated equally. - for (var index = startIndex + 1; - index <= Math.max(lastIndex, this.lastVisibleIndex_); - ++index) { - // Only add items that are in either old or the new viewport. - if (this.lastVisibleIndex_ < index && index < firstIndex || - lastIndex < index && index < this.firstVisibleIndex_) - continue; - var box = this.renderThumbnail_(index); - box.style.marginLeft = '0'; - this.appendChild(box); - if (index < firstIndex || index > lastIndex) { - // If the node is not in the new viewport we only need it while - // the animation is playing out. - box.setAttribute('vanishing', 'slide'); - } - } - - var slideCount = this.childNodes.length + 1 - Ribbon.ITEMS_COUNT; - var margin = itemWidth * slideCount; - var startBox = this.renderThumbnail_(startIndex); - if (startIndex == firstIndex) { - // Sliding to the right. - startBox.style.marginLeft = -margin + 'px'; - if (this.firstChild) - this.insertBefore(startBox, this.firstChild); - else - this.appendChild(startBox); - setTimeout(function() { - startBox.style.marginLeft = '0'; - }, 0); - } else { - // Sliding to the left. Start item will become invisible and should be - // removed afterwards. - startBox.setAttribute('vanishing', 'slide'); - startBox.style.marginLeft = '0'; - if (this.firstChild) - this.insertBefore(startBox, this.firstChild); - else - this.appendChild(startBox); - setTimeout(function() { - startBox.style.marginLeft = -margin + 'px'; - }, 0); - } - - ImageUtil.setClass(this, 'fade-left', - firstIndex > 0 && selectedIndex != firstIndex); - - ImageUtil.setClass(this, 'fade-right', - lastIndex < length - 1 && selectedIndex != lastIndex); - - this.firstVisibleIndex_ = firstIndex; - this.lastVisibleIndex_ = lastIndex; - - this.scheduleRemove_(); - } - - var oldSelected = this.querySelector('[selected]'); - if (oldSelected) oldSelected.removeAttribute('selected'); - - var newSelected = - this.renderCache_[this.dataModel_.item(selectedIndex).getEntry().toURL()]; - if (newSelected) newSelected.setAttribute('selected', true); -}; - -/** - * Schedule the removal of thumbnails marked as vanishing. - * @private - */ -Ribbon.prototype.scheduleRemove_ = function() { - if (this.removeTimeout_) - clearTimeout(this.removeTimeout_); - - this.removeTimeout_ = setTimeout(function() { - this.removeTimeout_ = null; - this.removeVanishing_(); - }.bind(this), 200); -}; - -/** - * Remove all thumbnails marked as vanishing. - * @private - */ -Ribbon.prototype.removeVanishing_ = function() { - if (this.removeTimeout_) { - clearTimeout(this.removeTimeout_); - this.removeTimeout_ = 0; - } - var vanishingNodes = this.querySelectorAll('[vanishing]'); - for (var i = 0; i != vanishingNodes.length; i++) { - vanishingNodes[i].removeAttribute('vanishing'); - this.removeChild(vanishingNodes[i]); - } -}; - -/** - * Create a DOM element for a thumbnail. - * - * @param {number} index Item index. - * @return {Element} Newly created element. - * @private - */ -Ribbon.prototype.renderThumbnail_ = function(index) { - var item = this.dataModel_.item(index); - var url = item.getEntry().toURL(); - - var cached = this.renderCache_[url]; - if (cached) { - var img = cached.querySelector('img'); - if (img) - img.classList.add('cached'); - return cached; - } - - var thumbnail = this.ownerDocument.createElement('div'); - thumbnail.className = 'ribbon-image'; - thumbnail.addEventListener('click', function() { - var index = this.dataModel_.indexOf(item); - this.selectionModel_.unselectAll(); - this.selectionModel_.setIndexSelected(index, true); - }.bind(this)); - - util.createChild(thumbnail, 'image-wrapper'); - - this.metadataCache_.get(item.getEntry(), Gallery.METADATA_TYPE, - this.setThumbnailImage_.bind(this, thumbnail, url)); - - // TODO: Implement LRU eviction. - // Never evict the thumbnails that are currently in the DOM because we rely - // on this cache to find them by URL. - this.renderCache_[url] = thumbnail; - return thumbnail; -}; - -/** - * Set the thumbnail image. - * - * @param {Element} thumbnail Thumbnail element. - * @param {string} url Image url. - * @param {Object} metadata Metadata. - * @private - */ -Ribbon.prototype.setThumbnailImage_ = function(thumbnail, url, metadata) { - new ThumbnailLoader(url, ThumbnailLoader.LoaderType.IMAGE, metadata).load( - thumbnail.querySelector('.image-wrapper'), - ThumbnailLoader.FillMode.FILL /* fill */, - ThumbnailLoader.OptimizationMode.NEVER_DISCARD); -}; - -/** - * Content change handler. - * - * @param {Event} event Event. - * @private - */ -Ribbon.prototype.onContentChange_ = function(event) { - var url = event.item.getEntry().toURL(); - this.remapCache_(event.oldUrl, url); - - var thumbnail = this.renderCache_[url]; - if (thumbnail && event.metadata) - this.setThumbnailImage_(thumbnail, url, event.metadata); -}; - -/** - * Update the thumbnail element cache. - * - * @param {string} oldUrl Old url. - * @param {string} newUrl New url. - * @private - */ -Ribbon.prototype.remapCache_ = function(oldUrl, newUrl) { - if (oldUrl != newUrl && (oldUrl in this.renderCache_)) { - this.renderCache_[newUrl] = this.renderCache_[oldUrl]; - delete this.renderCache_[oldUrl]; - } -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/photo/slide_mode.js b/chromium/chrome/browser/resources/file_manager/foreground/js/photo/slide_mode.js deleted file mode 100644 index d9b47395bb9..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/photo/slide_mode.js +++ /dev/null @@ -1,1354 +0,0 @@ -// 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. - -'use strict'; - -/** - * Slide mode displays a single image and has a set of controls to navigate - * between the images and to edit an image. - * - * TODO(kaznacheev): Introduce a parameter object. - * - * @param {Element} container Main container element. - * @param {Element} content Content container element. - * @param {Element} toolbar Toolbar element. - * @param {ImageEditor.Prompt} prompt Prompt. - * @param {cr.ui.ArrayDataModel} dataModel Data model. - * @param {cr.ui.ListSelectionModel} selectionModel Selection model. - * @param {Object} context Context. - * @param {function(function())} toggleMode Function to toggle the Gallery mode. - * @param {function(string):string} displayStringFunction String formatting - * function. - * @constructor - */ -function SlideMode(container, content, toolbar, prompt, - dataModel, selectionModel, context, - toggleMode, displayStringFunction) { - this.container_ = container; - this.document_ = container.ownerDocument; - this.content = content; - this.toolbar_ = toolbar; - this.prompt_ = prompt; - this.dataModel_ = dataModel; - this.selectionModel_ = selectionModel; - this.context_ = context; - this.metadataCache_ = context.metadataCache; - this.toggleMode_ = toggleMode; - this.displayStringFunction_ = displayStringFunction; - - this.onSelectionBound_ = this.onSelection_.bind(this); - this.onSpliceBound_ = this.onSplice_.bind(this); - this.onContentBound_ = this.onContentChange_.bind(this); - - // Unique numeric key, incremented per each load attempt used to discard - // old attempts. This can happen especially when changing selection fast or - // Internet connection is slow. - this.currentUniqueKey_ = 0; - - this.initListeners_(); - this.initDom_(); -} - -/** - * SlideMode extends cr.EventTarget. - */ -SlideMode.prototype.__proto__ = cr.EventTarget.prototype; - -/** - * List of available editor modes. - * @type {Array.<ImageEditor.Mode>} - */ -SlideMode.editorModes = [ - new ImageEditor.Mode.InstantAutofix(), - new ImageEditor.Mode.Crop(), - new ImageEditor.Mode.Exposure(), - new ImageEditor.Mode.OneClick( - 'rotate_left', 'GALLERY_ROTATE_LEFT', new Command.Rotate(-1)), - new ImageEditor.Mode.OneClick( - 'rotate_right', 'GALLERY_ROTATE_RIGHT', new Command.Rotate(1)) -]; - -/** - * @return {string} Mode name. - */ -SlideMode.prototype.getName = function() { return 'slide' }; - -/** - * @return {string} Mode title. - */ -SlideMode.prototype.getTitle = function() { return 'GALLERY_SLIDE' }; - -/** - * Initialize the listeners. - * @private - */ -SlideMode.prototype.initListeners_ = function() { - window.addEventListener('resize', this.onResize_.bind(this), false); -}; - -/** - * Initialize the UI. - * @private - */ -SlideMode.prototype.initDom_ = function() { - // Container for displayed image or video. - this.imageContainer_ = util.createChild( - this.document_.querySelector('.content'), 'image-container'); - this.imageContainer_.addEventListener('click', this.onClick_.bind(this)); - - this.document_.addEventListener('click', this.onDocumentClick_.bind(this)); - - // Overwrite options and info bubble. - this.options_ = util.createChild( - this.toolbar_.querySelector('.filename-spacer'), 'options'); - - this.savedLabel_ = util.createChild(this.options_, 'saved'); - this.savedLabel_.textContent = this.displayStringFunction_('GALLERY_SAVED'); - - var overwriteOriginalBox = - util.createChild(this.options_, 'overwrite-original'); - - this.overwriteOriginal_ = util.createChild( - overwriteOriginalBox, 'common white', 'input'); - this.overwriteOriginal_.type = 'checkbox'; - this.overwriteOriginal_.id = 'overwrite-checkbox'; - util.platform.getPreference(SlideMode.OVERWRITE_KEY, function(value) { - // Out-of-the box default is 'true' - this.overwriteOriginal_.checked = - (typeof value !== 'string' || value === 'true'); - }.bind(this)); - this.overwriteOriginal_.addEventListener('click', - this.onOverwriteOriginalClick_.bind(this)); - - var overwriteLabel = util.createChild(overwriteOriginalBox, '', 'label'); - overwriteLabel.textContent = - this.displayStringFunction_('GALLERY_OVERWRITE_ORIGINAL'); - overwriteLabel.setAttribute('for', 'overwrite-checkbox'); - - this.bubble_ = util.createChild(this.toolbar_, 'bubble'); - this.bubble_.hidden = true; - - var bubbleContent = util.createChild(this.bubble_); - bubbleContent.innerHTML = this.displayStringFunction_( - 'GALLERY_OVERWRITE_BUBBLE'); - - util.createChild(this.bubble_, 'pointer bottom', 'span'); - - var bubbleClose = util.createChild(this.bubble_, 'close-x'); - bubbleClose.addEventListener('click', this.onCloseBubble_.bind(this)); - - // Video player controls. - this.mediaSpacer_ = - util.createChild(this.container_, 'video-controls-spacer'); - this.mediaToolbar_ = util.createChild(this.mediaSpacer_, 'tool'); - this.mediaControls_ = new VideoControls( - this.mediaToolbar_, - this.showErrorBanner_.bind(this, 'GALLERY_VIDEO_ERROR'), - this.displayStringFunction_.bind(this), - this.toggleFullScreen_.bind(this), - this.container_); - - // Ribbon and related controls. - this.arrowBox_ = util.createChild(this.container_, 'arrow-box'); - - this.arrowLeft_ = - util.createChild(this.arrowBox_, 'arrow left tool dimmable'); - this.arrowLeft_.addEventListener('click', - this.advanceManually.bind(this, -1)); - util.createChild(this.arrowLeft_); - - util.createChild(this.arrowBox_, 'arrow-spacer'); - - this.arrowRight_ = - util.createChild(this.arrowBox_, 'arrow right tool dimmable'); - this.arrowRight_.addEventListener('click', - this.advanceManually.bind(this, 1)); - util.createChild(this.arrowRight_); - - this.ribbonSpacer_ = util.createChild(this.toolbar_, 'ribbon-spacer'); - this.ribbon_ = new Ribbon(this.document_, - this.metadataCache_, this.dataModel_, this.selectionModel_); - this.ribbonSpacer_.appendChild(this.ribbon_); - - // Error indicator. - var errorWrapper = util.createChild(this.container_, 'prompt-wrapper'); - errorWrapper.setAttribute('pos', 'center'); - - this.errorBanner_ = util.createChild(errorWrapper, 'error-banner'); - - util.createChild(this.container_, 'spinner'); - - var slideShowButton = util.createChild(this.toolbar_, - 'button slideshow', 'button'); - slideShowButton.title = this.displayStringFunction_('GALLERY_SLIDESHOW'); - slideShowButton.addEventListener('click', - this.startSlideshow.bind(this, SlideMode.SLIDESHOW_INTERVAL_FIRST)); - - var slideShowToolbar = - util.createChild(this.container_, 'tool slideshow-toolbar'); - util.createChild(slideShowToolbar, 'slideshow-play'). - addEventListener('click', this.toggleSlideshowPause_.bind(this)); - util.createChild(slideShowToolbar, 'slideshow-end'). - addEventListener('click', this.stopSlideshow_.bind(this)); - - // Editor. - - this.editButton_ = util.createChild(this.toolbar_, 'button edit', 'button'); - this.editButton_.title = this.displayStringFunction_('GALLERY_EDIT'); - this.editButton_.setAttribute('disabled', ''); // Disabled by default. - this.editButton_.addEventListener('click', this.toggleEditor.bind(this)); - - this.printButton_ = util.createChild(this.toolbar_, 'button print', 'button'); - this.printButton_.title = this.displayStringFunction_('GALLERY_PRINT'); - this.printButton_.setAttribute('disabled', ''); // Disabled by default. - this.printButton_.addEventListener('click', this.print_.bind(this)); - - this.editBarSpacer_ = util.createChild(this.toolbar_, 'edit-bar-spacer'); - this.editBarMain_ = util.createChild(this.editBarSpacer_, 'edit-main'); - - this.editBarMode_ = util.createChild(this.container_, 'edit-modal'); - this.editBarModeWrapper_ = util.createChild( - this.editBarMode_, 'edit-modal-wrapper'); - this.editBarModeWrapper_.hidden = true; - - // Objects supporting image display and editing. - this.viewport_ = new Viewport(); - - this.imageView_ = new ImageView( - this.imageContainer_, - this.viewport_, - this.metadataCache_); - - this.editor_ = new ImageEditor( - this.viewport_, - this.imageView_, - this.prompt_, - { - root: this.container_, - image: this.imageContainer_, - toolbar: this.editBarMain_, - mode: this.editBarModeWrapper_ - }, - SlideMode.editorModes, - this.displayStringFunction_, - this.onToolsVisibilityChanged_.bind(this)); - - this.editor_.getBuffer().addOverlay( - new SwipeOverlay(this.advanceManually.bind(this))); -}; - -/** - * Load items, display the selected item. - * @param {Rect} zoomFromRect Rectangle for zoom effect. - * @param {function} displayCallback Called when the image is displayed. - * @param {function} loadCallback Called when the image is displayed. - */ -SlideMode.prototype.enter = function( - zoomFromRect, displayCallback, loadCallback) { - this.sequenceDirection_ = 0; - this.sequenceLength_ = 0; - - var loadDone = function(loadType, delay) { - this.active_ = true; - - this.selectionModel_.addEventListener('change', this.onSelectionBound_); - this.dataModel_.addEventListener('splice', this.onSpliceBound_); - this.dataModel_.addEventListener('content', this.onContentBound_); - - ImageUtil.setAttribute(this.arrowBox_, 'active', this.getItemCount_() > 1); - this.ribbon_.enable(); - - // Wait 1000ms after the animation is done, then prefetch the next image. - this.requestPrefetch(1, delay + 1000); - - if (loadCallback) loadCallback(); - }.bind(this); - - // The latest |leave| call might have left the image animating. Remove it. - this.unloadImage_(); - - if (this.getItemCount_() === 0) { - this.displayedIndex_ = -1; - //TODO(kaznacheev) Show this message in the grid mode too. - this.showErrorBanner_('GALLERY_NO_IMAGES'); - loadDone(); - } else { - // Remember the selection if it is empty or multiple. It will be restored - // in |leave| if the user did not changing the selection manually. - var currentSelection = this.selectionModel_.selectedIndexes; - if (currentSelection.length === 1) - this.savedSelection_ = null; - else - this.savedSelection_ = currentSelection; - - // Ensure valid single selection. - // Note that the SlideMode object is not listening to selection change yet. - this.select(Math.max(0, this.getSelectedIndex())); - this.displayedIndex_ = this.getSelectedIndex(); - - var selectedItem = this.getSelectedItem(); - // Show the selected item ASAP, then complete the initialization - // (loading the ribbon thumbnails can take some time). - this.metadataCache_.get(selectedItem.getEntry(), Gallery.METADATA_TYPE, - function(metadata) { - this.loadItem_(selectedItem.getEntry(), metadata, - zoomFromRect && this.imageView_.createZoomEffect(zoomFromRect), - displayCallback, loadDone); - }.bind(this)); - - } -}; - -/** - * Leave the mode. - * @param {Rect} zoomToRect Rectangle for zoom effect. - * @param {function} callback Called when the image is committed and - * the zoom-out animation has started. - */ -SlideMode.prototype.leave = function(zoomToRect, callback) { - var commitDone = function() { - this.stopEditing_(); - this.stopSlideshow_(); - ImageUtil.setAttribute(this.arrowBox_, 'active', false); - this.selectionModel_.removeEventListener( - 'change', this.onSelectionBound_); - this.dataModel_.removeEventListener('splice', this.onSpliceBound_); - this.dataModel_.removeEventListener('content', this.onContentBound_); - this.ribbon_.disable(); - this.active_ = false; - if (this.savedSelection_) - this.selectionModel_.selectedIndexes = this.savedSelection_; - this.unloadImage_(zoomToRect); - callback(); - }.bind(this); - - if (this.getItemCount_() === 0) { - this.showErrorBanner_(false); - commitDone(); - } else { - this.commitItem_(commitDone); - } - - // Disable the slide-mode only buttons when leaving. - this.editButton_.setAttribute('disabled', ''); - this.printButton_.setAttribute('disabled', ''); -}; - - -/** - * Execute an action when the editor is not busy. - * - * @param {function} action Function to execute. - */ -SlideMode.prototype.executeWhenReady = function(action) { - this.editor_.executeWhenReady(action); -}; - -/** - * @return {boolean} True if the mode has active tools (that should not fade). - */ -SlideMode.prototype.hasActiveTool = function() { - return this.isEditing(); -}; - -/** - * @return {number} Item count. - * @private - */ -SlideMode.prototype.getItemCount_ = function() { - return this.dataModel_.length; -}; - -/** - * @param {number} index Index. - * @return {Gallery.Item} Item. - */ -SlideMode.prototype.getItem = function(index) { - return this.dataModel_.item(index); -}; - -/** - * @return {Gallery.Item} Selected index. - */ -SlideMode.prototype.getSelectedIndex = function() { - return this.selectionModel_.selectedIndex; -}; - -/** - * @return {Rect} Screen rectangle of the selected image. - */ -SlideMode.prototype.getSelectedImageRect = function() { - if (this.getSelectedIndex() < 0) - return null; - else - return this.viewport_.getScreenClipped(); -}; - -/** - * @return {Gallery.Item} Selected item. - */ -SlideMode.prototype.getSelectedItem = function() { - return this.getItem(this.getSelectedIndex()); -}; - -/** - * Toggles the full screen mode. - * @private - */ -SlideMode.prototype.toggleFullScreen_ = function() { - util.toggleFullScreen(this.context_.appWindow, - !util.isFullScreen(this.context_.appWindow)); -}; - -/** - * Selection change handler. - * - * Commits the current image and displays the newly selected image. - * @private - */ -SlideMode.prototype.onSelection_ = function() { - if (this.selectionModel_.selectedIndexes.length === 0) - return; // Temporary empty selection. - - // Forget the saved selection if the user changed the selection manually. - if (!this.isSlideshowOn_()) - this.savedSelection_ = null; - - if (this.getSelectedIndex() === this.displayedIndex_) - return; // Do not reselect. - - this.commitItem_(this.loadSelectedItem_.bind(this)); -}; - -/** - * Handles changes in tools visibility, and if the header is dimmed, then - * requests disabling the draggable app region. - * - * @private - */ -SlideMode.prototype.onToolsVisibilityChanged_ = function() { - var headerDimmed = - this.document_.querySelector('.header').hasAttribute('dimmed'); - this.context_.onAppRegionChanged(!headerDimmed); -}; - -/** - * Change the selection. - * - * @param {number} index New selected index. - * @param {number=} opt_slideHint Slide animation direction (-1|1). - */ -SlideMode.prototype.select = function(index, opt_slideHint) { - this.slideHint_ = opt_slideHint; - this.selectionModel_.selectedIndex = index; - this.selectionModel_.leadIndex = index; -}; - -/** - * Load the selected item. - * - * @private - */ -SlideMode.prototype.loadSelectedItem_ = function() { - var slideHint = this.slideHint_; - this.slideHint_ = undefined; - - var index = this.getSelectedIndex(); - if (index === this.displayedIndex_) - return; // Do not reselect. - - var step = slideHint || (index - this.displayedIndex_); - - if (Math.abs(step) != 1) { - // Long leap, the sequence is broken, we have no good prefetch candidate. - this.sequenceDirection_ = 0; - this.sequenceLength_ = 0; - } else if (this.sequenceDirection_ === step) { - // Keeping going in sequence. - this.sequenceLength_++; - } else { - // Reversed the direction. Reset the counter. - this.sequenceDirection_ = step; - this.sequenceLength_ = 1; - } - - if (this.sequenceLength_ <= 1) { - // We have just broke the sequence. Touch the current image so that it stays - // in the cache longer. - this.imageView_.prefetch(this.imageView_.contentEntry_); - } - - this.displayedIndex_ = index; - - function shouldPrefetch(loadType, step, sequenceLength) { - // Never prefetch when selecting out of sequence. - if (Math.abs(step) != 1) - return false; - - // Never prefetch after a video load (decoding the next image can freeze - // the UI for a second or two). - if (loadType === ImageView.LOAD_TYPE_VIDEO_FILE) - return false; - - // Always prefetch if the previous load was from cache. - if (loadType === ImageView.LOAD_TYPE_CACHED_FULL) - return true; - - // Prefetch if we have been going in the same direction for long enough. - return sequenceLength >= 3; - } - - var selectedItem = this.getSelectedItem(); - this.currentUniqueKey_++; - var selectedUniqueKey = this.currentUniqueKey_; - var onMetadata = function(metadata) { - // Discard, since another load has been invoked after this one. - if (selectedUniqueKey != this.currentUniqueKey_) return; - this.loadItem_(selectedItem.getEntry(), metadata, - new ImageView.Effect.Slide(step, this.isSlideshowPlaying_()), - function() {} /* no displayCallback */, - function(loadType, delay) { - // Discard, since another load has been invoked after this one. - if (selectedUniqueKey != this.currentUniqueKey_) return; - if (shouldPrefetch(loadType, step, this.sequenceLength_)) { - this.requestPrefetch(step, delay); - } - if (this.isSlideshowPlaying_()) - this.scheduleNextSlide_(); - }.bind(this)); - }.bind(this); - this.metadataCache_.get( - selectedItem.getEntry(), Gallery.METADATA_TYPE, onMetadata); -}; - -/** - * Unload the current image. - * - * @param {Rect} zoomToRect Rectangle for zoom effect. - * @private - */ -SlideMode.prototype.unloadImage_ = function(zoomToRect) { - this.imageView_.unload(zoomToRect); - this.container_.removeAttribute('video'); -}; - -/** - * Data model 'splice' event handler. - * @param {Event} event Event. - * @private - */ -SlideMode.prototype.onSplice_ = function(event) { - ImageUtil.setAttribute(this.arrowBox_, 'active', this.getItemCount_() > 1); - - // Splice invalidates saved indices, drop the saved selection. - this.savedSelection_ = null; - - if (event.removed.length != 1) - return; - - // Delay the selection to let the ribbon splice handler work first. - setTimeout(function() { - if (event.index < this.dataModel_.length) { - // There is the next item, select it. - // The next item is now at the same index as the removed one, so we need - // to correct displayIndex_ so that loadSelectedItem_ does not think - // we are re-selecting the same item (and does right-to-left slide-in - // animation). - this.displayedIndex_ = event.index - 1; - this.select(event.index); - } else if (this.dataModel_.length) { - // Removed item is the rightmost, but there are more items. - this.select(event.index - 1); // Select the new last index. - } else { - // No items left. Unload the image and show the banner. - this.commitItem_(function() { - this.unloadImage_(); - this.showErrorBanner_('GALLERY_NO_IMAGES'); - }.bind(this)); - } - }.bind(this), 0); -}; - -/** - * @param {number} direction -1 for left, 1 for right. - * @return {number} Next index in the given direction, with wrapping. - * @private - */ -SlideMode.prototype.getNextSelectedIndex_ = function(direction) { - function advance(index, limit) { - index += (direction > 0 ? 1 : -1); - if (index < 0) - return limit - 1; - if (index === limit) - return 0; - return index; - } - - // If the saved selection is multiple the Slideshow should cycle through - // the saved selection. - if (this.isSlideshowOn_() && - this.savedSelection_ && this.savedSelection_.length > 1) { - var pos = advance(this.savedSelection_.indexOf(this.getSelectedIndex()), - this.savedSelection_.length); - return this.savedSelection_[pos]; - } else { - return advance(this.getSelectedIndex(), this.getItemCount_()); - } -}; - -/** - * Advance the selection based on the pressed key ID. - * @param {string} keyID Key identifier. - */ -SlideMode.prototype.advanceWithKeyboard = function(keyID) { - this.advanceManually(keyID === 'Up' || keyID === 'Left' ? -1 : 1); -}; - -/** - * Advance the selection as a result of a user action (as opposed to an - * automatic change in the slideshow mode). - * @param {number} direction -1 for left, 1 for right. - */ -SlideMode.prototype.advanceManually = function(direction) { - if (this.isSlideshowPlaying_()) { - this.pauseSlideshow_(); - cr.dispatchSimpleEvent(this, 'useraction'); - } - this.selectNext(direction); -}; - -/** - * Select the next item. - * @param {number} direction -1 for left, 1 for right. - */ -SlideMode.prototype.selectNext = function(direction) { - this.select(this.getNextSelectedIndex_(direction), direction); -}; - -/** - * Select the first item. - */ -SlideMode.prototype.selectFirst = function() { - this.select(0); -}; - -/** - * Select the last item. - */ -SlideMode.prototype.selectLast = function() { - this.select(this.getItemCount_() - 1); -}; - -// Loading/unloading - -/** - * Load and display an item. - * - * @param {FileEntry} entry Item entry to be loaded. - * @param {Object} metadata Item metadata. - * @param {Object} effect Transition effect object. - * @param {function} displayCallback Called when the image is displayed - * (which can happen before the image load due to caching). - * @param {function} loadCallback Called when the image is fully loaded. - * @private - */ -SlideMode.prototype.loadItem_ = function( - entry, metadata, effect, displayCallback, loadCallback) { - this.selectedImageMetadata_ = MetadataCache.cloneMetadata(metadata); - - this.showSpinner_(true); - - var loadDone = function(loadType, delay, error) { - var video = this.isShowingVideo_(); - ImageUtil.setAttribute(this.container_, 'video', video); - - this.showSpinner_(false); - if (loadType === ImageView.LOAD_TYPE_ERROR) { - // if we have a specific error, then display it - if (error) { - this.showErrorBanner_(error); - } else { - // otherwise try to infer general error - this.showErrorBanner_( - video ? 'GALLERY_VIDEO_ERROR' : 'GALLERY_IMAGE_ERROR'); - } - } else if (loadType === ImageView.LOAD_TYPE_OFFLINE) { - this.showErrorBanner_( - video ? 'GALLERY_VIDEO_OFFLINE' : 'GALLERY_IMAGE_OFFLINE'); - } - - if (video) { - // The editor toolbar does not make sense for video, hide it. - this.stopEditing_(); - this.mediaControls_.attachMedia(this.imageView_.getVideo()); - - // TODO(kaznacheev): Add metrics for video playback. - } else { - ImageUtil.metrics.recordUserAction(ImageUtil.getMetricName('View')); - - var toMillions = function(number) { - return Math.round(number / (1000 * 1000)); - }; - - ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MB'), - toMillions(metadata.filesystem.size)); - - var canvas = this.imageView_.getCanvas(); - ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MPix'), - toMillions(canvas.width * canvas.height)); - - var extIndex = entry.name.lastIndexOf('.'); - var ext = extIndex < 0 ? '' : - entry.name.substr(extIndex + 1).toLowerCase(); - if (ext === 'jpeg') ext = 'jpg'; - ImageUtil.metrics.recordEnum( - ImageUtil.getMetricName('FileType'), ext, ImageUtil.FILE_TYPES); - } - - // Enable or disable buttons for editing and printing. - if (video || error) { - this.editButton_.setAttribute('disabled', ''); - this.printButton_.setAttribute('disabled', ''); - } else { - this.editButton_.removeAttribute('disabled'); - this.printButton_.removeAttribute('disabled'); - } - - // For once edited image, disallow the 'overwrite' setting change. - ImageUtil.setAttribute(this.options_, 'saved', - !this.getSelectedItem().isOriginal()); - - util.platform.getPreference(SlideMode.OVERWRITE_BUBBLE_KEY, - function(value) { - var times = typeof value === 'string' ? parseInt(value, 10) : 0; - if (times < SlideMode.OVERWRITE_BUBBLE_MAX_TIMES) { - this.bubble_.hidden = false; - if (this.isEditing()) { - util.platform.setPreference( - SlideMode.OVERWRITE_BUBBLE_KEY, times + 1); - } - } - }.bind(this)); - - loadCallback(loadType, delay); - }.bind(this); - - var displayDone = function() { - cr.dispatchSimpleEvent(this, 'image-displayed'); - displayCallback(); - }.bind(this); - - this.editor_.openSession(entry, metadata, effect, - this.saveCurrentImage_.bind(this), displayDone, loadDone); -}; - -/** - * Commit changes to the current item and reset all messages/indicators. - * - * @param {function} callback Callback. - * @private - */ -SlideMode.prototype.commitItem_ = function(callback) { - this.showSpinner_(false); - this.showErrorBanner_(false); - this.editor_.getPrompt().hide(); - - // Detach any media attached to the controls. - if (this.mediaControls_.getMedia()) - this.mediaControls_.detachMedia(); - - // If showing the video, then pause it. Note, that it may not be attached - // to the media controls yet. - if (this.isShowingVideo_()) { - this.imageView_.getVideo().pause(); - // Force stop downloading, if uncached on Drive. - this.imageView_.getVideo().src = ''; - this.imageView_.getVideo().load(); - } - - this.editor_.closeSession(callback); -}; - -/** - * Request a prefetch for the next image. - * - * @param {number} direction -1 or 1. - * @param {number} delay Delay in ms. Used to prevent the CPU-heavy image - * loading from disrupting the animation that might be still in progress. - */ -SlideMode.prototype.requestPrefetch = function(direction, delay) { - if (this.getItemCount_() <= 1) return; - - var index = this.getNextSelectedIndex_(direction); - var nextItemEntry = this.getItem(index).getEntry(); - this.imageView_.prefetch(nextItemEntry, delay); -}; - -// Event handlers. - -/** - * Unload handler, to be called from the top frame. - * @param {boolean} exiting True if the app is exiting. - */ -SlideMode.prototype.onUnload = function(exiting) { - if (this.isShowingVideo_() && this.mediaControls_.isPlaying()) { - this.mediaControls_.savePosition(exiting); - } -}; - -/** - * beforeunload handler, to be called from the top frame. - * @return {string} Message to show if there are unsaved changes. - */ -SlideMode.prototype.onBeforeUnload = function() { - if (this.editor_.isBusy()) - return this.displayStringFunction_('GALLERY_UNSAVED_CHANGES'); - return null; -}; - -/** - * Click handler for the image container. - * - * @param {Event} event Mouse click event. - * @private - */ -SlideMode.prototype.onClick_ = function(event) { - if (!this.isShowingVideo_() || !this.mediaControls_.getMedia()) - return; - if (event.ctrlKey) { - this.mediaControls_.toggleLoopedModeWithFeedback(true); - if (!this.mediaControls_.isPlaying()) - this.mediaControls_.togglePlayStateWithFeedback(); - } else { - this.mediaControls_.togglePlayStateWithFeedback(); - } -}; - -/** - * Click handler for the entire document. - * @param {Event} e Mouse click event. - * @private - */ -SlideMode.prototype.onDocumentClick_ = function(e) { - // Close the bubble if clicked outside of it and if it is visible. - if (!this.bubble_.contains(e.target) && - !this.editButton_.contains(e.target) && - !this.arrowLeft_.contains(e.target) && - !this.arrowRight_.contains(e.target) && - !this.bubble_.hidden) { - this.bubble_.hidden = true; - } -}; - -/** - * Keydown handler. - * - * @param {Event} event Event. - * @return {boolean} True if handled. - */ -SlideMode.prototype.onKeyDown = function(event) { - var keyID = util.getKeyModifiers(event) + event.keyIdentifier; - - if (this.isSlideshowOn_()) { - switch (keyID) { - case 'U+001B': // Escape exits the slideshow. - this.stopSlideshow_(event); - break; - - case 'U+0020': // Space pauses/resumes the slideshow. - this.toggleSlideshowPause_(); - break; - - case 'Up': - case 'Down': - case 'Left': - case 'Right': - this.advanceWithKeyboard(keyID); - break; - } - return true; // Consume all keystrokes in the slideshow mode. - } - - if (this.isEditing() && this.editor_.onKeyDown(event)) - return true; - - switch (keyID) { - case 'U+0020': // Space toggles the video playback. - if (this.isShowingVideo_() && this.mediaControls_.getMedia()) - this.mediaControls_.togglePlayStateWithFeedback(); - break; - - case 'Ctrl-U+0050': // Ctrl+'p' prints the current image. - if (!this.printButton_.hasAttribute('disabled')) - this.print_(); - break; - - case 'U+0045': // 'e' toggles the editor. - if (!this.editButton_.hasAttribute('disabled')) - this.toggleEditor(event); - break; - - case 'U+001B': // Escape - if (!this.isEditing()) - return false; // Not handled. - this.toggleEditor(event); - break; - - case 'Home': - this.selectFirst(); - break; - case 'End': - this.selectLast(); - break; - case 'Up': - case 'Down': - case 'Left': - case 'Right': - this.advanceWithKeyboard(keyID); - break; - - default: return false; - } - - return true; -}; - -/** - * Resize handler. - * @private - */ -SlideMode.prototype.onResize_ = function() { - this.viewport_.sizeByFrameAndFit(this.container_); - this.viewport_.repaint(); -}; - -/** - * Update thumbnails. - */ -SlideMode.prototype.updateThumbnails = function() { - this.ribbon_.reset(); - if (this.active_) - this.ribbon_.redraw(); -}; - -// Saving - -/** - * Save the current image to a file. - * - * @param {function} callback Callback. - * @private - */ -SlideMode.prototype.saveCurrentImage_ = function(callback) { - var item = this.getSelectedItem(); - var oldEntry = item.getEntry(); - var canvas = this.imageView_.getCanvas(); - - this.showSpinner_(true); - var metadataEncoder = ImageEncoder.encodeMetadata( - this.selectedImageMetadata_.media, canvas, 1 /* quality */); - - this.selectedImageMetadata_ = ContentProvider.ConvertContentMetadata( - metadataEncoder.getMetadata(), this.selectedImageMetadata_); - - item.saveToFile( - this.context_.saveDirEntry, - this.shouldOverwriteOriginal_(), - canvas, - metadataEncoder, - function(success) { - // TODO(kaznacheev): Implement write error handling. - // Until then pretend that the save succeeded. - this.showSpinner_(false); - this.flashSavedLabel_(); - - var event = new Event('content'); - event.item = item; - event.oldEntry = oldEntry; - event.metadata = this.selectedImageMetadata_; - this.dataModel_.dispatchEvent(event); - - // Allow changing the 'Overwrite original' setting only if the user - // used Undo to restore the original image AND it is not a copy. - // Otherwise lock the setting in its current state. - var mayChangeOverwrite = !this.editor_.canUndo() && item.isOriginal(); - ImageUtil.setAttribute(this.options_, 'saved', !mayChangeOverwrite); - - if (this.imageView_.getContentRevision() === 1) { // First edit. - ImageUtil.metrics.recordUserAction(ImageUtil.getMetricName('Edit')); - } - - if (!util.isSameEntry(oldEntry, item.getEntry())) { - this.dataModel_.splice( - this.getSelectedIndex(), 0, new Gallery.Item(oldEntry)); - // The ribbon will ignore the splice above and redraw after the - // select call below (while being obscured by the Editor toolbar, - // so there is no need for nice animation here). - // SlideMode will ignore the selection change as the displayed item - // index has not changed. - this.select(++this.displayedIndex_); - } - callback(); - cr.dispatchSimpleEvent(this, 'image-saved'); - }.bind(this)); -}; - -/** - * Update caches when the selected item has been renamed. - * @param {Event} event Event. - * @private - */ -SlideMode.prototype.onContentChange_ = function(event) { - var newEntry = event.item.getEntry(); - if (util.isSameEntry(newEntry, event.oldEntry)) - this.imageView_.changeEntry(newEntry); - this.metadataCache_.clear(event.oldEntry, Gallery.METADATA_TYPE); -}; - -/** - * Flash 'Saved' label briefly to indicate that the image has been saved. - * @private - */ -SlideMode.prototype.flashSavedLabel_ = function() { - var setLabelHighlighted = - ImageUtil.setAttribute.bind(null, this.savedLabel_, 'highlighted'); - setTimeout(setLabelHighlighted.bind(null, true), 0); - setTimeout(setLabelHighlighted.bind(null, false), 300); -}; - -/** - * Local storage key for the 'Overwrite original' setting. - * @type {string} - */ -SlideMode.OVERWRITE_KEY = 'gallery-overwrite-original'; - -/** - * Local storage key for the number of times that - * the overwrite info bubble has been displayed. - * @type {string} - */ -SlideMode.OVERWRITE_BUBBLE_KEY = 'gallery-overwrite-bubble'; - -/** - * Max number that the overwrite info bubble is shown. - * @type {number} - */ -SlideMode.OVERWRITE_BUBBLE_MAX_TIMES = 5; - -/** - * @return {boolean} True if 'Overwrite original' is set. - * @private - */ -SlideMode.prototype.shouldOverwriteOriginal_ = function() { - return this.overwriteOriginal_.checked; -}; - -/** - * 'Overwrite original' checkbox handler. - * @param {Event} event Event. - * @private - */ -SlideMode.prototype.onOverwriteOriginalClick_ = function(event) { - util.platform.setPreference(SlideMode.OVERWRITE_KEY, event.target.checked); -}; - -/** - * Overwrite info bubble close handler. - * @private - */ -SlideMode.prototype.onCloseBubble_ = function() { - this.bubble_.hidden = true; - util.platform.setPreference(SlideMode.OVERWRITE_BUBBLE_KEY, - SlideMode.OVERWRITE_BUBBLE_MAX_TIMES); -}; - -// Slideshow - -/** - * Slideshow interval in ms. - */ -SlideMode.SLIDESHOW_INTERVAL = 5000; - -/** - * First slideshow interval in ms. It should be shorter so that the user - * is not guessing whether the button worked. - */ -SlideMode.SLIDESHOW_INTERVAL_FIRST = 1000; - -/** - * Empirically determined duration of the fullscreen toggle animation. - */ -SlideMode.FULLSCREEN_TOGGLE_DELAY = 500; - -/** - * @return {boolean} True if the slideshow is on. - * @private - */ -SlideMode.prototype.isSlideshowOn_ = function() { - return this.container_.hasAttribute('slideshow'); -}; - -/** - * Start the slideshow. - * @param {number=} opt_interval First interval in ms. - * @param {Event=} opt_event Event. - */ -SlideMode.prototype.startSlideshow = function(opt_interval, opt_event) { - // Set the attribute early to prevent the toolbar from flashing when - // the slideshow is being started from the mosaic view. - this.container_.setAttribute('slideshow', 'playing'); - - if (this.active_) { - this.stopEditing_(); - } else { - // We are in the Mosaic mode. Toggle the mode but remember to return. - this.leaveAfterSlideshow_ = true; - this.toggleMode_(this.startSlideshow.bind( - this, SlideMode.SLIDESHOW_INTERVAL, opt_event)); - return; - } - - if (opt_event) // Caused by user action, notify the Gallery. - cr.dispatchSimpleEvent(this, 'useraction'); - - this.fullscreenBeforeSlideshow_ = util.isFullScreen(this.context_.appWindow); - if (!this.fullscreenBeforeSlideshow_) { - // Wait until the zoom animation from the mosaic mode is done. - setTimeout(this.toggleFullScreen_.bind(this), - ImageView.ZOOM_ANIMATION_DURATION); - opt_interval = (opt_interval || SlideMode.SLIDESHOW_INTERVAL) + - SlideMode.FULLSCREEN_TOGGLE_DELAY; - } - - this.resumeSlideshow_(opt_interval); -}; - -/** - * Stop the slideshow. - * @param {Event=} opt_event Event. - * @private - */ -SlideMode.prototype.stopSlideshow_ = function(opt_event) { - if (!this.isSlideshowOn_()) - return; - - if (opt_event) // Caused by user action, notify the Gallery. - cr.dispatchSimpleEvent(this, 'useraction'); - - this.pauseSlideshow_(); - this.container_.removeAttribute('slideshow'); - - // Do not restore fullscreen if we exited fullscreen while in slideshow. - var fullscreen = util.isFullScreen(this.context_.appWindow); - var toggleModeDelay = 0; - if (!this.fullscreenBeforeSlideshow_ && fullscreen) { - this.toggleFullScreen_(); - toggleModeDelay = SlideMode.FULLSCREEN_TOGGLE_DELAY; - } - if (this.leaveAfterSlideshow_) { - this.leaveAfterSlideshow_ = false; - setTimeout(this.toggleMode_.bind(this), toggleModeDelay); - } -}; - -/** - * @return {boolean} True if the slideshow is playing (not paused). - * @private - */ -SlideMode.prototype.isSlideshowPlaying_ = function() { - return this.container_.getAttribute('slideshow') === 'playing'; -}; - -/** - * Pause/resume the slideshow. - * @private - */ -SlideMode.prototype.toggleSlideshowPause_ = function() { - cr.dispatchSimpleEvent(this, 'useraction'); // Show the tools. - if (this.isSlideshowPlaying_()) { - this.pauseSlideshow_(); - } else { - this.resumeSlideshow_(SlideMode.SLIDESHOW_INTERVAL_FIRST); - } -}; - -/** - * @param {number=} opt_interval Slideshow interval in ms. - * @private - */ -SlideMode.prototype.scheduleNextSlide_ = function(opt_interval) { - console.assert(this.isSlideshowPlaying_(), 'Inconsistent slideshow state'); - - if (this.slideShowTimeout_) - clearTimeout(this.slideShowTimeout_); - - this.slideShowTimeout_ = setTimeout(function() { - this.slideShowTimeout_ = null; - this.selectNext(1); - }.bind(this), - opt_interval || SlideMode.SLIDESHOW_INTERVAL); -}; - -/** - * Resume the slideshow. - * @param {number=} opt_interval Slideshow interval in ms. - * @private - */ -SlideMode.prototype.resumeSlideshow_ = function(opt_interval) { - this.container_.setAttribute('slideshow', 'playing'); - this.scheduleNextSlide_(opt_interval); -}; - -/** - * Pause the slideshow. - * @private - */ -SlideMode.prototype.pauseSlideshow_ = function() { - this.container_.setAttribute('slideshow', 'paused'); - if (this.slideShowTimeout_) { - clearTimeout(this.slideShowTimeout_); - this.slideShowTimeout_ = null; - } -}; - -/** - * @return {boolean} True if the editor is active. - */ -SlideMode.prototype.isEditing = function() { - return this.container_.hasAttribute('editing'); -}; - -/** - * Stop editing. - * @private - */ -SlideMode.prototype.stopEditing_ = function() { - if (this.isEditing()) - this.toggleEditor(); -}; - -/** - * Activate/deactivate editor. - * @param {Event=} opt_event Event. - */ -SlideMode.prototype.toggleEditor = function(opt_event) { - if (opt_event) // Caused by user action, notify the Gallery. - cr.dispatchSimpleEvent(this, 'useraction'); - - if (!this.active_) { - this.toggleMode_(this.toggleEditor.bind(this)); - return; - } - - this.stopSlideshow_(); - if (!this.isEditing() && this.isShowingVideo_()) - return; // No editing for videos. - - ImageUtil.setAttribute(this.container_, 'editing', !this.isEditing()); - - if (this.isEditing()) { // isEditing has just been flipped to a new value. - if (this.context_.readonlyDirName) { - this.editor_.getPrompt().showAt( - 'top', 'GALLERY_READONLY_WARNING', 0, this.context_.readonlyDirName); - } - } else { - this.editor_.getPrompt().hide(); - this.editor_.leaveModeGently(); - } -}; - -/** - * Prints the current item. - * @private - */ -SlideMode.prototype.print_ = function() { - cr.dispatchSimpleEvent(this, 'useraction'); - window.print(); -}; - -/** - * Display the error banner. - * @param {string} message Message. - * @private - */ -SlideMode.prototype.showErrorBanner_ = function(message) { - if (message) { - this.errorBanner_.textContent = this.displayStringFunction_(message); - } - ImageUtil.setAttribute(this.container_, 'error', !!message); -}; - -/** - * Show/hide the busy spinner. - * - * @param {boolean} on True if show, false if hide. - * @private - */ -SlideMode.prototype.showSpinner_ = function(on) { - if (this.spinnerTimer_) { - clearTimeout(this.spinnerTimer_); - this.spinnerTimer_ = null; - } - - if (on) { - this.spinnerTimer_ = setTimeout(function() { - this.spinnerTimer_ = null; - ImageUtil.setAttribute(this.container_, 'spinner', true); - }.bind(this), 1000); - } else { - ImageUtil.setAttribute(this.container_, 'spinner', false); - } -}; - -/** - * @return {boolean} True if the current item is a video. - * @private - */ -SlideMode.prototype.isShowingVideo_ = function() { - return !!this.imageView_.getVideo(); -}; - -/** - * Overlay that handles swipe gestures. Changes to the next or previous file. - * @param {function(number)} callback A callback accepting the swipe direction - * (1 means left, -1 right). - * @constructor - * @implements {ImageBuffer.Overlay} - */ -function SwipeOverlay(callback) { - this.callback_ = callback; -} - -/** - * Inherit ImageBuffer.Overlay. - */ -SwipeOverlay.prototype.__proto__ = ImageBuffer.Overlay.prototype; - -/** - * @param {number} x X pointer position. - * @param {number} y Y pointer position. - * @param {boolean} touch True if dragging caused by touch. - * @return {function} The closure to call on drag. - */ -SwipeOverlay.prototype.getDragHandler = function(x, y, touch) { - if (!touch) - return null; - var origin = x; - var done = false; - return function(x, y) { - if (!done && origin - x > SwipeOverlay.SWIPE_THRESHOLD) { - this.callback_(1); - done = true; - } else if (!done && x - origin > SwipeOverlay.SWIPE_THRESHOLD) { - this.callback_(-1); - done = true; - } - }.bind(this); -}; - -/** - * If the user touched the image and moved the finger more than SWIPE_THRESHOLD - * horizontally it's considered as a swipe gesture (change the current image). - */ -SwipeOverlay.SWIPE_THRESHOLD = 100; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/scrollbar.js b/chromium/chrome/browser/resources/file_manager/foreground/js/scrollbar.js deleted file mode 100644 index a81fe8db12f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/scrollbar.js +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright (c) 2013 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. - -'use strict'; - -/** - * Creates a new scroll bar element. - * @extends {HTMLDivElement} - * @constructor - */ -var ScrollBar = cr.ui.define('div'); - -/** - * Mode of the scrollbar. As for now, only vertical scrollbars are supported. - * @type {number} - */ -ScrollBar.Mode = { - VERTICAL: 0, - HORIZONTAL: 1 -}; - -ScrollBar.prototype = { - set mode(value) { - this.mode_ = value; - if (this.mode_ == ScrollBar.Mode.VERTICAL) { - this.classList.remove('scrollbar-horizontal'); - this.classList.add('scrollbar-vertical'); - } else { - this.classList.remove('scrollbar-vertical'); - this.classList.add('scrollbar-horizontal'); - } - this.redraw_(); - }, - get mode() { - return this.mode_; - } -}; - -/** - * Inherits after HTMLDivElement. - */ -ScrollBar.prototype.__proto__ = HTMLDivElement.prototype; - -/** - * Initializes the DOM structure of the scrollbar. - */ -ScrollBar.prototype.decorate = function() { - this.classList.add('scrollbar'); - this.button_ = util.createChild(this, 'scrollbar-button', 'div'); - this.mode = ScrollBar.Mode.VERTICAL; - - this.button_.addEventListener('mousedown', - this.onButtonPressed_.bind(this)); - window.addEventListener('mouseup', this.onMouseUp_.bind(this)); - window.addEventListener('mousemove', this.onMouseMove_.bind(this)); -}; - -/** - * Initialize a scrollbar. - * - * @param {Element} parent Parent element, must have a relative or absolute - * positioning. - * @param {Element=} opt_scrollableArea Element with scrollable contents. - * If not passed, then call attachToView manually when the scrollable - * element becomes available. - */ -ScrollBar.prototype.initialize = function(parent, opt_scrollableArea) { - parent.appendChild(this); - if (opt_scrollableArea) - this.attachToView(opt_scrollableArea); -}; - -/** - * Attaches the scrollbar to a scrollable element and attaches handlers. - * @param {Element} view Scrollable element. - */ -ScrollBar.prototype.attachToView = function(view) { - this.view_ = view; - this.view_.addEventListener('scroll', this.onScroll_.bind(this)); - this.view_.addEventListener('relayout', this.onRelayout_.bind(this)); - this.domObserver_ = new MutationObserver(this.onDomChanged_.bind(this)); - this.domObserver_.observe(this.view_, {subtree: true, attributes: true}); - this.onRelayout_(); -}; - -/** - * Scroll handler. - * @private - */ -ScrollBar.prototype.onScroll_ = function() { - this.scrollTop_ = this.view_.scrollTop; - this.redraw_(); -}; - -/** - * Relayout handler. - * @private - */ -ScrollBar.prototype.onRelayout_ = function() { - this.scrollHeight_ = this.view_.scrollHeight; - this.clientHeight_ = this.view_.clientHeight; - this.offsetTop_ = this.view_.offsetTop; - this.scrollTop_ = this.view_.scrollTop; - this.redraw_(); -}; - -/** - * Pressing on the scrollbar's button handler. - * - * @param {Event} event Pressing event. - * @private - */ -ScrollBar.prototype.onButtonPressed_ = function(event) { - this.buttonPressed_ = true; - this.buttonPressedEvent_ = event; - this.buttonPressedPosition_ = this.button_.offsetTop - this.view_.offsetTop; - this.button_.classList.add('pressed'); - - event.preventDefault(); -}; - -/** - * Releasing the button handler. Note, that it may not be called when releasing - * outside of the window. Therefore this is also called from onMouseMove_. - * - * @param {Event} event Mouse event. - * @private - */ -ScrollBar.prototype.onMouseUp_ = function(event) { - this.buttonPressed_ = false; - this.button_.classList.remove('pressed'); -}; - -/** - * Mouse move handler. Updates the scroll position. - * - * @param {Event} event Mouse event. - * @private - */ -ScrollBar.prototype.onMouseMove_ = function(event) { - if (!this.buttonPressed_) - return; - if (!event.which) { - this.onMouseUp_(event); - return; - } - var clientSize = this.getClientHeight(); - var totalSize = this.getTotalHeight(); - // TODO(hirono): Fix the geometric calculation. crbug.com/253779 - var buttonSize = Math.max(50, clientSize / totalSize * clientSize); - var buttonPosition = this.buttonPressedPosition_ + - (event.screenY - this.buttonPressedEvent_.screenY); - // Ensures the scrollbar is in the view. - buttonPosition = - Math.max(0, Math.min(buttonPosition, clientSize - buttonSize)); - var scrollPosition; - if (clientSize > buttonSize) { - scrollPosition = Math.max(totalSize - clientSize, 0) * - buttonPosition / (clientSize - buttonSize); - } else { - scrollPosition = 0; - } - - this.scrollTop_ = scrollPosition; - this.view_.scrollTop = scrollPosition; - this.redraw_(); -}; - -/** - * Handles changed in Dom by redrawing the scrollbar. Ignores consecutive calls. - * @private - */ -ScrollBar.prototype.onDomChanged_ = function() { - if (this.domChangedTimer_) { - clearTimeout(this.domChangedTimer_); - this.domChangedTimer_ = null; - } - this.domChangedTimer_ = setTimeout(function() { - this.onRelayout_(); - this.domChangedTimer_ = null; - }.bind(this), 50); -}; - -/** - * Redraws the scrollbar. - * @private - */ -ScrollBar.prototype.redraw_ = function() { - if (!this.view_) - return; - - var clientSize = this.getClientHeight(); - var clientTop = this.offsetTop_; - var scrollPosition = this.scrollTop_; - var totalSize = this.getTotalHeight(); - var hidden = totalSize <= clientSize; - - var buttonSize = Math.max(50, clientSize / totalSize * clientSize); - var buttonPosition; - if (clientSize - buttonSize > 0) { - buttonPosition = scrollPosition / (totalSize - clientSize) * - (clientSize - buttonSize); - } else { - buttonPosition = 0; - } - var buttonTop = buttonPosition + clientTop; - - var time = Date.now(); - if (this.hidden != hidden || - this.lastButtonTop_ != buttonTop || - this.lastButtonSize_ != buttonSize) { - requestAnimationFrame(function() { - this.hidden = hidden; - this.button_.style.top = buttonTop + 'px'; - this.button_.style.height = buttonSize + 'px'; - }.bind(this)); - } - - this.lastButtonTop_ = buttonTop; - this.lastButtonSize_ = buttonSize; -}; - -/** - * Returns the viewport height of the view. - * @return {number} The viewport height of the view in px. - * @protected - */ -ScrollBar.prototype.getClientHeight = function() { - return this.clientHeight_; -}; - -/** - * Returns the total height of the view. - * @return {number} The total height of the view in px. - * @protected - */ -ScrollBar.prototype.getTotalHeight = function() { - return this.scrollHeight_; -}; - -/** - * Creates a new scroll bar for elements in the main panel. - * @extends {ScrollBar} - * @constructor - */ -var MainPanelScrollBar = cr.ui.define('div'); - -/** - * Inherits after ScrollBar. - */ -MainPanelScrollBar.prototype.__proto__ = ScrollBar.prototype; - -/** @override */ -MainPanelScrollBar.prototype.decorate = function() { - ScrollBar.prototype.decorate.call(this); - - /** - * Margin for the transparent preview panel at the bottom. - * @type {number} - * @private - */ - this.bottomMarginForPanel_ = 0; -}; - -/** - * GReturns the viewport height of the view, considering the preview panel. - * - * @return {number} The viewport height of the view in px. - * @override - * @protected - */ -MainPanelScrollBar.prototype.getClientHeight = function() { - return this.clientHeight_ - this.bottomMarginForPanel_; -}; - -/** - * Returns the total height of the view, considering the preview panel. - * - * @return {number} The total height of the view in px. - * @override - * @protected - */ -MainPanelScrollBar.prototype.getTotalHeight = function() { - return this.scrollHeight_ - this.bottomMarginForPanel_; -}; - -/** - * Sets the bottom margin height of the view for the transparent preview panel. - * @param {number} margin Margin to be set in px. - */ -MainPanelScrollBar.prototype.setBottomMarginForPanel = function(margin) { - this.bottomMarginForPanel_ = margin; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/share_client.js b/chromium/chrome/browser/resources/file_manager/foreground/js/share_client.js deleted file mode 100644 index 3044b21a17e..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/share_client.js +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * @param {WebView} webView Web View tag. - * @param {string} url Share Url for an entry. - * @param {ShareClient.Observer} observer Observer instance. - * @constructor - */ -function ShareClient(webView, url, observer) { - this.webView_ = webView; - this.url_ = url; - this.observer_ = observer; - this.loaded_ = false; - this.loading_ = false; - this.onMessageBound_ = this.onMessage_.bind(this); - this.onLoadStopBound_ = this.onLoadStop_.bind(this); - this.onLoadAbortBound_ = this.onLoadAbort_.bind(this); -} - -/** - * Source origin of the client. - * @type {string} - * @const - */ -ShareClient.SHARE_ORIGIN = - 'chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj'; - -/** - * Target origin of the embedded dialog. - * @type {string} - * @const - */ -ShareClient.SHARE_TARGET = 'https://drive.google.com'; - -/** - * Observes for state changes of the embedded dialog. - * @interface - */ -ShareClient.Observer = function() { -}; - -/** - * Notifies about the embedded dialog being loaded. - */ -ShareClient.Observer.prototype.onLoaded = function() { -}; - -/** - * Notifies when the the embedded dialog failed to load. - */ -ShareClient.Observer.prototype.onLoadingFailed = function() { -}; - -/** - * Notifies about changed dimensions of the embedded dialog. - * @param {number} width Width in pixels. - * @param {number} height Height in pixels. - * @param {function()} callback Completion callback. Call when finished - * handling the resize. - */ -ShareClient.Observer.prototype.onResized = function(width, height, callback) { -}; - -/** - * Notifies about the embedded dialog being closed. - */ -ShareClient.Observer.prototype.onClosed = function() { -}; - -/** - * Handles messages from the embedded dialog. - * @param {Event} e Message event. - * @private - */ -ShareClient.prototype.onMessage_ = function(e) { - if (e.origin != ShareClient.SHARE_TARGET && !window.IN_TEST) { - // Logs added temporarily to track crbug.com/288783. - console.debug('Received a message from an illegal origin: ' + e.origin); - return; - } - - var data = JSON.parse(e.data); - // Logs added temporarily to track crbug.com/288783. - console.debug('Received message: ' + data.type); - - switch (data.type) { - case 'resize': - this.observer_.onResized(data.args.width, - data.args.height, - this.postMessage_.bind(this, 'resizeComplete')); - break; - case 'prepareForVisible': - this.postMessage_('prepareComplete'); - if (!this.loaded_) { - this.loading_ = false; - this.loaded_ = true; - this.observer_.onLoaded(); - } - break; - case 'setVisible': - if (!data.args.visible) - this.observer_.onClosed(); - break; - } -}; - -/** - * Handles completion of the web view request. - * @param {Event} e Message event. - * @private - */ -ShareClient.prototype.onLoadStop_ = function(e) { - // Logs added temporarily to track crbug.com/288783. - console.debug('Web View loaded.'); - - this.postMessage_('makeBodyVisible'); -}; - -/** - * Handles termination of the web view request. - * @param {Event} e Message event. - * @private - */ -ShareClient.prototype.onLoadAbort_ = function(e) { - // Logs added temporarily to track crbug.com/288783. - console.debug('Web View failed to load with error: ' + e.reason + ', url: ' + - e.url + ' while requested: ' + this.url_); - - this.observer_.onLoadFailed(); -}; - -/** - * Sends a message to the embedded dialog. - * @param {string} type Message type. - * @param {Object=} opt_args Optional arguments. - * @private - */ -ShareClient.prototype.postMessage_ = function(type, opt_args) { - // Logs added temporarily to track crbug.com/288783. - console.debug('Sending message: ' + type); - - var message = { - type: type, - args: opt_args - }; - this.webView_.contentWindow.postMessage( - JSON.stringify(message), - !window.IN_TEST ? ShareClient.SHARE_TARGET : '*'); -}; - -/** - * Loads the embedded dialog. Can be called only one. - */ -ShareClient.prototype.load = function() { - if (this.loading_ || this.loaded_) - throw new Error('Already loaded.'); - this.loading_ = true; - - // Logs added temporarily to track crbug.com/288783. - console.debug('Loading.'); - - window.addEventListener('message', this.onMessageBound_); - this.webView_.addEventListener('loadstop', this.onLoadStopBound_); - this.webView_.addEventListener('loadabort', this.onLoadAbortBound_); - this.webView_.setAttribute('src', this.url_); -}; - -/** - * Aborts loading of the embedded dialog and performs cleanup. - */ -ShareClient.prototype.abort = function() { - window.removeEventListener('message', this.onMessageBound_); - this.webView_.removeEventListener('loadstop', this.onLoadStopBound_); - this.webView_.removeEventListener( - 'loadabort', this.onLoadAbortBound_); - this.webView_.stop(); -}; - -/** - * Cleans the dialog by removing all handlers. - */ -ShareClient.prototype.dispose = function() { - this.abort(); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/share_dialog.js b/chromium/chrome/browser/resources/file_manager/foreground/js/share_dialog.js deleted file mode 100644 index ff7fbf6b665..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/share_dialog.js +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * @param {HTMLElement} parentNode Node to be parent for this dialog. - * @constructor - * @extends {FileManagerDialogBase} - * @implements {ShareClient.Observer} - */ -function ShareDialog(parentNode) { - this.queue_ = new AsyncUtil.Queue(); - this.onQueueTaskFinished_ = null; - this.shareClient_ = null; - this.spinner_ = null; - this.spinnerLayer_ = null; - this.webViewWrapper_ = null; - this.webView_ = null; - this.failureTimeout_ = null; - this.callback_ = null; - - FileManagerDialogBase.call(this, parentNode); -} - -/** - * Timeout for loading the share dialog before giving up. - * @type {number} - * @const - */ -ShareDialog.FAILURE_TIMEOUT = 10000; - -/** - * The result of opening the dialog. - * @enum {string} - * @const - */ -ShareDialog.Result = Object.freeze({ - // The dialog is closed normally. This includes user cancel. - SUCCESS: 'success', - // The dialog is closed by network error. - NETWORK_ERROR: 'networkError', - // The dialog is not opened because it is already showing. - ALREADY_SHOWING: 'alreadyShowing' -}); - -/** - * Wraps a Web View element and adds authorization headers to it. - * @param {string} urlPattern Pattern of urls to be authorized. - * @param {WebView} webView Web View element to be wrapped. - * @constructor - */ -ShareDialog.WebViewAuthorizer = function(urlPattern, webView) { - this.urlPattern_ = urlPattern; - this.webView_ = webView; - this.initialized_ = false; - this.accessToken_ = null; -}; - -/** - * Initializes the web view by installing hooks injecting the authorization - * headers. - * @param {function()} callback Completion callback. - */ -ShareDialog.WebViewAuthorizer.prototype.initialize = function(callback) { - if (this.initialized_) { - callback(); - return; - } - - var registerInjectionHooks = function() { - this.webView_.removeEventListener('loadstop', registerInjectionHooks); - this.webView_.request.onBeforeSendHeaders.addListener( - this.authorizeRequest_.bind(this), - {urls: [this.urlPattern_]}, - ['blocking', 'requestHeaders']); - this.initialized_ = true; - callback(); - }.bind(this); - - this.webView_.addEventListener('loadstop', registerInjectionHooks); - this.webView_.setAttribute('src', 'data:text/html,'); -}; - -/** - * Authorizes the web view by fetching the freshest access tokens. - * @param {function()} callback Completion callback. - */ -ShareDialog.WebViewAuthorizer.prototype.authorize = function(callback) { - // Fetch or update the access token. - chrome.fileBrowserPrivate.requestAccessToken(false, // force_refresh - function(inAccessToken) { - this.accessToken_ = inAccessToken; - callback(); - }.bind(this)); -}; - -/** - * Injects headers into the passed request. - * @param {Event} e Request event. - * @return {{requestHeaders: HttpHeaders}} Modified headers. - * @private - */ -ShareDialog.WebViewAuthorizer.prototype.authorizeRequest_ = function(e) { - e.requestHeaders.push({ - name: 'Authorization', - value: 'Bearer ' + this.accessToken_ - }); - return {requestHeaders: e.requestHeaders}; -}; - -ShareDialog.prototype = { - __proto__: FileManagerDialogBase.prototype -}; - -/** - * One-time initialization of DOM. - * @private - */ -ShareDialog.prototype.initDom_ = function() { - FileManagerDialogBase.prototype.initDom_.call(this); - this.frame_.classList.add('share-dialog-frame'); - - this.spinnerLayer_ = this.document_.createElement('div'); - this.spinnerLayer_.className = 'spinner-layer'; - this.frame_.appendChild(this.spinnerLayer_); - - this.webViewWrapper_ = this.document_.createElement('div'); - this.webViewWrapper_.className = 'share-dialog-webview-wrapper'; - this.cancelButton_.hidden = true; - this.okButton_.hidden = true; - this.frame_.insertBefore(this.webViewWrapper_, - this.frame_.querySelector('.cr-dialog-buttons')); -}; - -/** - * @override - */ -ShareDialog.prototype.onResized = function(width, height, callback) { - if (width && height) { - this.webViewWrapper_.style.width = width + 'px'; - this.webViewWrapper_.style.height = height + 'px'; - this.webView_.style.width = width + 'px'; - this.webView_.style.height = height + 'px'; - } - setTimeout(callback, 0); -}; - -/** - * @override - */ -ShareDialog.prototype.onClosed = function() { - this.hide(); -}; - -/** - * @override - */ -ShareDialog.prototype.onLoaded = function() { - if (this.failureTimeout_) { - clearTimeout(this.failureTimeout_); - this.failureTimeout_ = null; - } - - // Logs added temporarily to track crbug.com/288783. - console.debug('Loaded.'); - - this.okButton_.hidden = false; - this.spinnerLayer_.hidden = true; - this.webViewWrapper_.classList.add('loaded'); - this.webView_.focus(); -}; - -/** - * @override - */ -ShareDialog.prototype.onLoadFailed = function() { - this.hideWithResult(ShareDialog.Result.NETWORK_ERROR); -}; - -/** - * @override - */ -ShareDialog.prototype.hide = function(opt_onHide) { - this.hideWithResult(ShareDialog.Result.SUCCESS, opt_onHide); -}; - -/** - * Hide the dialog with the result and the callback. - * @param {ShareDialog.Result} result Result passed to the closing callback. - * @param {function()=} opt_onHide Callback called at the end of hiding. - */ -ShareDialog.prototype.hideWithResult = function(result, opt_onHide) { - if (!this.isShowing()) - return; - - if (this.shareClient_) { - this.shareClient_.dispose(); - this.shareClient_ = null; - } - - this.webViewWrapper_.textContent = ''; - if (this.failureTimeout_) { - clearTimeout(this.failureTimeout_); - this.failureTimeout_ = null; - } - - FileManagerDialogBase.prototype.hide.call( - this, - function() { - if (opt_onHide) - opt_onHide(); - this.callback_(result); - this.callback_ = null; - }.bind(this)); -}; - -/** - * Shows the dialog. - * @param {FileEntry} entry Entry to share. - * @param {function(boolean)} callback Callback to be called when the showing - * task is completed. The argument is whether to succeed or not. Note that - * cancel is regarded as success. - */ -ShareDialog.prototype.show = function(entry, callback) { - // If the dialog is already showing, return the error. - if (this.isShowing()) { - callback(ShareDialog.Result.ALREADY_SHOWING); - return; - } - - // Initialize the variables. - this.callback_ = callback; - this.spinnerLayer_.hidden = false; - this.webViewWrapper_.style.width = ''; - this.webViewWrapper_.style.height = ''; - - // If the embedded share dialog is not started within some time, then - // give up and show an error message. - this.failureTimeout_ = setTimeout(function() { - this.hideWithResult(ShareDialog.Result.NETWORK_ERROR); - - // Logs added temporarily to track crbug.com/288783. - console.debug('Timeout. Web View points at: ' + this.webView_.src); - }.bind(this), ShareDialog.FAILURE_TIMEOUT); - - // TODO(mtomasz): Move to initDom_() once and reuse <webview> once it gets - // fixed. See: crbug.com/260622. - this.webView_ = util.createChild( - this.webViewWrapper_, 'share-dialog-webview', 'webview'); - this.webView_.setAttribute('tabIndex', '-1'); - this.webViewAuthorizer_ = new ShareDialog.WebViewAuthorizer( - !window.IN_TEST ? (ShareClient.SHARE_TARGET + '/*') : '<all_urls>', - this.webView_); - this.webView_.addEventListener('newwindow', function(e) { - // Discard the window object and reopen in an external window. - e.window.discard(); - util.visitURL(e.targetUrl); - e.preventDefault(); - }); - var show = FileManagerDialogBase.prototype.showBlankDialog.call(this); - if (!show) { - // The code shoundn't get here, since already-showing was handled before. - console.error('ShareDialog can\'t be shown.'); - return; - } - - // Initialize and authorize the Web View tag asynchronously. - var group = new AsyncUtil.Group(); - - // Fetches an url to the sharing dialog. - var shareUrl; - group.add(function(inCallback) { - chrome.fileBrowserPrivate.getShareUrl( - entry.toURL(), - function(inShareUrl) { - if (!chrome.runtime.lastError) - shareUrl = inShareUrl; - inCallback(); - }); - }); - group.add(this.webViewAuthorizer_.initialize.bind(this.webViewAuthorizer_)); - group.add(this.webViewAuthorizer_.authorize.bind(this.webViewAuthorizer_)); - - // Loads the share widget once all the previous async calls are finished. - group.run(function() { - // If the url is not obtained, return the network error. - if (!shareUrl) { - // Logs added temporarily to track crbug.com/288783. - console.debug('URL not available.'); - - this.hideWithResult(ShareDialog.Result.NETWORK_ERROR); - return; - } - // Already inactive, therefore ignore. - if (!this.isShowing()) - return; - this.shareClient_ = new ShareClient(this.webView_, - shareUrl, - this); - this.shareClient_.load(); - }.bind(this)); -}; - -/** - * Tells whether the share dialog is showing or not. - * - * @return {boolean} True since the show method is called and until the closing - * callback is invoked. - */ -ShareDialog.prototype.isShowing = function() { - return !!this.callback_; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/suggest_apps_dialog.js b/chromium/chrome/browser/resources/file_manager/foreground/js/suggest_apps_dialog.js deleted file mode 100644 index 27d12dfe19b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/suggest_apps_dialog.js +++ /dev/null @@ -1,554 +0,0 @@ -// Copyright (c) 2013 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. - -'use strict'; - -/** - * SuggestAppsDialog contains a list box to select an app to be opened the file - * with. This dialog should be used as action picker for file operations. - */ - -/** - * The width of the widget (in pixel). - * @type {number} - * @const - */ -var WEBVIEW_WIDTH = 735; -/** - * The height of the widget (in pixel). - * @type {number} - * @const - */ -var WEBVIEW_HEIGHT = 480; - -/** - * The URL of the widget. - * @type {string} - * @const - */ -var CWS_WIDGET_URL = - 'https://clients5.google.com/webstore/wall/cros-widget-container'; -/** - * The origin of the widget. - * @type {string} - * @const - */ -var CWS_WIDGET_ORIGIN = 'https://clients5.google.com'; - -/** - * Creates dialog in DOM tree. - * - * @param {HTMLElement} parentNode Node to be parent for this dialog. - * @param {Object} state Static state of suggest app dialog. - * @constructor - * @extends {FileManagerDialogBase} - */ -function SuggestAppsDialog(parentNode, state) { - FileManagerDialogBase.call(this, parentNode); - - this.frame_.id = 'suggest-app-dialog'; - - this.webviewContainer_ = this.document_.createElement('div'); - this.webviewContainer_.id = 'webview-container'; - this.webviewContainer_.style.width = WEBVIEW_WIDTH + 'px'; - this.webviewContainer_.style.height = WEBVIEW_HEIGHT + 'px'; - this.frame_.insertBefore(this.webviewContainer_, this.text_.nextSibling); - - var spinnerLayer = this.document_.createElement('div'); - spinnerLayer.className = 'spinner-layer'; - this.webviewContainer_.appendChild(spinnerLayer); - - this.buttons_ = this.document_.createElement('div'); - this.buttons_.id = 'buttons'; - this.frame_.appendChild(this.buttons_); - - this.webstoreButton_ = this.document_.createElement('div'); - this.webstoreButton_.id = 'webstore-button'; - this.webstoreButton_.innerHTML = str('SUGGEST_DIALOG_LINK_TO_WEBSTORE'); - this.webstoreButton_.addEventListener( - 'click', this.onWebstoreLinkClicked_.bind(this)); - this.buttons_.appendChild(this.webstoreButton_); - - this.initialFocusElement_ = this.webviewContainer_; - - this.webview_ = null; - this.accessToken_ = null; - this.widgetUrl_ = - state.overrideCwsContainerUrlForTest || CWS_WIDGET_URL; - this.widgetOrigin_ = - state.overrideCwsContainerOriginForTest || CWS_WIDGET_ORIGIN; - - this.extension_ = null; - this.mime_ = null; - this.installingItemId_ = null; - this.state_ = SuggestAppsDialog.State.UNINITIALIZED; - - this.initializationTask_ = new AsyncUtil.Group(); - this.initializationTask_.add(this.retrieveAuthorizeToken_.bind(this)); - this.initializationTask_.run(); -} - -SuggestAppsDialog.prototype = { - __proto__: FileManagerDialogBase.prototype -}; - -/** - * @enum {string} - * @const - */ -SuggestAppsDialog.State = { - UNINITIALIZED: 'SuggestAppsDialog.State.UNINITIALIZED', - INITIALIZING: 'SuggestAppsDialog.State.INITIALIZING', - INITIALIZE_FAILED_CLOSING: - 'SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING', - INITIALIZED: 'SuggestAppsDialog.State.INITIALIZED', - INSTALLING: 'SuggestAppsDialog.State.INSTALLING', - INSTALLED_CLOSING: 'SuggestAppsDialog.State.INSTALLED_CLOSING', - OPENING_WEBSTORE_CLOSING: 'SuggestAppsDialog.State.OPENING_WEBSTORE_CLOSING', - CANCELED_CLOSING: 'SuggestAppsDialog.State.CANCELED_CLOSING' -}; -Object.freeze(SuggestAppsDialog.State); - -/** - * @enum {string} - * @const - */ -SuggestAppsDialog.Result = { - // Install is done. The install app should be opened. - INSTALL_SUCCESSFUL: 'SuggestAppsDialog.Result.INSTALL_SUCCESSFUL', - // User cancelled the suggest app dialog. No message should be shown. - USER_CANCELL: 'SuggestAppsDialog.Result.USER_CANCELL', - // User clicked the link to web store so the dialog is closed. - WEBSTORE_LINK_OPENED: 'SuggestAppsDialog.Result.WEBSTORE_LINK_OPENED', - // Failed to load the widget. Error message should be shown. - FAILED: 'SuggestAppsDialog.Result.FAILED' -}; -Object.freeze(SuggestAppsDialog.Result); - -/** - * @override - */ -SuggestAppsDialog.prototype.onInputFocus = function() { - this.webviewContainer_.select(); -}; - -/** - * Injects headers into the passed request. - * - * @param {Event} e Request event. - * @return {{requestHeaders: HttpHeaders}} Modified headers. - * @private - */ -SuggestAppsDialog.prototype.authorizeRequest_ = function(e) { - e.requestHeaders.push({ - name: 'Authorization', - value: 'Bearer ' + this.accessToken_ - }); - return {requestHeaders: e.requestHeaders}; -}; - -/** - * Retrieves the authorize token. This method should be called in - * initialization of the dialog. - * - * @param {function()} callback Called when the token is retrieved. - * @private - */ -SuggestAppsDialog.prototype.retrieveAuthorizeToken_ = function(callback) { - if (window.IN_TEST) { - // In test, use a dummy string as token. This must be a non-empty string. - this.accessToken_ = 'DUMMY_ACCESS_TOKEN_FOR_TEST'; - } - - if (this.accessToken_) { - callback(); - return; - } - - // Fetch or update the access token. - chrome.fileBrowserPrivate.requestWebStoreAccessToken( - function(accessToken) { - // In case of error, this.accessToken_ will be set to null. - this.accessToken_ = accessToken; - callback(); - }.bind(this)); -}; - -/** - * Dummy function for SuggestAppsDialog.show() not to be called unintentionally. - */ -SuggestAppsDialog.prototype.show = function() { - console.error('SuggestAppsDialog.show() shouldn\'t be called directly.'); -}; - -/** - * Shows suggest-apps dialog by file extension and mime. - * - * @param {string} extension Extension of the file. - * @param {string} mime Mime of the file. - * @param {function(boolean)} onDialogClosed Called when the dialog is closed. - * The argument is the result of installation: true if an app is installed, - * false otherwise. - */ -SuggestAppsDialog.prototype.showByExtensionAndMime = - function(extension, mime, onDialogClosed) { - this.text_.hidden = true; - this.dialogText_ = ''; - this.showInternal_(null, extension, mime, onDialogClosed); -}; - -/** - * Shows suggest-apps dialog by the filename. - * - * @param {string} filename Filename (without extension) of the file. - * @param {function(boolean)} onDialogClosed Called when the dialog is closed. - * The argument is the result of installation: true if an app is installed, - * false otherwise. - */ -SuggestAppsDialog.prototype.showByFilename = - function(filename, onDialogClosed) { - this.text_.hidden = false; - this.dialogText_ = str('SUGGEST_DIALOG_MESSAGE_FOR_EXECUTABLE'); - this.showInternal_(filename, null, null, onDialogClosed); -}; - -/** - * Internal methdo to shows a dialog. This should be called only from 'Suggest. - * appDialog.showXxxx()' functions. - * - * @param {string} filename Filename (without extension) of the file. - * @param {string} extension Extension of the file. - * @param {string} mime Mime of the file. - * @param {function(boolean)} onDialogClosed Called when the dialog is closed. - * The argument is the result of installation: true if an app is installed, - * false otherwise. - * @private - */ -SuggestAppsDialog.prototype.showInternal_ = - function(filename, extension, mime, onDialogClosed) { - if (this.state_ != SuggestAppsDialog.State.UNINITIALIZED) { - console.error('Invalid state.'); - return; - } - - this.extension_ = extension; - this.mimeType_ = mime; - this.onDialogClosed_ = onDialogClosed; - this.state_ = SuggestAppsDialog.State.INITIALIZING; - - SuggestAppsDialog.Metrics.recordShowDialog(); - SuggestAppsDialog.Metrics.startLoad(); - - // Makes it sure that the initialization is completed. - this.initializationTask_.run(function() { - if (!this.accessToken_) { - this.state_ = SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING; - this.onHide_(); - return; - } - - var title = str('SUGGEST_DIALOG_TITLE'); - var show = this.dialogText_ ? - FileManagerDialogBase.prototype.showTitleAndTextDialog.call( - this, title, this.dialogText_) : - FileManagerDialogBase.prototype.showTitleOnlyDialog.call( - this, title); - if (!show) { - console.error('SuggestAppsDialog can\'t be shown'); - this.state_ = SuggestAppsDialog.State.UNINITIALIZED; - this.onHide(); - return; - } - - this.webview_ = this.document_.createElement('webview'); - this.webview_.id = 'cws-widget'; - this.webview_.partition = 'persist:cwswidgets'; - this.webview_.style.width = WEBVIEW_WIDTH + 'px'; - this.webview_.style.height = WEBVIEW_HEIGHT + 'px'; - this.webview_.request.onBeforeSendHeaders.addListener( - this.authorizeRequest_.bind(this), - {urls: [this.widgetOrigin_ + '/*']}, - ['blocking', 'requestHeaders']); - this.webview_.addEventListener('newwindow', function(event) { - // Discard the window object and reopen in an external window. - event.window.discard(); - util.visitURL(event.targetUrl); - event.preventDefault(); - }); - this.webviewContainer_.appendChild(this.webview_); - - this.frame_.classList.add('show-spinner'); - - this.webviewClient_ = new CWSContainerClient( - this.webview_, - extension, mime, filename, - WEBVIEW_WIDTH, WEBVIEW_HEIGHT, - this.widgetUrl_, this.widgetOrigin_); - this.webviewClient_.addEventListener(CWSContainerClient.Events.LOADED, - this.onWidgetLoaded_.bind(this)); - this.webviewClient_.addEventListener(CWSContainerClient.Events.LOAD_FAILED, - this.onWidgetLoadFailed_.bind(this)); - this.webviewClient_.addEventListener( - CWSContainerClient.Events.REQUEST_INSTALL, - this.onInstallRequest_.bind(this)); - this.webviewClient_.load(); - }.bind(this)); -}; - -/** - * Called when the 'See more...' link is clicked to be navigated to Webstore. - * @param {Event} e Event. - * @private - */ -SuggestAppsDialog.prototype.onWebstoreLinkClicked_ = function(e) { - var webStoreUrl = - FileTasks.createWebStoreLink(this.extension_, this.mimeType_); - chrome.windows.create({url: webStoreUrl}); - this.state_ = SuggestAppsDialog.State.OPENING_WEBSTORE_CLOSING; - this.hide(); -}; - -/** - * Called when the widget is loaded successfully. - * @param {Event} event Event. - * @private - */ -SuggestAppsDialog.prototype.onWidgetLoaded_ = function(event) { - SuggestAppsDialog.Metrics.finishLoad(); - SuggestAppsDialog.Metrics.recordLoad( - SuggestAppsDialog.Metrics.LOAD.SUCCEEDED); - - this.frame_.classList.remove('show-spinner'); - this.state_ = SuggestAppsDialog.State.INITIALIZED; - - this.webview_.focus(); -}; - -/** - * Called when the widget is failed to load. - * @param {Event} event Event. - * @private - */ -SuggestAppsDialog.prototype.onWidgetLoadFailed_ = function(event) { - SuggestAppsDialog.Metrics.recordLoad(SuggestAppsDialog.Metrics.LOAD.FAILURE); - - this.frame_.classList.remove('show-spinner'); - this.state_ = SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING; - - this.hide(); -}; - -/** - * Called when the connection status is changed. - * @param {util.DriveConnectionType} connectionType Current connection type. - */ -SuggestAppsDialog.prototype.onDriveConnectionChanged = - function(connectionType) { - if (this.state_ !== SuggestAppsDialog.State.UNINITIALIZED && - connectionType === util.DriveConnectionType.OFFLINE) { - this.state_ = SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING; - this.hide(); - } -}; - -/** - * Called when receiving the install request from the webview client. - * @param {Event} e Event. - * @private - */ -SuggestAppsDialog.prototype.onInstallRequest_ = function(e) { - var itemId = e.itemId; - this.installingItemId_ = itemId; - - this.appInstaller_ = new AppInstaller(itemId); - this.appInstaller_.install(this.onInstallCompleted_.bind(this)); - - this.frame_.classList.add('show-spinner'); - this.state_ = SuggestAppsDialog.State.INSTALLING; -}; - -/** - * Called when the installation is completed from the app installer. - * @param {AppInstaller.Result} result Result of the installation. - * @param {string} error Detail of the error. - * @private - */ -SuggestAppsDialog.prototype.onInstallCompleted_ = function(result, error) { - var success = (result === AppInstaller.Result.SUCCESS); - - this.frame_.classList.remove('show-spinner'); - this.state_ = success ? - SuggestAppsDialog.State.INSTALLED_CLOSING : - SuggestAppsDialog.State.INITIALIZED; // Back to normal state. - this.webviewClient_.onInstallCompleted(success, this.installingItemId_); - this.installingItemId_ = null; - - switch (result) { - case AppInstaller.Result.SUCCESS: - SuggestAppsDialog.Metrics.recordInstall( - SuggestAppsDialog.Metrics.INSTALL.SUCCESS); - this.hide(); - break; - case AppInstaller.Result.CANCELLED: - SuggestAppsDialog.Metrics.recordInstall( - SuggestAppsDialog.Metrics.INSTALL.CANCELLED); - // User cancelled the installation. Do nothing. - break; - case AppInstaller.Result.ERROR: - SuggestAppsDialog.Metrics.recordInstall( - SuggestAppsDialog.Metrics.INSTALL.FAILED); - fileManager.error.show(str('SUGGEST_DIALOG_INSTALLATION_FAILED')); - break; - } -}; - -/** - * @override - */ -SuggestAppsDialog.prototype.hide = function(opt_originalOnHide) { - switch (this.state_) { - case SuggestAppsDialog.State.INSTALLING: - // Install is being aborted. Send the failure result. - // Cancels the install. - if (this.webviewClient_) - this.webviewClient_.onInstallCompleted(false, this.installingItemId_); - this.installingItemId_ = null; - - // Assumes closing the dialog as canceling the install. - this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING; - break; - case SuggestAppsDialog.State.INITIALIZING: - SuggestAppsDialog.Metrics.recordLoad( - SuggestAppsDialog.Metrics.LOAD.CANCELLED); - this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING; - break; - case SuggestAppsDialog.State.INSTALLED_CLOSING: - case SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING: - case SuggestAppsDialog.State.OPENING_WEBSTORE_CLOSING: - // Do nothing. - break; - case SuggestAppsDialog.State.INITIALIZED: - this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING; - break; - default: - this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING; - console.error('Invalid state.'); - } - - if (this.webviewClient_) { - this.webviewClient_.dispose(); - this.webviewClient_ = null; - } - - this.webviewContainer_.removeChild(this.webview_); - this.webview_ = null; - this.extension_ = null; - this.mime_ = null; - - FileManagerDialogBase.prototype.hide.call( - this, - this.onHide_.bind(this, opt_originalOnHide)); -}; - -/** - * @param {function()=} opt_originalOnHide Original onHide function passed to - * SuggestAppsDialog.hide(). - * @private - */ -SuggestAppsDialog.prototype.onHide_ = function(opt_originalOnHide) { - // Calls the callback after the dialog hides. - if (opt_originalOnHide) - opt_originalOnHide(); - - var result; - switch (this.state_) { - case SuggestAppsDialog.State.INSTALLED_CLOSING: - result = SuggestAppsDialog.Result.INSTALL_SUCCESSFUL; - SuggestAppsDialog.Metrics.recordCloseDialog( - SuggestAppsDialog.Metrics.CLOSE_DIALOG.ITEM_INSTALLED); - break; - case SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING: - result = SuggestAppsDialog.Result.FAILED; - break; - case SuggestAppsDialog.State.CANCELED_CLOSING: - result = SuggestAppsDialog.Result.USER_CANCELL; - SuggestAppsDialog.Metrics.recordCloseDialog( - SuggestAppsDialog.Metrics.CLOSE_DIALOG.USER_CANCELL); - break; - case SuggestAppsDialog.State.OPENING_WEBSTORE_CLOSING: - result = SuggestAppsDialog.Result.WEBSTORE_LINK_OPENED; - SuggestAppsDialog.Metrics.recordCloseDialog( - SuggestAppsDialog.Metrics.CLOSE_DIALOG.WEB_STORE_LINK); - break; - default: - result = SuggestAppsDialog.Result.USER_CANCELL; - SuggestAppsDialog.Metrics.recordCloseDialog( - SuggestAppsDialog.Metrics.CLOSE_DIALOG.UNKNOWN_ERROR); - console.error('Invalid state.'); - } - this.state_ = SuggestAppsDialog.State.UNINITIALIZED; - - this.onDialogClosed_(result); -}; - -/** - * Utility methods and constants to record histograms. - */ -SuggestAppsDialog.Metrics = Object.freeze({ - LOAD: Object.freeze({ - SUCCEEDED: 0, - CANCELLED: 1, - FAILED: 2, - }), - - /** - * @param {SuggestAppsDialog.Metrics.LOAD} result Result of load. - */ - recordLoad: function(result) { - if (0 <= result && result < 3) - metrics.recordEnum('SuggestApps.Load', result, 3); - }, - - CLOSE_DIALOG: Object.freeze({ - UNKOWN_ERROR: 0, - ITEM_INSTALLED: 1, - USER_CANCELLED: 2, - WEBSTORE_LINK_OPENED: 3, - }), - - /** - * @param {SuggestAppsDialog.Metrics.CLOSE_DIALOG} reason Reason of closing - * dialog. - */ - recordCloseDialog: function(reason) { - if (0 <= reason && reason < 4) - metrics.recordEnum('SuggestApps.CloseDialog', reason, 4); - }, - - INSTALL: Object.freeze({ - SUCCEEDED: 0, - CANCELLED: 1, - FAILED: 2, - }), - - /** - * @param {SuggestAppsDialog.Metrics.INSTALL} result Result of installation. - */ - recordInstall: function(result) { - if (0 <= result && result < 3) - metrics.recordEnum('SuggestApps.Install', result, 3); - }, - - recordShowDialog: function() { - metrics.recordUserAction('SuggestApps.ShowDialog'); - }, - - startLoad: function() { - metrics.startInterval('SuggestApps.LoadTime'); - }, - - finishLoad: function() { - metrics.recordInterval('SuggestApps.LoadTime'); - }, -}); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/text_measure.js b/chromium/chrome/browser/resources/file_manager/foreground/js/text_measure.js deleted file mode 100644 index a8db83ae582..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/text_measure.js +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * TextMeasure constructor. - * - * TextMeasure is a measure for text that returns the width of text. This - * class has a dummy span element. When measuring the width of text, it sets - * the text to the element and obtains the element's size by - * getBoundingClientRect. - * - * @constructor - * @param {HTMLElement} element Element that has styles of measured text. The - * width of text is measures like as it is rendered in this element. - */ -var TextMeasure = function(element) { - var doc = element.ownerDocument; - this.dummySpan_ = doc.createElement('span'); - this.dummySpan_ = doc.getElementsByTagName('body')[0]. - appendChild(this.dummySpan_); - this.dummySpan_.style.position = 'absolute'; - this.dummySpan_.style.visibility = 'hidden'; - var styles = window.getComputedStyle(element, ''); - var stylesToBeCopied = [ - 'fontSize', - 'fontStyle', - 'fontWeight', - 'fontFamily', - 'letterSpacing' - ]; - for (var i = 0; i < stylesToBeCopied.length; i++) { - this.dummySpan_.style[stylesToBeCopied[i]] = styles[stylesToBeCopied[i]]; - } - Object.seal(this); -}; - -/** - * Measures the width of text. - * - * @param {string} text Text that is measured the width. - * @return {number} Width of the specified text. - */ -TextMeasure.prototype.getWidth = function(text) { - this.dummySpan_.innerText = text; - var rect = this.dummySpan_.getBoundingClientRect(); - return rect ? rect.width : 0; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/tree.css.js b/chromium/chrome/browser/resources/file_manager/foreground/js/tree.css.js deleted file mode 100644 index 6b89acbdb86..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/tree.css.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * Custom version of chrome://resources/css/tree.css.js, adding support for - * inverted arrow icons. - */ -(function() { - /** - * @type {number} - * @const - */ - var WIDTH = 14; - - /** - * @type {number} - * @const - */ - var HEIGHT = WIDTH / 2 + 2; - - /** - * @type {number} - * @const - */ - var MARGIN = 1; - - /** - * @param {string} name CSS canvas identifier. - * @param {string} backgroundColor Background color. - * @param {string} strokeColor Outline color. - */ - function prepareTriangle(name, backgroundColor, strokeColor) { - var ctx = document.getCSSCanvasContext('2d', - name, - WIDTH + MARGIN * 2, - HEIGHT + MARGIN * 2); - - ctx.fillStyle = backgroundColor; - ctx.strokeStyle = strokeColor; - ctx.translate(MARGIN, MARGIN); - - ctx.beginPath(); - ctx.moveTo(0, 0); - ctx.lineTo(0, 2); - ctx.lineTo(WIDTH / 2, HEIGHT); - ctx.lineTo(WIDTH, 2); - ctx.lineTo(WIDTH, 0); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - } - - prepareTriangle( - 'tree-triangle', 'rgba(122, 122, 122, 0.6)', 'rgba(0, 0, 0, 0)'); - prepareTriangle('tree-triangle-inverted', '#ffffff', '#ffffff'); -})(); diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/breadcrumbs_controller.js b/chromium/chrome/browser/resources/file_manager/foreground/js/ui/breadcrumbs_controller.js deleted file mode 100644 index 4189ef9ea0b..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/breadcrumbs_controller.js +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * @extends cr.EventTarget - * @param {HTMLDivElement} div Div container for breadcrumbs. - * @param {MetadataCache} metadataCache To retrieve metadata. - * @param {VolumeManagerWrapper} volumeManager Volume manager. - * @constructor - */ -function BreadcrumbsController(div, metadataCache, volumeManager) { - this.bc_ = div; - this.metadataCache_ = metadataCache; - this.volumeManager_ = volumeManager; - this.entry_ = null; - - /** - * Sequence value to skip requests that are out of date. - * @type {number} - * @private - */ - this.showSequence_ = 0; - - // Register events and seql the object. - div.addEventListener('click', this.onClick_.bind(this)); -} - -/** - * Extends cr.EventTarget. - */ -BreadcrumbsController.prototype.__proto__ = cr.EventTarget.prototype; - -/** - * Shows breadcrumbs. - * - * @param {Entry} entry Target entry. - */ -BreadcrumbsController.prototype.show = function(entry) { - if (entry === this.entry_) - return; - - this.entry_ = entry; - this.bc_.hidden = false; - this.bc_.textContent = ''; - this.showSequence_++; - - var queue = new AsyncUtil.Queue(); - var entries = []; - var error = false; - - // Obtain entries from the target entry to the root. - var loop; - var resolveParent = function(inEntry, callback) { - entries.unshift(inEntry); - if (!this.volumeManager_.getLocationInfo(inEntry).isRootEntry) { - inEntry.getParent(function(parent) { - resolveParent(parent, callback); - }, function() { - error = true; - callback(); - }); - } else { - callback(); - } - }.bind(this); - queue.run(resolveParent.bind(null, entry)); - - // Override DRIVE_OTHER root to DRIVE_SHARED_WITH_ME root. - queue.run(function(callback) { - // If an error was occured, just skip. - if (error) { - callback(); - return; - } - - // If the path is not under the drive other root, it is not needed to - // override root type. - var locationInfo = this.volumeManager_.getLocationInfo(entry); - if (!locationInfo) { - error = true; - callback(); - return; - } - if (locationInfo.rootType !== RootType.DRIVE_OTHER) { - callback(); - return; - } - - // Otherwise check the metadata of the directory localted at just under - // drive other. - if (!entries[1]) { - error = true; - callback(); - return; - } - this.metadataCache_.getOne(entries[1], 'drive', function(result) { - if (result && result.sharedWithMe) - entries[0] = RootType.DRIVE_SHARED_WITH_ME; - else - entries.shift(); - callback(); - }); - }.bind(this)); - - // Update DOM element. - queue.run(function(sequence, callback) { - // Check the sequence number to skip requests that are out of date. - if (this.showSequence_ === sequence && !error) - this.updateInternal_(entries); - callback(); - }.bind(this, this.showSequence_)); -}; - -/** - * Updates the breadcrumb display. - * @param {Array.<Entry|RootType>} entries Location information of target path. - * @private - */ -BreadcrumbsController.prototype.updateInternal_ = function(entries) { - // Make elements. - var doc = this.bc_.ownerDocument; - for (var i = 0; i < entries.length; i++) { - // Add a component. - var entry = entries[i]; - var div = doc.createElement('div'); - div.className = 'breadcrumb-path'; - if (entry === RootType.DRIVE_SHARED_WITH_ME) { - div.textContent = PathUtil.getRootLabel(RootType.DRIVE_SHARED_WITH_ME); - } else { - var location = this.volumeManager_.getLocationInfo(entry); - div.textContent = (location && location.isRootEntry) ? - PathUtil.getRootLabel(entry.fullPath) : entry.name; - } - div.entry = entry; - this.bc_.appendChild(div); - - // If this is the last component, break here. - if (i === entries.length - 1) { - div.classList.add('breadcrumb-last'); - break; - } - - // Add a separator. - var separator = doc.createElement('div'); - separator.className = 'separator'; - this.bc_.appendChild(separator); - } - - this.truncate(); -}; - -/** - * Updates breadcrumbs widths in order to truncate it properly. - */ -BreadcrumbsController.prototype.truncate = function() { - if (!this.bc_.firstChild) - return; - - // Assume style.width == clientWidth (items have no margins or paddings). - - for (var item = this.bc_.firstChild; item; item = item.nextSibling) { - item.removeAttribute('style'); - item.removeAttribute('collapsed'); - } - - var containerWidth = this.bc_.clientWidth; - - var pathWidth = 0; - var currentWidth = 0; - var lastSeparator; - for (var item = this.bc_.firstChild; item; item = item.nextSibling) { - if (item.className == 'separator') { - pathWidth += currentWidth; - currentWidth = item.clientWidth; - lastSeparator = item; - } else { - currentWidth += item.clientWidth; - } - } - if (pathWidth + currentWidth <= containerWidth) - return; - if (!lastSeparator) { - this.bc_.lastChild.style.width = Math.min(currentWidth, containerWidth) + - 'px'; - return; - } - var lastCrumbSeparatorWidth = lastSeparator.clientWidth; - // Current directory name may occupy up to 70% of space or even more if the - // path is short. - var maxPathWidth = Math.max(Math.round(containerWidth * 0.3), - containerWidth - currentWidth); - maxPathWidth = Math.min(pathWidth, maxPathWidth); - - var parentCrumb = lastSeparator.previousSibling; - var collapsedWidth = 0; - if (parentCrumb && pathWidth - maxPathWidth > parentCrumb.clientWidth) { - // At least one crumb is hidden completely (or almost completely). - // Show sign of hidden crumbs like this: - // root > some di... > ... > current directory. - parentCrumb.setAttribute('collapsed', ''); - collapsedWidth = Math.min(maxPathWidth, parentCrumb.clientWidth); - maxPathWidth -= collapsedWidth; - if (parentCrumb.clientWidth != collapsedWidth) - parentCrumb.style.width = collapsedWidth + 'px'; - - lastSeparator = parentCrumb.previousSibling; - if (!lastSeparator) - return; - collapsedWidth += lastSeparator.clientWidth; - maxPathWidth = Math.max(0, maxPathWidth - lastSeparator.clientWidth); - } - - pathWidth = 0; - for (var item = this.bc_.firstChild; item != lastSeparator; - item = item.nextSibling) { - // TODO(serya): Mixing access item.clientWidth and modifying style and - // attributes could cause multiple layout reflows. - if (pathWidth + item.clientWidth <= maxPathWidth) { - pathWidth += item.clientWidth; - } else if (pathWidth == maxPathWidth) { - item.style.width = '0'; - } else if (item.classList.contains('separator')) { - // Do not truncate separator. Instead let the last crumb be longer. - item.style.width = '0'; - maxPathWidth = pathWidth; - } else { - // Truncate the last visible crumb. - item.style.width = (maxPathWidth - pathWidth) + 'px'; - pathWidth = maxPathWidth; - } - } - - currentWidth = Math.min(currentWidth, - containerWidth - pathWidth - collapsedWidth); - this.bc_.lastChild.style.width = - (currentWidth - lastCrumbSeparatorWidth) + 'px'; -}; - -/** - * Hide breadcrumbs div. - */ -BreadcrumbsController.prototype.hide = function() { - this.bc_.hidden = true; -}; - -/** - * Handle a click event on a breadcrumb element. - * @param {Event} event The click event. - * @private - */ -BreadcrumbsController.prototype.onClick_ = function(event) { - if (!event.target.classList.contains('breadcrumb-path') || - event.target.classList.contains('breadcrumb-last')) - return; - - var newEvent = new Event('pathclick'); - newEvent.entry = event.target.entry; - this.dispatchEvent(newEvent); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/conflict_dialog.js b/chromium/chrome/browser/resources/file_manager/foreground/js/ui/conflict_dialog.js deleted file mode 100644 index 8aecd737228..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/conflict_dialog.js +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * Dialog to confirm the operation for conflicted file operations. - * - * @param {HTMLElement} parentNode Node to be parent for this dialog. - * @constructor - * @extends {FileManagerDialogBase} - */ -function ConflictDialog(parentNode) { - FileManagerDialogBase.call(this, parentNode); - - /** - * Callback to be called when the showing task is completed. The first - * argument is which button is pressed. The second argument is whether to - * apply all or not. - * - * @type {function(ConflictDialog.Result, boolean)} - * @private - */ - this.callback_ = null; - - /** - * Checkbox to specify whether to apply the selection to all entries or not. - * @type {HTMLElement} - * @private - */ - this.applyAllCheckbox_ = parentNode.ownerDocument.createElement('input'); - this.applyAllCheckbox_.id = 'conflict-confirm-dialog-apply-all-checkbox'; - this.applyAllCheckbox_.type = 'checkbox'; - - // Apply all line. - var applyAllLabel = parentNode.ownerDocument.createElement('label'); - applyAllLabel.textContent = str('CONFLICT_DIALOG_APPLY_TO_ALL'); - applyAllLabel.setAttribute('for', this.applyAllCheckbox_.id); - - /** - * Element of the keep both button. - * @type {HTMLElement} - * @private - */ - this.keepBothButton_ = parentNode.ownerDocument.createElement('button'); - this.keepBothButton_.textContent = str('CONFLICT_DIALOG_KEEP_BOTH'); - this.keepBothButton_.addEventListener( - 'click', - this.hideWithResult_.bind(this, ConflictDialog.Result.KEEP_BOTH)); - - /** - * Element of the replace button. - * @type {HTMLElement} - * @private - */ - this.replaceButton_ = parentNode.ownerDocument.createElement('button'); - this.replaceButton_.textContent = str('CONFLICT_DIALOG_REPLACE'); - this.replaceButton_.addEventListener( - 'click', - this.hideWithResult_.bind(this, ConflictDialog.Result.REPLACE)); - - // Buttons line. - var buttons = this.okButton_.parentNode; - buttons.insertBefore(this.applyAllCheckbox_, this.okButton_); - buttons.insertBefore(applyAllLabel, this.okButton_); - buttons.replaceChild(this.keepBothButton_, this.okButton_); - buttons.appendChild(this.replaceButton_); - - // Frame - this.frame_.id = 'conflict-confirm-dialog'; -} - -/** - * Result of conflict confirm dialogs. - * @enum {string} - * @const - */ -ConflictDialog.Result = Object.freeze({ - KEEP_BOTH: 'keepBoth', - CANCEL: 'cancel', - REPLACE: 'replace' -}); - -ConflictDialog.prototype = { - __proto__: FileManagerDialogBase.prototype -}; - -/** - * Shows the conflict confirm dialog. - * - * @param {string} fileName Filename that is conflicted. - * @param {function(ConflictDialog.Result, boolean)} callback Complete - * callbak. See also ConflictDialog#callback_. - * @return {boolean} True if the dialog can show successfully. False if the - * dialog failed to show due to an existing dialog. - */ -ConflictDialog.prototype.show = function(fileName, callback) { - if (this.callback_) - return false; - - this.callback_ = callback; - FileManagerDialogBase.prototype.showOkCancelDialog.call( - this, - '', // We dont't show the title for the dialog. - strf('CONFLICT_DIALOG_MESSAGE', fileName)); - return true; -}; - -/** - * Handles cancellation. - * @param {Event} event Click event. - * @private - */ -ConflictDialog.prototype.onCancelClick_ = function(event) { - this.hideWithResult_(ConflictDialog.Result.CANCEL); -}; - -/** - * Hides the dialog box with the result. - * @param {ConflictDialog.Result} result Result. - * @private - */ -ConflictDialog.prototype.hideWithResult_ = function(result) { - this.hide(function() { - if (!this.callback_) - return; - this.callback_(result, this.applyAllCheckbox_.checked); - this.callback_ = null; - this.applyAllCheckbox_.checked = false; - }.bind(this)); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/file_manager_dialog_base.js b/chromium/chrome/browser/resources/file_manager/foreground/js/ui/file_manager_dialog_base.js deleted file mode 100644 index 63b856f087f..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/file_manager_dialog_base.js +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * This class is an extended class, to manage the status of the dialogs. - * - * @param {HTMLElement} parentNode Parent node of the dialog. - * @extends {cr.ui.dialogs.FileManagerDialogBase} - * @constructor - */ -var FileManagerDialogBase = function(parentNode) { - cr.ui.dialogs.BaseDialog.call(this, parentNode); -}; - -FileManagerDialogBase.prototype = { - __proto__: cr.ui.dialogs.BaseDialog.prototype -}; - -/** - * The FileManager object. This is used to notify events of showing or hiding - * dialog to file manager. - * - * @type {FileManager} - * @private - */ -FileManagerDialogBase.fileManager_ = null; - -/** - * Setter of FileManagerDialogBase.fileManager_. - * @param {FileManager} fileManager The fileManager object. - */ -FileManagerDialogBase.setFileManager = function(fileManager) { - FileManagerDialogBase.fileManager_ = fileManager; -}; - -/** - * The flag if any dialog is shown. True if a dialog is visible, false - * otherwise. - * @type {boolean} - */ -FileManagerDialogBase.shown = false; - -/** - * @param {string} title Title. - * @param {string} message Message. - * @param {function()} onOk Called when the OK button is pressed. - * @param {function()} onCancel Called when the cancel button is pressed. - * @return {boolean} True if the dialog can show successfully. False if the - * dialog failed to show due to an existing dialog. - */ -FileManagerDialogBase.prototype.showOkCancelDialog = function( - title, message, onOk, onCancel) { - return this.showImpl_(title, message, onOk, onCancel); -}; - -/** - * @param {string} title Title. - * @param {string} message Message. - * @param {function()} onOk Called when the OK button is pressed. - * @param {function()} onCancel Called when the cancel button is pressed. - * @return {boolean} True if the dialog can show successfully. False if the - * dialog failed to show due to an existing dialog. - * @private - */ -FileManagerDialogBase.prototype.showImpl_ = function( - title, message, onOk, onCancel) { - if (FileManagerDialogBase.shown) - return false; - - FileManagerDialogBase.shown = true; - if (FileManagerDialogBase.fileManager_) - FileManagerDialogBase.fileManager_.onDialogShownOrHidden(true); - cr.ui.dialogs.BaseDialog.prototype.showWithTitle.call( - this, title, message, onOk, onCancel, null); - - return true; -}; - -/** - * @return {boolean} True if the dialog can show successfully. False if the - * dialog failed to show due to an existing dialog. - */ -FileManagerDialogBase.prototype.showBlankDialog = function() { - return this.showImpl_('', '', null, null, null); -}; - -/** - * @param {string} title Title. - * @return {boolean} True if the dialog can show successfully. False if the - * dialog failed to show due to an existing dialog. - */ -FileManagerDialogBase.prototype.showTitleOnlyDialog = function(title) { - return this.showImpl_(title, '', null, null, null); -}; - -/** - * @param {string} title Title. - * @param {string} text Text to be shown in the dialog. - * @return {boolean} True if the dialog can show successfully. False if the - * dialog failed to show due to an existing dialog. - */ -FileManagerDialogBase.prototype.showTitleAndTextDialog = function(title, text) { - return this.showImpl_(title, text, null, null, null); -}; - -/** - * @param {function()=} opt_onHide Called when the dialog is hidden. - */ -FileManagerDialogBase.prototype.hide = function(opt_onHide) { - cr.ui.dialogs.BaseDialog.prototype.hide.call( - this, - function() { - if (opt_onHide) - opt_onHide(); - if (FileManagerDialogBase.fileManager_) - FileManagerDialogBase.fileManager_.onDialogShownOrHidden(false); - FileManagerDialogBase.shown = false; - }); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/file_manager_ui.js b/chromium/chrome/browser/resources/file_manager/foreground/js/ui/file_manager_ui.js deleted file mode 100644 index 1d460f54cdb..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/file_manager_ui.js +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * The root of the file manager's view managing the DOM of Files.app. - * - * @param {HTMLElement} element Top level element of Files.app. - * @param {DialogType} dialogType Dialog type. - * @constructor. - */ -var FileManagerUI = function(element, dialogType) { - /** - * Top level element of Files.app. - * @type {HTMLElement} - * @private - */ - this.element_ = element; - - /** - * Dialog type. - * @type {DialogType} - * @private - */ - this.dialogType_ = dialogType; - - /** - * Error dialog. - * @type {ErrorDialog} - */ - this.errorDialog = null; - - /** - * Alert dialog. - * @type {cr.ui.dialogs.AlertDialog} - */ - this.alertDialog = null; - - /** - * Confirm dialog. - * @type {cr.ui.dialogs.ConfirmDialog} - */ - this.confirmDialog = null; - - /** - * Prompt dialog. - * @type {cr.ui.dialogs.PromptDialog} - */ - this.promptDialog = null; - - /** - * Share dialog. - * @type {ShareDialog} - */ - this.shareDialog = null; - - /** - * Default task picker. - * @type {DefaultActionDialog} - */ - this.defaultTaskPicker = null; - - /** - * Suggest apps dialog. - * @type {SuggestAppsDialog} - */ - this.suggestAppsDialog = null; - - /** - * Conflict dialog. - * @type {ConflictDialog} - */ - this.conflictDialog = null; - - /** - * Search box. - * @type {SearchBox} - */ - this.searchBox = null; - - /** - * File type selector in the footer. - * @type {HTMLElement} - */ - this.fileTypeSelector = null; - - /** - * OK button in the footer. - * @type {HTMLElement} - */ - this.okButton = null; - - /** - * Cancel button in the footer. - * @type {HTMLElement} - */ - this.cancelButton = null; - - Object.seal(this); - - // Initialize the header. - this.element_.querySelector('#app-name').innerText = - chrome.runtime.getManifest().name; - - // Initialize dialog type. - this.initDialogType_(); - - // Pre-populate the static localized strings. - i18nTemplate.process(this.element_.ownerDocument, loadTimeData); -}; - -/** - * Tweak the UI to become a particular kind of dialog, as determined by the - * dialog type parameter passed to the constructor. - * - * @private - */ -FileManagerUI.prototype.initDialogType_ = function() { - // Obtain elements. - var hasFooterPanel = - this.dialogType_ == DialogType.SELECT_SAVEAS_FILE || - DialogType.isFolderDialog(this.dialogType_); - - // If the footer panel exists, the buttons are placed there. Otherwise, - // the buttons are on the preview panel. - var parentPanelOfButtons = this.element_.ownerDocument.querySelector( - !hasFooterPanel ? '.preview-panel' : '.dialog-footer'); - parentPanelOfButtons.classList.add('button-panel'); - this.fileTypeSelector = parentPanelOfButtons.querySelector('.file-type'); - this.okButton = parentPanelOfButtons.querySelector('.ok'); - this.cancelButton = parentPanelOfButtons.querySelector('.cancel'); - - // Set attributes. - var okLabel = str('OPEN_LABEL'); - - switch (this.dialogType_) { - case DialogType.SELECT_UPLOAD_FOLDER: - okLabel = str('UPLOAD_LABEL'); - break; - - case DialogType.SELECT_SAVEAS_FILE: - okLabel = str('SAVE_LABEL'); - break; - - case DialogType.SELECT_FOLDER: - case DialogType.SELECT_OPEN_FILE: - case DialogType.SELECT_OPEN_MULTI_FILE: - case DialogType.FULL_PAGE: - break; - - default: - throw new Error('Unknown dialog type: ' + this.dialogType); - } - - this.okButton.textContent = okLabel; - this.element_.setAttribute('type', this.dialogType_); -}; - -/** - * Initialize the dialogs. - */ -FileManagerUI.prototype.initDialogs = function() { - // Initialize the dialog label. - var dialogs = cr.ui.dialogs; - dialogs.BaseDialog.OK_LABEL = str('OK_LABEL'); - dialogs.BaseDialog.CANCEL_LABEL = str('CANCEL_LABEL'); - var appState = window.appState || {}; - - // Create the dialog instances. - this.errorDialog = new ErrorDialog(this.element_); - this.alertDialog = new dialogs.AlertDialog(this.element_); - this.confirmDialog = new dialogs.ConfirmDialog(this.element_); - this.promptDialog = new dialogs.PromptDialog(this.element_); - this.shareDialog = new ShareDialog(this.element_); - this.defaultTaskPicker = - new cr.filebrowser.DefaultActionDialog(this.element_); - this.suggestAppsDialog = new SuggestAppsDialog( - this.element_, appState.suggestAppsDialogState || {}); - this.conflictDialog = new ConflictDialog(this.element_); -}; - -/** - * Initialize here elements, which are expensive - * or hidden in the beginning. - */ -FileManagerUI.prototype.initAdditionalUI = function() { - this.searchBox = new SearchBox(this.element_.querySelector('#search-box')); -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/navigation_list.js b/chromium/chrome/browser/resources/file_manager/foreground/js/ui/navigation_list.js deleted file mode 100644 index f471aa6c0de..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/navigation_list.js +++ /dev/null @@ -1,386 +0,0 @@ -// 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. - -'use strict'; - -/** - * A navigation list item. - * @constructor - * @extends {HTMLLIElement} - */ -var NavigationListItem = cr.ui.define('li'); - -NavigationListItem.prototype = { - __proto__: HTMLLIElement.prototype, - get modelItem() { return this.modelItem_; } -}; - -/** - * Decorate the item. - */ -NavigationListItem.prototype.decorate = function() { - // decorate() may be called twice: from the constructor and from - // List.createItem(). This check prevents double-decorating. - if (this.className) - return; - - this.className = 'root-item'; - this.setAttribute('role', 'option'); - - this.iconDiv_ = cr.doc.createElement('div'); - this.iconDiv_.className = 'volume-icon'; - this.appendChild(this.iconDiv_); - - this.label_ = cr.doc.createElement('div'); - this.label_.className = 'root-label'; - this.appendChild(this.label_); - - cr.defineProperty(this, 'lead', cr.PropertyKind.BOOL_ATTR); - cr.defineProperty(this, 'selected', cr.PropertyKind.BOOL_ATTR); -}; - -/** - * Associate a path with this item. - * @param {NavigationModelItem} modelItem NavigationModelItem of this item. - * @param {string=} opt_deviceType The type of the device. Available iff the - * path represents removable storage. - */ -NavigationListItem.prototype.setModelItem = - function(modelItem, opt_deviceType) { - if (this.modelItem_) - console.warn('NavigationListItem.setModelItem should be called only once.'); - - this.modelItem_ = modelItem; - - var rootType = PathUtil.getRootType(modelItem.path); - this.iconDiv_.setAttribute('volume-type-icon', rootType); - if (opt_deviceType) { - this.iconDiv_.setAttribute('volume-subtype', opt_deviceType); - } - - this.label_.textContent = modelItem.label; - - if (rootType === RootType.ARCHIVE || rootType === RootType.REMOVABLE) { - this.eject_ = cr.doc.createElement('div'); - // Block other mouse handlers. - this.eject_.addEventListener( - 'mouseup', function(event) { event.stopPropagation() }); - this.eject_.addEventListener( - 'mousedown', function(event) { event.stopPropagation() }); - - this.eject_.className = 'root-eject'; - this.eject_.addEventListener('click', function(event) { - event.stopPropagation(); - cr.dispatchSimpleEvent(this, 'eject'); - }.bind(this)); - - this.appendChild(this.eject_); - } -}; - -/** - * Associate a context menu with this item. - * @param {cr.ui.Menu} menu Menu this item. - */ -NavigationListItem.prototype.maybeSetContextMenu = function(menu) { - if (!this.modelItem_.path) { - console.error('NavigationListItem.maybeSetContextMenu must be called ' + - 'after setModelItem().'); - return; - } - - var isRoot = PathUtil.isRootPath(this.modelItem_.path); - var rootType = PathUtil.getRootType(this.modelItem_.path); - // The context menu is shown on the following items: - // - Removable and Archive volumes - // - Folder shortcuts - if (!isRoot || - (rootType != RootType.DRIVE && rootType != RootType.DOWNLOADS)) - cr.ui.contextMenuHandler.setContextMenu(this, menu); -}; - -/** - * A navigation list. - * @constructor - * @extends {cr.ui.List} - */ -function NavigationList() { -} - -/** - * NavigationList inherits cr.ui.List. - */ -NavigationList.prototype = { - __proto__: cr.ui.List.prototype, - - set dataModel(dataModel) { - if (!this.onListContentChangedBound_) - this.onListContentChangedBound_ = this.onListContentChanged_.bind(this); - - if (this.dataModel_) { - this.dataModel_.removeEventListener( - 'change', this.onListContentChangedBound_); - this.dataModel_.removeEventListener( - 'permuted', this.onListContentChangedBound_); - } - - var parentSetter = cr.ui.List.prototype.__lookupSetter__('dataModel'); - parentSetter.call(this, dataModel); - - // This must be placed after the parent method is called, in order to make - // it sure that the list was changed. - dataModel.addEventListener('change', this.onListContentChangedBound_); - dataModel.addEventListener('permuted', this.onListContentChangedBound_); - }, - - get dataModel() { - return this.dataModel_; - }, - - // TODO(yoshiki): Add a setter of 'directoryModel'. -}; - -/** - * @param {HTMLElement} el Element to be DirectoryItem. - * @param {VolumeManagerWrapper} volumeManager The VolumeManager of the system. - * @param {DirectoryModel} directoryModel Current DirectoryModel. - * folders. - */ -NavigationList.decorate = function(el, volumeManager, directoryModel) { - el.__proto__ = NavigationList.prototype; - el.decorate(volumeManager, directoryModel); -}; - -/** - * @param {VolumeManagerWrapper} volumeManager The VolumeManager of the system. - * @param {DirectoryModel} directoryModel Current DirectoryModel. - */ -NavigationList.prototype.decorate = function(volumeManager, directoryModel) { - cr.ui.List.decorate(this); - this.__proto__ = NavigationList.prototype; - - this.directoryModel_ = directoryModel; - this.volumeManager_ = volumeManager; - this.selectionModel = new cr.ui.ListSingleSelectionModel(); - - this.directoryModel_.addEventListener('directory-changed', - this.onCurrentDirectoryChanged_.bind(this)); - this.selectionModel.addEventListener( - 'change', this.onSelectionChange_.bind(this)); - this.selectionModel.addEventListener( - 'beforeChange', this.onBeforeSelectionChange_.bind(this)); - - this.scrollBar_ = new ScrollBar(); - this.scrollBar_.initialize(this.parentNode, this); - - // Overriding default role 'list' set by cr.ui.List.decorate() to 'listbox' - // role for better accessibility on ChromeOS. - this.setAttribute('role', 'listbox'); - - var self = this; - this.itemConstructor = function(modelItem) { - return self.renderRoot_(modelItem); - }; -}; - -/** - * This overrides cr.ui.List.measureItem(). - * In the method, a temporary element is added/removed from the list, and we - * need to omit animations for such temporary items. - * - * @param {ListItem=} opt_item The list item to be measured. - * @return {{height: number, marginTop: number, marginBottom:number, - * width: number, marginLeft: number, marginRight:number}} Size. - * @override - */ -NavigationList.prototype.measureItem = function(opt_item) { - this.measuringTemporaryItemNow_ = true; - var result = cr.ui.List.prototype.measureItem.call(this, opt_item); - this.measuringTemporaryItemNow_ = false; - return result; -}; - -/** - * Creates an element of a navigation list. This method is called from - * cr.ui.List internally. - * - * @param {NavigationModelItem} modelItem NavigationModelItem to be rendered. - * @return {NavigationListItem} Rendered element. - * @private - */ -NavigationList.prototype.renderRoot_ = function(modelItem) { - var item = new NavigationListItem(); - var volumeInfo = - PathUtil.isRootPath(modelItem.path) && - this.volumeManager_.getVolumeInfo(modelItem.path); - item.setModelItem(modelItem, volumeInfo && volumeInfo.deviceType); - - var handleClick = function() { - if (item.selected && - modelItem.path !== this.directoryModel_.getCurrentDirPath()) { - metrics.recordUserAction('FolderShortcut.Navigate'); - this.changeDirectory_(modelItem); - } - }.bind(this); - item.addEventListener('click', handleClick); - - var handleEject = function() { - var unmountCommand = cr.doc.querySelector('command#unmount'); - // Let's make sure 'canExecute' state of the command is properly set for - // the root before executing it. - unmountCommand.canExecuteChange(item); - unmountCommand.execute(item); - }; - item.addEventListener('eject', handleEject); - - if (this.contextMenu_) - item.maybeSetContextMenu(this.contextMenu_); - - return item; -}; - -/** - * Changes the current directory to the given path. - * If the given path is not found, a 'shortcut-target-not-found' event is - * fired. - * - * @param {NavigationModelItem} modelItem Directory to be chagned to. - * @private - */ -NavigationList.prototype.changeDirectory_ = function(modelItem) { - var onErrorCallback = function(error) { - if (error.code === FileError.NOT_FOUND_ERR) - this.dataModel.onItemNotFoundError(modelItem); - }.bind(this); - - this.directoryModel_.changeDirectory(modelItem.path, onErrorCallback); -}; - -/** - * Sets a context menu. Context menu is enabled only on archive and removable - * volumes as of now. - * - * @param {cr.ui.Menu} menu Context menu. - */ -NavigationList.prototype.setContextMenu = function(menu) { - this.contextMenu_ = menu; - - for (var i = 0; i < this.dataModel.length; i++) { - this.getListItemByIndex(i).maybeSetContextMenu(this.contextMenu_); - } -}; - -/** - * Selects the n-th item from the list. - * - * @param {number} index Item index. - * @return {boolean} True for success, otherwise false. - */ -NavigationList.prototype.selectByIndex = function(index) { - if (index < 0 || index > this.dataModel.length - 1) - return false; - - var newModelItem = this.dataModel.item(index); - var newPath = newModelItem.path; - if (!newPath) - return false; - - // Prevents double-moving to the current directory. - // eg. When user clicks the item, changing directory has already been done in - // click handler. - var entry = this.directoryModel_.getCurrentDirEntry(); - if (entry && entry.fullPath == newPath) - return false; - - metrics.recordUserAction('FolderShortcut.Navigate'); - this.changeDirectory_(newModelItem); - return true; -}; - -/** - * Handler before root item change. - * @param {Event} event The event. - * @private - */ -NavigationList.prototype.onBeforeSelectionChange_ = function(event) { - if (event.changes.length == 1 && !event.changes[0].selected) - event.preventDefault(); -}; - -/** - * Handler for root item being clicked. - * @param {Event} event The event. - * @private - */ -NavigationList.prototype.onSelectionChange_ = function(event) { - // This handler is invoked even when the navigation list itself changes the - // selection. In such case, we shouldn't handle the event. - if (this.dontHandleSelectionEvent_) - return; - - this.selectByIndex(this.selectionModel.selectedIndex); -}; - -/** - * Invoked when the current directory is changed. - * @param {Event} event The event. - * @private - */ -NavigationList.prototype.onCurrentDirectoryChanged_ = function(event) { - this.selectBestMatchItem_(); -}; - -/** - * Invoked when the content in the data model is changed. - * @param {Event} event The event. - * @private - */ -NavigationList.prototype.onListContentChanged_ = function(event) { - this.selectBestMatchItem_(); -}; - -/** - * Synchronizes the volume list selection with the current directory, after - * it is changed outside of the volume list. - * @private - */ -NavigationList.prototype.selectBestMatchItem_ = function() { - var entry = this.directoryModel_.getCurrentDirEntry(); - var path = entry && entry.fullPath; - if (!path) - return; - - // (1) Select the nearest parent directory (including the shortcut folders). - var bestMatchIndex = -1; - var bestMatchSubStringLen = 0; - for (var i = 0; i < this.dataModel.length; i++) { - var itemPath = this.dataModel.item(i).path; - if (path.indexOf(itemPath) == 0) { - if (bestMatchSubStringLen < itemPath.length) { - bestMatchIndex = i; - bestMatchSubStringLen = itemPath.length; - } - } - } - if (bestMatchIndex != -1) { - // Not to invoke the handler of this instance, sets the guard. - this.dontHandleSelectionEvent_ = true; - this.selectionModel.selectedIndex = bestMatchIndex; - this.dontHandleSelectionEvent_ = false; - return; - } - - // (2) Selects the volume of the current directory. - var newRootPath = PathUtil.getRootPath(path); - for (var i = 0; i < this.dataModel.length; i++) { - var itemPath = this.dataModel.item(i).path; - if (PathUtil.getRootPath(itemPath) == newRootPath) { - // Not to invoke the handler of this instance, sets the guard. - this.dontHandleSelectionEvent_ = true; - this.selectionModel.selectedIndex = i; - this.dontHandleSelectionEvent_ = false; - return; - } - } -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/preview_panel.js b/chromium/chrome/browser/resources/file_manager/foreground/js/ui/preview_panel.js deleted file mode 100644 index a8d0db482df..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/preview_panel.js +++ /dev/null @@ -1,518 +0,0 @@ -// Copyright (c) 2013 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. - -'use strict'; - -/** - * PreviewPanel UI class. - * @param {HTMLElement} element DOM Element of preview panel. - * @param {PreviewPanel.VisibilityType} visibilityType Initial value of the - * visibility type. - * @param {MetadataCache} metadataCache Metadata cache. - * @param {VolumeManagerWrapper} volumeManager Volume manager. - * @constructor - * @extends {cr.EventTarget} - */ -var PreviewPanel = function(element, - visibilityType, - metadataCache, - volumeManager) { - /** - * The cached height of preview panel. - * @type {number} - * @private - */ - this.height_ = 0; - - /** - * Visibility type of the preview panel. - * @type {PreviewPanel.VisiblityType} - * @private - */ - this.visibilityType_ = visibilityType; - - /** - * Current entry to be displayed. - * @type {Entry} - * @private - */ - this.currentEntry_ = null; - - /** - * Dom element of the preview panel. - * @type {HTMLElement} - * @private - */ - this.element_ = element; - - /** - * @type {BreadcrumbsController} - */ - this.breadcrumbs = new BreadcrumbsController( - element.querySelector('#search-breadcrumbs'), - metadataCache, - volumeManager); - - /** - * @type {PreviewPanel.Thumbnails} - */ - this.thumbnails = new PreviewPanel.Thumbnails( - element.querySelector('.preview-thumbnails'), metadataCache); - - /** - * @type {HTMLElement} - * @private - */ - this.summaryElement_ = element.querySelector('.preview-summary'); - - /** - * @type {PreviewPanel.CalculatingSizeLabel} - * @private - */ - this.calculatingSizeLabel_ = new PreviewPanel.CalculatingSizeLabel( - this.summaryElement_.querySelector('.calculating-size')); - - /** - * @type {HTMLElement} - * @private - */ - this.previewText_ = element.querySelector('.preview-text'); - - /** - * FileSelection to be displayed. - * @type {FileSelection} - * @private - */ - this.selection_ = {entries: [], computeBytes: function() {}}; - - /** - * Sequence value that is incremented by every selection update and is used to - * check if the callback is up to date or not. - * @type {number} - * @private - */ - this.sequence_ = 0; - - /** - * @type {VolumeManager} - * @private - */ - this.volumeManager_ = volumeManager; - - cr.EventTarget.call(this); -}; - -/** - * Name of PreviewPanels's event. - * @enum {string} - * @const - */ -PreviewPanel.Event = Object.freeze({ - // Event to be triggered at the end of visibility change. - VISIBILITY_CHANGE: 'visibilityChange' -}); - -/** - * Visibility type of the preview panel. - */ -PreviewPanel.VisibilityType = Object.freeze({ - // Preview panel always shows. - ALWAYS_VISIBLE: 'alwaysVisible', - // Preview panel shows when the selection property are set. - AUTO: 'auto', - // Preview panel does not show. - ALWAYS_HIDDEN: 'alwaysHidden' -}); - -/** - * @private - */ -PreviewPanel.Visibility_ = Object.freeze({ - VISIBLE: 'visible', - HIDING: 'hiding', - HIDDEN: 'hidden' -}); - -PreviewPanel.prototype = { - __proto__: cr.EventTarget.prototype, - - /** - * Setter for the current entry. - * @param {Entry} entry New entry. - */ - set currentEntry(entry) { - if (util.isSameEntry(this.currentEntry_, entry)) - return; - this.currentEntry_ = entry; - this.updateVisibility_(); - this.updatePreviewArea_(); - }, - - /** - * Setter for the visibility type. - * @param {PreviewPanel.VisibilityType} visibilityType New value of visibility - * type. - */ - set visibilityType(visibilityType) { - this.visibilityType_ = visibilityType; - this.updateVisibility_(); - }, - - get visible() { - return this.element_.getAttribute('visibility') == - PreviewPanel.Visibility_.VISIBLE; - }, - - /** - * Obtains the height of preview panel. - * @return {number} Height of preview panel. - */ - get height() { - this.height_ = this.height_ || this.element_.clientHeight; - return this.height_; - } -}; - -/** - * Initializes the element. - */ -PreviewPanel.prototype.initialize = function() { - this.element_.addEventListener('webkitTransitionEnd', - this.onTransitionEnd_.bind(this)); - this.updatePreviewArea_(); - this.updateVisibility_(); -}; - -/** - * Apply the selection and update the view of the preview panel. - * @param {FileSelection} selection Selection to be applied. - */ -PreviewPanel.prototype.setSelection = function(selection) { - this.sequence_++; - this.selection_ = selection; - this.updateVisibility_(); - // If the previw panel is hiding, does not update the current view. - if (this.visible) - this.updatePreviewArea_(); -}; - -/** - * Update the visibility of the preview panel. - * @private - */ -PreviewPanel.prototype.updateVisibility_ = function() { - // Get the new visibility value. - var visibility = this.element_.getAttribute('visibility'); - var newVisible = null; - switch (this.visibilityType_) { - case PreviewPanel.VisibilityType.ALWAYS_VISIBLE: - newVisible = true; - break; - case PreviewPanel.VisibilityType.AUTO: - newVisible = - this.selection_.entries.length !== 0 || - (this.currentEntry_ && - !this.volumeManager_.getLocationInfo( - this.currentEntry_).isRootEntry); - break; - case PreviewPanel.VisibilityType.ALWAYS_HIDDEN: - newVisible = false; - break; - default: - console.error('Invalid visibilityType.'); - return; - } - - // If the visibility has been already the new value, just return. - if ((visibility == PreviewPanel.Visibility_.VISIBLE && newVisible) || - (visibility == PreviewPanel.Visibility_.HIDDEN && !newVisible)) - return; - - // Set the new visibility value. - if (newVisible) { - this.element_.setAttribute('visibility', PreviewPanel.Visibility_.VISIBLE); - cr.dispatchSimpleEvent(this, PreviewPanel.Event.VISIBILITY_CHANGE); - } else { - this.element_.setAttribute('visibility', PreviewPanel.Visibility_.HIDING); - } -}; - -/** - * Update the text in the preview panel. - * - * @param {boolean} breadCrumbsVisible Whether the bread crumbs is visible or - * not. - * @private - */ -PreviewPanel.prototype.updatePreviewArea_ = function(breadCrumbsVisible) { - var selection = this.selection_; - - // Update thumbnails. - this.thumbnails.selection = selection.totalCount !== 0 ? - selection : {entries: [this.currentEntry_]}; - - // Check if the breadcrumb list should show instead on the preview text. - var entry; - if (this.selection_.totalCount == 1) - entry = this.selection_.entries[0]; - else if (this.selection_.totalCount == 0) - entry = this.currentEntry_; - - if (entry) { - this.breadcrumbs.show(entry); - this.calculatingSizeLabel_.hidden = true; - this.previewText_.textContent = ''; - return; - } - this.breadcrumbs.hide(); - - // Obtains the preview text. - var text; - if (selection.directoryCount == 0) - text = strf('MANY_FILES_SELECTED', selection.fileCount); - else if (selection.fileCount == 0) - text = strf('MANY_DIRECTORIES_SELECTED', selection.directoryCount); - else - text = strf('MANY_ENTRIES_SELECTED', selection.totalCount); - - // Obtains the size of files. - this.calculatingSizeLabel_.hidden = selection.bytesKnown; - if (selection.bytesKnown && selection.showBytes) - text += ', ' + util.bytesToString(selection.bytes); - - // Set the preview text to the element. - this.previewText_.textContent = text; - - // Request the byte calculation if needed. - if (!selection.bytesKnown) { - this.selection_.computeBytes(function(sequence) { - // Selection has been already updated. - if (this.sequence_ != sequence) - return; - this.updatePreviewArea_(); - }.bind(this, this.sequence_)); - } -}; - -/** - * Event handler to be called at the end of hiding transition. - * @param {Event} event The webkitTransitionEnd event. - * @private - */ -PreviewPanel.prototype.onTransitionEnd_ = function(event) { - if (event.target != this.element_ || event.propertyName != 'opacity') - return; - var visibility = this.element_.getAttribute('visibility'); - if (visibility != PreviewPanel.Visibility_.HIDING) - return; - this.element_.setAttribute('visibility', PreviewPanel.Visibility_.HIDDEN); - cr.dispatchSimpleEvent(this, PreviewPanel.Event.VISIBILITY_CHANGE); -}; - -/** - * Animating label that is shown during the bytes of selection entries is being - * calculated. - * - * This label shows dots and varying the number of dots every - * CalculatingSizeLabel.PERIOD milliseconds. - * @param {HTMLElement} element DOM element of the label. - * @constructor - */ -PreviewPanel.CalculatingSizeLabel = function(element) { - this.element_ = element; - this.count_ = 0; - this.intervalID_ = null; - Object.seal(this); -}; - -/** - * Time period in milliseconds. - * @const {number} - */ -PreviewPanel.CalculatingSizeLabel.PERIOD = 500; - -PreviewPanel.CalculatingSizeLabel.prototype = { - /** - * Set visibility of the label. - * When it is displayed, the text is animated. - * @param {boolean} hidden Whether to hide the label or not. - */ - set hidden(hidden) { - this.element_.hidden = hidden; - if (!hidden) { - if (this.intervalID_ != null) - return; - this.count_ = 2; - this.intervalID_ = - setInterval(this.onStep_.bind(this), - PreviewPanel.CalculatingSizeLabel.PERIOD); - this.onStep_(); - } else { - if (this.intervalID_ == null) - return; - clearInterval(this.intervalID_); - this.intervalID_ = null; - } - } -}; - -/** - * Increments the counter and updates the number of dots. - * @private - */ -PreviewPanel.CalculatingSizeLabel.prototype.onStep_ = function() { - var text = str('CALCULATING_SIZE'); - for (var i = 0; i < ~~(this.count_ / 2) % 4; i++) { - text += '.'; - } - this.element_.textContent = text; - this.count_++; -}; - -/** - * Thumbnails on the preview panel. - * - * @param {HTMLElement} element DOM Element of thumbnail container. - * @param {MetadataCache} metadataCache MetadataCache. - * @constructor - */ -PreviewPanel.Thumbnails = function(element, metadataCache) { - this.element_ = element; - this.metadataCache_ = metadataCache; - this.sequence_ = 0; - Object.seal(this); -}; - -/** - * Maximum number of thumbnails. - * @const {number} - */ -PreviewPanel.Thumbnails.MAX_THUMBNAIL_COUNT = 4; - -/** - * Edge length of the thumbnail square. - * @const {number} - */ -PreviewPanel.Thumbnails.THUMBNAIL_SIZE = 35; - -/** - * Longer edge length of zoomed thumbnail rectangle. - * @const {number} - */ -PreviewPanel.Thumbnails.ZOOMED_THUMBNAIL_SIZE = 200; - -PreviewPanel.Thumbnails.prototype = { - /** - * Sets entries to be displayed in the view. - * @param {Array.<Entry>} value Entries. - */ - set selection(value) { - this.sequence_++; - this.loadThumbnails_(value); - } -}; - -/** - * Loads thumbnail images. - * @param {FileSelection} selection Selection containing entries that are - * sources of images. - * @private - */ -PreviewPanel.Thumbnails.prototype.loadThumbnails_ = function(selection) { - var entries = selection.entries; - this.element_.classList.remove('has-zoom'); - this.element_.innerText = ''; - var clickHandler = selection.tasks && - selection.tasks.executeDefault.bind(selection.tasks); - var length = Math.min(entries.length, - PreviewPanel.Thumbnails.MAX_THUMBNAIL_COUNT); - for (var i = 0; i < length; i++) { - // Create a box. - var box = this.element_.ownerDocument.createElement('div'); - box.style.zIndex = PreviewPanel.Thumbnails.MAX_THUMBNAIL_COUNT + 1 - i; - - // Load the image. - if (entries[i]) { - FileGrid.decorateThumbnailBox(box, - entries[i], - this.metadataCache_, - ThumbnailLoader.FillMode.FILL, - FileGrid.ThumbnailQuality.LOW, - i == 0 && length == 1 && - this.setZoomedImage_.bind(this)); - } - - // Register the click handler. - if (clickHandler) - box.addEventListener('click', clickHandler); - - // Append - this.element_.appendChild(box); - } -}; - -/** - * Create the zoomed version of image and set it to the DOM element to show the - * zoomed image. - * - * @param {Image} image Image to be source of the zoomed image. - * @param {transform} transform Transformation to be applied to the image. - * @private - */ -PreviewPanel.Thumbnails.prototype.setZoomedImage_ = function(image, transform) { - if (!image) - return; - var width = image.width || 0; - var height = image.height || 0; - if (width == 0 || - height == 0 || - (width < PreviewPanel.Thumbnails.THUMBNAIL_SIZE * 2 && - height < PreviewPanel.Thumbnails.THUMBNAIL_SIZE * 2)) - return; - - var scale = Math.min(1, - PreviewPanel.Thumbnails.ZOOMED_THUMBNAIL_SIZE / - Math.max(width, height)); - var imageWidth = ~~(width * scale); - var imageHeight = ~~(height * scale); - var zoomedImage = this.element_.ownerDocument.createElement('img'); - - if (scale < 0.3) { - // Scaling large images kills animation. Downscale it in advance. - // Canvas scales images with liner interpolation. Make a larger - // image (but small enough to not kill animation) and let IMAGE - // scale it smoothly. - var INTERMEDIATE_SCALE = 3; - var canvas = this.element_.ownerDocument.createElement('canvas'); - canvas.width = imageWidth * INTERMEDIATE_SCALE; - canvas.height = imageHeight * INTERMEDIATE_SCALE; - var ctx = canvas.getContext('2d'); - ctx.drawImage(image, 0, 0, canvas.width, canvas.height); - // Using bigger than default compression reduces image size by - // several times. Quality degradation compensated by greater resolution. - zoomedImage.src = canvas.toDataURL('image/jpeg', 0.6); - } else { - zoomedImage.src = image.src; - } - - var boxWidth = Math.max(PreviewPanel.Thumbnails.THUMBNAIL_SIZE, imageWidth); - var boxHeight = Math.max(PreviewPanel.Thumbnails.THUMBNAIL_SIZE, imageHeight); - if (transform && transform.rotate90 % 2 == 1) { - var t = boxWidth; - boxWidth = boxHeight; - boxHeight = t; - } - - util.applyTransform(zoomedImage, transform); - - var zoomedBox = this.element_.ownerDocument.createElement('div'); - zoomedBox.className = 'popup'; - zoomedBox.style.width = boxWidth + 'px'; - zoomedBox.style.height = boxHeight + 'px'; - zoomedBox.appendChild(zoomedImage); - - this.element_.appendChild(zoomedBox); - this.element_.classList.add('has-zoom'); - return; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/progress_center_panel.js b/chromium/chrome/browser/resources/file_manager/foreground/js/ui/progress_center_panel.js deleted file mode 100644 index bcfe6d8e747..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/progress_center_panel.js +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * Progress center panel. - * - * @param {HTMLElement} element DOM Element of the process center panel. - * @constructor - */ -var ProgressCenterPanel = function(element) { - /** - * Root element of the progress center. - * @type {!HTMLElement} - * @private - */ - this.element_ = element; - - /** - * Open view containing multiple progress items. - * @type {!HTMLElement} - * @private - */ - this.openView_ = this.element_.querySelector('#progress-center-open-view'); - - /** - * Close view that is a summarized progress item. - * @type {!HTMLElement} - * @private - */ - this.closeView_ = this.element_.querySelector('#progress-center-close-view'); - - /** - * Toggle animation rule of the progress center. - * @type {!CSSKeyFrameRule} - * @private - */ - this.toggleAnimation_ = ProgressCenterPanel.getToggleAnimation_( - element.ownerDocument); - - /** - * Reset is requested but it is pending until the transition of progress bar - * is complete. - * @type {boolean} - * @private - */ - this.resetRequested_ = false; - - /** - * Callback to becalled with the ID of the progress item when the cancel - * button is clicked. - */ - this.cancelCallback = null; - - Object.seal(this); - - // Register event handlers. - element.addEventListener('click', this.onClick_.bind(this)); - element.addEventListener( - 'webkitAnimationEnd', this.onToggleAnimationEnd_.bind(this)); - element.addEventListener( - 'webkitTransitionEnd', this.onItemTransitionEnd_.bind(this)); -}; - -/** - * Updates attributes of the item element. - * @param {!HTMLElement} element Element to be updated. - * @param {!ProgressCenterItem} item Progress center item. - * @private - */ -ProgressCenterPanel.updateItemElement_ = function(element, item) { - // Sets element attributes. - element.setAttribute('data-progress-id', item.id); - element.classList.toggle('error', item.state === ProgressItemState.ERROR); - element.classList.toggle('cancelable', item.cancelable); - - // Only when the previousWidthRate is not NaN (when style width is already - // set) and the progress rate increases, we use transition animation. - var previousWidthRate = - parseInt(element.querySelector('.progress-track').style.width); - var targetWidthRate = item.progressRateInPercent; - var animation = !isNaN(previousWidthRate) && - previousWidthRate < targetWidthRate; - if (item.state === ProgressItemState.COMPLETED && animation) { - // The attribute pre-complete means that the actual operation is already - // done but the UI transition of progress bar is not complete. - element.setAttribute('pre-complete', ''); - } else { - element.querySelector('label').textContent = item.message; - } - - // To commit the property change and to trigger the transition even if the - // change is done synchronously, assign the width value asynchronously. - var updateTrackWidth = function() { - var track = element.querySelector('.progress-track'); - track.classList.toggle('animated', animation); - track.style.width = targetWidthRate + '%'; - track.hidden = false; - }; - if (animation) - setTimeout(updateTrackWidth); - else - updateTrackWidth(); -}; - -/** - * Obtains the toggle animation keyframes rule from the document. - * @param {HTMLDocument} document Document containing the rule. - * @return {CSSKeyFrameRules} Animation rule. - * @private - */ -ProgressCenterPanel.getToggleAnimation_ = function(document) { - for (var i = 0; i < document.styleSheets.length; i++) { - var styleSheet = document.styleSheets[i]; - for (var j = 0; j < styleSheet.cssRules.length; j++) { - var rule = styleSheet.cssRules[j]; - if (rule.type === CSSRule.WEBKIT_KEYFRAMES_RULE && - rule.name === 'progress-center-toggle') { - return rule; - } - } - } - throw new Error('The progress-center-toggle rules is not found.'); -}; - -/** - * Updates an item to the progress center panel. - * @param {!ProgressCenterItem} item Item including new contents. - */ -ProgressCenterPanel.prototype.updateItem = function(item) { - // If reset is requested, force to reset. - if (this.resetRequested_) - this.reset(true); - - var itemElement = this.getItemElement_(item.id); - - // Check whether the item should be displayed or not by referring its state. - switch (item.state) { - // Should show the item. - case ProgressItemState.PROGRESSING: - case ProgressItemState.ERROR: - // If the item has not been added yet, create a new element and add it. - if (!itemElement) { - itemElement = this.createNewItemElement_(); - this.openView_.insertBefore(itemElement, this.openView_.firstNode); - } - - // Update the element by referring the item model. - ProgressCenterPanel.updateItemElement_(itemElement, item); - this.element_.hidden = false; - break; - - // Should not show the item. - case ProgressItemState.COMPLETED: - case ProgressItemState.CANCELED: - // If itemElement is not shown, just break. - if (!itemElement) - break; - - // If the item is complete state, once update it because it may turn to - // have the pre-complete attribute. - if (item.state === ProgressItemState.COMPLETED) - ProgressCenterPanel.updateItemElement_(itemElement, item); - - // If the item has the pre-complete attribute, keep showing it. Otherwise, - // just remove it. - if (item.state !== ProgressItemState.COMPLETED || - !itemElement.hasAttribute('pre-complete')) { - this.openView_.removeChild(itemElement); - } - break; - } -}; - -/** - * Updates close showing summarized item. - * @param {!ProgressCenterItem} summarizedItem Item to be displayed in the close - * view. - */ -ProgressCenterPanel.prototype.updateCloseView = function(summarizedItem) { - this.closeView_.classList.toggle('single', !summarizedItem.summarized); - ProgressCenterPanel.updateItemElement_(this.closeView_, summarizedItem); -}; - -/** - * Remove all the items. - * @param {boolean=} opt_force True if we force to reset and do not wait the - * transition of progress bar. False otherwise. False is default. - */ -ProgressCenterPanel.prototype.reset = function(opt_force) { - if (!opt_force && this.element_.querySelector('[pre-complete]')) { - this.resetRequested_ = true; - return; - } - - // Clear the flag. - this.resetRequested_ = false; - - // Clear the all compete item. - this.openView_.innerHTML = ''; - - // Clear track width of close view. - this.closeView_.querySelector('.progress-track').style.width = ''; - - // Hide the progress center. - this.element_.hidden = true; - this.closeView_.querySelector('.progress-track').hidden = true; - this.element_.classList.remove('opened'); -}; - -/** - * Gets an item element having the specified ID. - * @param {string} id progress item ID. - * @return {HTMLElement} Item element having the ID. - * @private - */ -ProgressCenterPanel.prototype.getItemElement_ = function(id) { - var query = 'li[data-progress-id="' + id + '"]'; - return this.openView_.querySelector(query); -}; - -/** - * Creates an item element. - * @return {HTMLElement} Created item element. - * @private - */ -ProgressCenterPanel.prototype.createNewItemElement_ = function() { - var label = this.element_.ownerDocument.createElement('label'); - label.className = 'label'; - - var progressBarIndicator = this.element_.ownerDocument.createElement('div'); - progressBarIndicator.className = 'progress-track'; - - var progressBar = this.element_.ownerDocument.createElement('div'); - progressBar.className = 'progress-bar'; - progressBar.appendChild(progressBarIndicator); - - var cancelButton = this.element_.ownerDocument.createElement('button'); - cancelButton.className = 'cancel'; - cancelButton.setAttribute('tabindex', '-1'); - - var progressFrame = this.element_.ownerDocument.createElement('div'); - progressFrame.className = 'progress-frame'; - progressFrame.appendChild(progressBar); - progressFrame.appendChild(cancelButton); - - var itemElement = this.element_.ownerDocument.createElement('li'); - itemElement.appendChild(label); - itemElement.appendChild(progressFrame); - - return itemElement; -}; - -/** - * Handles the animation end event of the progress center. - * @param {Event} event Animation end event. - * @private - */ -ProgressCenterPanel.prototype.onToggleAnimationEnd_ = function(event) { - // Transition end of the root element's height. - if (event.target === this.element_ && - event.animationName === 'progress-center-toggle') { - this.element_.classList.remove('animated'); - return; - } -}; - -/** - * Handles the transition end event of items. - * @param {Event} event Transition end event. - * @private - */ -ProgressCenterPanel.prototype.onItemTransitionEnd_ = function(event) { - var itemElement = event.target.parentNode.parentNode.parentNode; - if (!itemElement.hasAttribute('pre-complete') || - event.propertyName !== 'width') - return; - if (itemElement !== this.closeView_) - this.openView_.removeChild(itemElement); - itemElement.removeAttribute('pre-complete'); - - if (this.resetRequested_) - this.reset(); -}; - -/** - * Handles the click event. - * @param {Event} event Click event. - * @private - */ -ProgressCenterPanel.prototype.onClick_ = function(event) { - // Toggle button. - if (event.target.classList.contains('toggle') && - (!this.closeView_.classList.contains('single') || - this.element_.classList.contains('opened'))) { - - // If the progress center has already animated, just return. - if (this.element_.classList.contains('animated')) - return; - - // Obtains current and target height. - var currentHeight; - var targetHeight; - if (this.element_.classList.contains('opened')) { - currentHeight = this.openView_.getBoundingClientRect().height; - targetHeight = this.closeView_.getBoundingClientRect().height; - } else { - currentHeight = this.closeView_.getBoundingClientRect().height; - targetHeight = this.openView_.getBoundingClientRect().height; - } - - // Set styles for animation. - this.toggleAnimation_.cssRules[0].style.height = currentHeight + 'px'; - this.toggleAnimation_.cssRules[1].style.height = targetHeight + 'px'; - this.element_.classList.add('animated'); - this.element_.classList.toggle('opened'); - return; - } - - // Cancel button. - if (this.cancelCallback) { - var id = event.target.classList.contains('toggle') ? - this.closeView_.getAttribute('data-progress-id') : - event.target.parentNode.parentNode.getAttribute('data-progress-id'); - this.cancelCallback(id); - } -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/search_box.js b/chromium/chrome/browser/resources/file_manager/foreground/js/ui/search_box.js deleted file mode 100644 index 30a7ea73faf..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/ui/search_box.js +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2013 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. - -'use strict'; - -/** - * Search box. - * - * @param {element} element Root element of the search box. - * @constructor - */ -function SearchBox(element) { - /** - * Autocomplete List. - * @type {AutocompleteList} - */ - this.autocompleteList = new SearchBox.AutocompleteList(element.ownerDocument); - - /** - * Root element of the search box. - * @type {HTMLElement} - */ - this.element = element; - - /** - * Text input of the search box. - * @type {HTMLElement} - */ - this.inputElement = element.querySelector('input'); - - /** - * Clear button of the search box. - * @type {HTMLElement} - */ - this.clearButton = element.querySelector('.clear'); - - /** - * Text measure. - * @type {TextMeasure} - * @private - */ - this.textMeasure_ = new TextMeasure(this.inputElement); - - Object.freeze(this); - - // Register events. - this.inputElement.addEventListener('input', this.updateStyles_.bind(this)); - this.inputElement.addEventListener('keydown', this.onKeyDown_.bind(this)); - this.inputElement.addEventListener('focus', this.onFocus_.bind(this)); - this.inputElement.addEventListener('blur', this.onBlur_.bind(this)); - element.querySelector('.icon').addEventListener( - 'click', this.onIconClick_.bind(this)); - element.parentNode.appendChild(this.autocompleteList); -} - -/** - * Autocomplete list for search box. - * @param {HTMLDocument} document Document. - * @constructor - */ -SearchBox.AutocompleteList = function(document) { - var self = cr.ui.AutocompleteList.call(this); - self.__proto__ = SearchBox.AutocompleteList.prototype; - self.id = 'autocomplete-list'; - self.autoExpands = true; - self.itemConstructor = SearchBox.AutocompleteListItem_.bind(null, document); - self.addEventListener('mouseover', self.onMouseOver_.bind(self)); - return self; -}; - -SearchBox.AutocompleteList.prototype = { - __proto__: cr.ui.AutocompleteList.prototype -}; - -/** - * Do nothing when a suggestion is selected. - * @override - */ -SearchBox.AutocompleteList.prototype.handleSelectedSuggestion = function() {}; - -/** - * Change the selection by a mouse over instead of just changing the - * color of moused over element with :hover in CSS. Here's why: - * - * 1) The user selects an item A with up/down keys (item A is highlighted) - * 2) Then the user moves the cursor to another item B - * - * If we just change the color of moused over element (item B), both - * the item A and B are highlighted. This is bad. We should change the - * selection so only the item B is highlighted. - * - * @param {Event} event Event. - * @private - */ -SearchBox.AutocompleteList.prototype.onMouseOver_ = function(event) { - if (event.target.itemInfo) - this.selectedItem = event.target.itemInfo; -}; - -/** - * ListItem element for autocomple. - * - * @param {HTMLDocument} document Document. - * @param {Object} item An object representing a suggestion. - * @constructor - * @private - */ -SearchBox.AutocompleteListItem_ = function(document, item) { - var li = new cr.ui.ListItem(); - li.itemInfo = item; - - var icon = document.createElement('div'); - icon.className = 'detail-icon'; - - var text = document.createElement('div'); - text.className = 'detail-text'; - - if (item.isHeaderItem) { - icon.setAttribute('search-icon', ''); - text.innerHTML = - strf('SEARCH_DRIVE_HTML', util.htmlEscape(item.searchQuery)); - } else { - var iconType = FileType.getIcon(item.entry); - icon.setAttribute('file-type-icon', iconType); - // highlightedBaseName is a piece of HTML with meta characters properly - // escaped. See the comment at fileBrowserPrivate.searchDriveMetadata(). - text.innerHTML = item.highlightedBaseName; - } - li.appendChild(icon); - li.appendChild(text); - return li; -}; - -/** - * Updates the size related style. - */ -SearchBox.prototype.updateSizeRelatedStyle = function() { - // Hide the search box if there is not enough space. - this.element.classList.toggle( - 'too-short', - this.element.clientWidth < 100); -}; - -/** - * Clears the search query. - */ -SearchBox.prototype.clear = function() { - this.inputElement.value = ''; - this.updateStyles_(); -}; - -/** - * Handles a focus event of the search box. - * @private - */ -SearchBox.prototype.onFocus_ = function() { - this.element.classList.toggle('has-cursor', true); - this.inputElement.tabIndex = '99'; // See: go/filesapp-tabindex. - this.autocompleteList.attachToInput(this.inputElement); -}; - -/** - * Handles a blur event of the search box. - * @private - */ -SearchBox.prototype.onBlur_ = function() { - this.element.classList.toggle('has-cursor', false); - this.inputElement.tabIndex = '-1'; - this.autocompleteList.detach(); -}; - -/** - * Handles a keydown event of the search box. - * @private - */ -SearchBox.prototype.onKeyDown_ = function() { - // Handle only Esc key now. - if (event.keyCode != 27 || this.inputElement.value) - return; - this.inputElement.blur(); -}; - -/** - * Handles a click event of the search icon. - * @private - */ -SearchBox.prototype.onIconClick_ = function() { - this.inputElement.focus(); -}; - -/** - * Updates styles of the search box. - * @private - */ -SearchBox.prototype.updateStyles_ = function() { - this.element.classList.toggle('has-text', - !!this.inputElement.value); - var width = this.textMeasure_.getWidth(this.inputElement.value) + - 16 /* Extra space to allow leeway. */; - this.inputElement.style.width = width + 'px'; -}; diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/volume_manager_wrapper.js b/chromium/chrome/browser/resources/file_manager/foreground/js/volume_manager_wrapper.js deleted file mode 100644 index a9631dc92d9..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/volume_manager_wrapper.js +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright 2013 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. - -/** - * Thin wrapper for VolumeManager. This should be an interface proxy to talk - * to VolumeManager. This class also filters Drive related data/events if - * driveEnabled is set to false. - * - * @param {VolumeManagerWrapper.DriveEnabledStatus} driveEnabled DRIVE_ENABLED - * if drive should be available. DRIVE_DISABLED if drive related - * data/events should be hidden. - * @param {DOMWindow} opt_backgroundPage Window object of the background - * page. If this is specified, the class skips to get background page. - * TOOD(hirono): Let all clients of the class pass the background page and - * make the argument not optional. - * @constructor - * @extends {cr.EventTarget} - */ -function VolumeManagerWrapper(driveEnabled, opt_backgroundPage) { - cr.EventTarget.call(this); - - this.driveEnabled_ = driveEnabled; - this.volumeInfoList = new cr.ui.ArrayDataModel([]); - - this.volumeManager_ = null; - this.pendingTasks_ = []; - this.onEventBound_ = this.onEvent_.bind(this); - this.onVolumeInfoListUpdatedBound_ = - this.onVolumeInfoListUpdated_.bind(this); - - this.disposed_ = false; - - // Start initialize the VolumeManager. - var queue = new AsyncUtil.Queue(); - - if (opt_backgroundPage) { - this.backgroundPage_ = opt_backgroundPage; - } else { - queue.run(function(callNextStep) { - chrome.runtime.getBackgroundPage(function(backgroundPage) { - this.backgroundPage_ = backgroundPage; - callNextStep(); - }.bind(this)); - }.bind(this)); - } - - queue.run(function(callNextStep) { - this.backgroundPage_.VolumeManager.getInstance(function(volumeManager) { - this.onReady_(volumeManager); - callNextStep(); - }.bind(this)); - }.bind(this)); -} - -/** - * If the drive is enabled on the wrapper. - * @enum {boolean} - */ -VolumeManagerWrapper.DriveEnabledStatus = { - DRIVE_ENABLED: true, - DRIVE_DISABLED: false -}; - -/** - * Extends cr.EventTarget. - */ -VolumeManagerWrapper.prototype.__proto__ = cr.EventTarget.prototype; - -/** - * Called when the VolumeManager gets ready for post initialization. - * @param {VolumeManager} volumeManager The initialized VolumeManager instance. - * @private - */ -VolumeManagerWrapper.prototype.onReady_ = function(volumeManager) { - if (this.disposed_) - return; - - this.volumeManager_ = volumeManager; - - // Subscribe to VolumeManager. - this.volumeManager_.addEventListener( - 'drive-connection-changed', this.onEventBound_); - this.volumeManager_.addEventListener( - 'externally-unmounted', this.onEventBound_); - - // Cache volumeInfoList. - var volumeInfoList = []; - for (var i = 0; i < this.volumeManager_.volumeInfoList.length; i++) { - var volumeInfo = this.volumeManager_.volumeInfoList.item(i); - // TODO(hidehiko): Filter mounted volumes located on Drive File System. - if (!this.driveEnabled_ && volumeInfo.volumeType === util.VolumeType.DRIVE) - continue; - volumeInfoList.push(volumeInfo); - } - this.volumeInfoList.splice.apply( - this.volumeInfoList, - [0, this.volumeInfoList.length].concat(volumeInfoList)); - - // Subscribe to VolumeInfoList. - // In VolumeInfoList, we only use 'splice' event. - this.volumeManager_.volumeInfoList.addEventListener( - 'splice', this.onVolumeInfoListUpdatedBound_); - - // Run pending tasks. - var pendingTasks = this.pendingTasks_; - this.pendingTasks_ = null; - for (var i = 0; i < pendingTasks.length; i++) - pendingTasks[i](); -}; - -/** - * Disposes the instance. After the invocation of this method, any other - * method should not be called. - */ -VolumeManagerWrapper.prototype.dispose = function() { - this.disposed_ = true; - - if (!this.volumeManager_) - return; - this.volumeManager_.removeEventListener( - 'drive-connection-changed', this.onEventBound_); - this.volumeManager_.removeEventListener( - 'externally-unmounted', this.onEventBound_); - this.volumeManager_.volumeInfoList.removeEventListener( - 'splice', this.onVolumeInfoListUpdatedBound_); -}; - -/** - * Called on events sent from VolumeManager. This has responsibility to - * re-dispatch the event to the listeners. - * @param {Event} event Event object sent from VolumeManager. - * @private - */ -VolumeManagerWrapper.prototype.onEvent_ = function(event) { - if (!this.driveEnabled_) { - // If the drive is disabled, ignore all drive related events. - if (event.type === 'drive-connection-changed' || - (event.type === 'externally-unmounted' && - event.volumeInfo.volumeType === util.VolumeType.DRIVE)) - return; - } - - this.dispatchEvent(event); -}; - -/** - * Called on events of modifying VolumeInfoList. - * @param {Event} event Event object sent from VolumeInfoList. - * @private - */ -VolumeManagerWrapper.prototype.onVolumeInfoListUpdated_ = function(event) { - if (this.driveEnabled_) { - // Apply the splice as is. - this.volumeInfoList.splice.apply( - this.volumeInfoList, - [event.index, event.removed.length].concat(event.added)); - } else { - // Filters drive related volumes. - var index = event.index; - for (var i = 0; i < event.index; i++) { - if (this.volumeManager_.volumeInfoList.item(i).volumeType === - util.VolumeType.DRIVE) - index--; - } - - var numRemovedVolumes = 0; - for (var i = 0; i < event.removed.length; i++) { - if (event.removed[i].volumeType !== util.VolumeType.DRIVE) - numRemovedVolumes++; - } - - var addedVolumes = []; - for (var i = 0; i < event.added.length; i++) { - var volumeInfo = event.added[i]; - if (volumeInfo.volumeType !== util.VolumeType.DRIVE) - addedVolumes.push(volumeInfo); - } - - this.volumeInfoList.splice.apply( - this.volumeInfoList, - [index, numRemovedVolumes].concat(addedVolumes)); - } -}; - -/** - * Ensures the VolumeManager is initialized, and then invokes callback. - * If the VolumeManager is already initialized, callback will be called - * immediately. - * @param {function()} callback Called on initialization completion. - */ -VolumeManagerWrapper.prototype.ensureInitialized = function(callback) { - if (this.pendingTasks_) { - this.pendingTasks_.push(this.ensureInitialized.bind(this, callback)); - return; - } - - callback(); -}; - -/** - * @return {util.DriveConnectionType} Current drive connection state. - */ -VolumeManagerWrapper.prototype.getDriveConnectionState = function() { - if (!this.driveEnabled_ || !this.volumeManager_) { - return { - type: util.DriveConnectionType.OFFLINE, - reason: util.DriveConnectionReason.NO_SERVICE - }; - } - - return this.volumeManager_.getDriveConnectionState(); -}; - -/** - * @param {string} mountPath The path to mount location of the volume. - * @return {VolumeInfo} The VolumeInfo instance for the volume mounted at - * mountPath, or null if no volume is found - */ -VolumeManagerWrapper.prototype.getVolumeInfo = function(mountPath) { - return this.filterDisabledDriveVolume_( - this.volumeManager_ && this.volumeManager_.getVolumeInfo(mountPath)); -}; - -/** - * Obtains a volume information from a file entry URL. - * TODO(hirono): Check a file system to find a volume. - * - * @param {string} url URL of entry. - * @return {VolumeInfo} Volume info. - */ -VolumeManagerWrapper.prototype.getVolumeInfoByURL = function(url) { - return this.filterDisabledDriveVolume_( - this.volumeManager_ && this.volumeManager_.getVolumeInfoByURL(url)); -}; - -/** - * Obtains a volume infomration of the current profile. - * - * @param {util.VolumeType} volumeType Volume type. - * @return {VolumeInfo} Found volume info. - */ -VolumeManagerWrapper.prototype.getCurrentProfileVolumeInfo = - function(volumeType) { - return this.filterDisabledDriveVolume_( - this.volumeManager_ && - this.volumeManager_.getCurrentProfileVolumeInfo(volumeType)); -}; - -/** - * Obtains location information from an entry. - * - * @param {Entry} entry File or directory entry. - * @return {EntryLocation} Location information. - */ -VolumeManagerWrapper.prototype.getLocationInfo = function(entry) { - return this.volumeManager_ && this.volumeManager_.getLocationInfo(entry); -}; - -/** - * Requests to mount the archive file. - * @param {string} fileUrl The path to the archive file to be mounted. - * @param {function(string)} successCallback Called with mount path on success. - * @param {function(util.VolumeError)} errorCallback Called when an error - * occurs. - */ -VolumeManagerWrapper.prototype.mountArchive = function( - fileUrl, successCallback, errorCallback) { - if (this.pendingTasks_) { - this.pendingTasks_.push( - this.mountArchive.bind(this, fileUrl, successCallback, errorCallback)); - return; - } - - this.volumeManager_.mountArchive(fileUrl, successCallback, errorCallback); -}; - -/** - * Requests unmount the volume at mountPath. - * @param {string} mountPath The path to the mount location of the volume. - * @param {function(string)} successCallback Called with the mount path - * on success. - * @param {function(util.VolumeError)} errorCallback Called when an error - * occurs. - */ -VolumeManagerWrapper.prototype.unmount = function( - mountPath, successCallback, errorCallback) { - if (this.pendingTasks_) { - this.pendingTasks_.push( - this.unmount.bind(this, mountPath, successCallback, errorCallback)); - return; - } - - this.volumeManager_.unmount(mountPath, successCallback, errorCallback); -}; - -/** - * Resolves the absolute path to an entry instance. - * @param {string} path The path to be resolved. - * @param {function(Entry)} successCallback Called with the resolved entry - * on success. - * @param {function(FileError)} errorCallback Called with the error on error. - */ -VolumeManagerWrapper.prototype.resolveAbsolutePath = function( - path, successCallback, errorCallback) { - if (this.pendingTasks_) { - this.pendingTasks_.push(this.resolveAbsolutePath.bind( - this, path, successCallback, errorCallback)); - return; - } - - // If the drive is disabled, any resolving the path under drive should be - // failed. - if (!this.driveEnabled_ && PathUtil.isDriveBasedPath(path)) { - errorCallback(util.createFileError(FileError.NOT_FOUND_ERR)); - return; - } - - this.volumeManager_.resolveAbsolutePath(path, successCallback, errorCallback); -}; - -/** - * Filters volume info by referring driveEnabled. - * - * @param {VolumeInfo} volumeInfo Volume info. - * @return {VolumeInfo} Null if the drive is disabled and the given volume is - * drive. Otherwise just returns the volume. - * @private - */ -VolumeManagerWrapper.prototype.filterDisabledDriveVolume_ = - function(volumeInfo) { - var isDrive = volumeInfo && volumeInfo.volumeType === util.VolumeType.DRIVE; - return this.driveEnabled_ || !isDrive ? volumeInfo : null; -}; |