Commit f25d6c05 authored by rbpotter's avatar rbpotter Committed by Commit Bot

Print Preview Componentization: Destinations Dialog additions

Add the recent destinations list and search box, and enable selection
of printers using the dialog.

Bug: 773928
Cq-Include-Trybots: master.tryserver.chromium.linux:closure_compilation
Change-Id: I157461a6a2ec5223e88b97067a4ddc8933f08ea8
Reviewed-on: https://chromium-review.googlesource.com/885502
Commit-Queue: Rebekah Potter <rbpotter@chromium.org>
Reviewed-by: default avatarDemetrios Papadopoulos <dpapad@chromium.org>
Cr-Commit-Position: refs/heads/master@{#532939}
parent 7b49ae6d
......@@ -65,7 +65,9 @@
settings="[[settings]]"></print-preview-header>
<div id="settings-sections">
<print-preview-destination-settings destination="[[destination_]]"
destination-store="[[destinationStore_]]" user-info="[[userInfo_]]">
destination-store="[[destinationStore_]]"
recent-destinations="[[recentDestinations_]]"
user-info="[[userInfo_]]">
</print-preview-destination-settings>
<print-preview-pages-settings settings="{{settings}}"
document-info="[[documentInfo_]]"
......
......@@ -193,6 +193,14 @@
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
'../compiled_resources2.gyp:native_layer',
'../data/compiled_resources2.gyp:destination',
'print_preview_search_box',
],
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
{
'target_name': 'print_preview_search_box',
'dependencies': [
'<(DEPTH)/ui/webui/resources/cr_elements/cr_search_field/compiled_resources2.gyp:cr_search_field_behavior',
],
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
......
......@@ -8,6 +8,7 @@
<link rel="import" href="../data/destination_store.html">
<link rel="import" href="button_css.html">
<link rel="import" href="destination_list.html">
<link rel="import" href="print_preview_search_box.html">
<link rel="import" href="print_preview_shared_css.html">
<dom-module id="print-preview-destination-dialog">
......@@ -32,6 +33,7 @@
box-shadow: 0 4px 23px 5px rgba(0, 0, 0, 0.2),
0 2px 6px rgba(0, 0, 0, 0.15);
max-height: calc(100% - 40px);
width: 640px;
}
......@@ -57,14 +59,26 @@
width: 24px;
}
</style>
<dialog is="cr-dialog" id="dialog">
<dialog is="cr-dialog" id="dialog" on-cancel="onCloseOrCancel_"
on-close="onCloseOrCancel_">
<div slot="title">
<span>$i18n{destinationSearchTitle}</span>
</div>
<div slot="body" scrollable>
<print-preview-search-box id="searchBox"
label="$i18n{searchBoxPlaceholder}" search-query="{{searchQuery_}}">
</print-preview-search-box>
<print-preview-destination-list
destinations="[[recentDestinationList_]]"
search-query="[[searchQuery_]]"
title="$i18n{recentDestinationsTitle}"
on-destination-selected="onDestinationSelected_">
</print-preview-destination-list>
<print-preview-destination-list destinations="[[destinations_]]"
has-action-link=true loading-destinations="[[loadingDestinations_]]"
title="$i18n{printDestinationsTitle}">
has-action-link loading-destinations="[[loadingDestinations_]]"
search-query="[[searchQuery_]]"
title="$i18n{printDestinationsTitle}"
on-destination-selected="onDestinationSelected_">
</print-preview-destination-list>
</div>
<div slot="button-container">
......
......@@ -15,7 +15,7 @@ Polymer({
/** @type {!print_preview.UserInfo} */
userInfo: Object,
/** @private {Array<!print_preview.Destination>} */
/** @private {!Array<!print_preview.Destination>} */
destinations_: {
type: Array,
notify: true,
......@@ -27,6 +27,24 @@ Polymer({
type: Boolean,
value: false,
},
/** @type {!Array<!print_preview.RecentDestination>} */
recentDestinations: Array,
/** @private {!Array<!print_preview.Destination>} */
recentDestinationList_: {
type: Array,
notify: true,
computed: 'computeRecentDestinationList_(' +
'destinationStore, recentDestinations, recentDestinations.*, ' +
'userInfo, destinations_.*)',
},
/** @private {?RegExp} */
searchQuery_: {
type: Object,
value: null,
},
},
/** @private {!EventTracker} */
......@@ -55,6 +73,25 @@ Polymer({
this.destinationStore.isPrintDestinationSearchInProgress;
},
/**
* @return {!Array<!print_preview.Destination>}
* @private
*/
computeRecentDestinationList_: function() {
let recentDestinations = [];
const filterAccount = this.userInfo.activeUser;
this.recentDestinations.forEach((recentDestination) => {
const destination = this.destinationStore.getDestination(
recentDestination.origin, recentDestination.id,
recentDestination.account || '');
if (destination &&
(!destination.account || destination.account == filterAccount)) {
recentDestinations.push(destination);
}
});
return recentDestinations;
},
/**
* @return {string} The cloud print promotion HTML.
* @private
......@@ -64,11 +101,29 @@ Polymer({
'cloudPrintPromotion', '<a is="action-link" class="sign-in">', '</a>');
},
/** @private */
onCloseOrCancel_: function() {
if (this.searchQuery_)
this.$.searchBox.setValue('');
this.shadowRoot.querySelectorAll('print-preview-destination-list')
.forEach(list => list.reset());
},
/** @private */
onCancelButtonTap_: function() {
this.$.dialog.cancel();
},
/**
* @param {!CustomEvent} e Event containing the selected destination.
* @private
*/
onDestinationSelected_: function(e) {
this.destinationStore.selectDestination(
/** @type {!print_preview.Destination} */ (e.detail));
this.$.dialog.close();
},
show: function() {
this.loadingDestinations_ =
this.destinationStore.isPrintDestinationSearchInProgress;
......
......@@ -11,6 +11,11 @@
<dom-module id="print-preview-destination-list">
<template>
<style include="print-preview-shared action-link cr-hidden-style throbber">
:host {
padding: 0 14px 18px;
user-select: none;
}
:host > header {
-webkit-padding-end: 19px;
-webkit-padding-start: 0;
......@@ -64,7 +69,7 @@
padding: 0;
}
:host .destination-list-item {
:host .list-item {
-webkit-padding-end: 2px;
-webkit-padding-start: 18px;
cursor: default;
......@@ -73,20 +78,20 @@
padding-top: 3px;
}
:not(.moving).destination-list-item {
:not(.moving).list-item {
transition: background-color 150ms;
}
.destination-list-item:hover,
.destination-list-item:focus {
.list-item:hover,
.list-item:focus {
background-color: rgb(228, 236, 247);
}
.destination-list-item:focus {
.list-item:focus {
outline: none;
}
.destination-list-item.stale :-webkit-any(.destination-list-item-icon,
.list-item.stale :-webkit-any(.destination-list-item-icon,
.destination-list-item-name,
.connection-status) {
opacity: 0.4;
......@@ -102,7 +107,8 @@
width: 24px;
}
.destination-list-item-name {
.destination-list-item-name,
.search-hint {
flex: 0 1 auto;
line-height: 24px;
overflow: hidden;
......@@ -111,8 +117,14 @@
white-space: nowrap;
}
.destination-list-item .connection-status,
.destination-list-item .learn-more-link {
.list-item .search-hint {
-webkit-margin-start: 1em;
color: #999;
font-size: 75%;
}
.list-item .connection-status,
.list-item .learn-more-link {
-webkit-margin-start: 1em;
flex: 0 0 auto;
font-size: 75%;
......@@ -120,7 +132,7 @@
vertical-align: middle;
}
.destination-list-item .learn-more-link {
.list-item .learn-more-link {
color: rgb(51, 103, 214);
}
......@@ -179,15 +191,15 @@
</div>
</header>
<ul>
<template is="dom-repeat" items="[[destinations]]">
<li class$="destination-list-item
[[getStaleCssClass_(item.isOfflineOrInvalid)]]"
hidden$="[[isDestinationHidden_(index, showAll_)]]">
<img class="destination-list-item-icon" alt=""
<template is="dom-repeat" items="[[displayedDestinations_]]">
<li class$="list-item [[getStaleCssClass_(item.isOfflineOrInvalid)]]"
title="[[item.displayName]]"
hidden$="[[isDestinationHidden_(index, showAll_)]]"
on-tap="onDestinationSelected_">
<img class="destination-list-item-icon"
src="[[item.iconUrl]]" srcset="[[item.srcSet]]">
<span class="destination-list-item-name">
[[item.displayName]]
</span>
<span class="destination-list-item-name">[[item.displayName]]</span>
<span class="search-hint">[[getSearchHint_(item, searchQuery)]]</span>
<span class="connection-status"
hidden$="[[!item.isOfflineOrInvalid]]">
[[item.connectionStatusText]]
......@@ -227,7 +239,9 @@
<button class="show-all-button" on-tap="onShowAllTap_">
$i18n{showAllButtonText}
</button>
<span class="total">[[totalDestinations_(destinations)]]</span>
<span class="total">
[[i18n('destinationCount', displayedDestinations_.length)]]
</span>
</footer>
</template>
<script src="destination_list.js"></script>
......
......@@ -18,10 +18,19 @@ Polymer({
destinations: Array,
/** @type {boolean} */
hasActionLink: Boolean,
hasActionLink: {
type: Boolean,
value: false,
},
/** @type {boolean} */
loadingDestinations: Boolean,
loadingDestinations: {
type: Boolean,
value: false,
},
/** @type {?RegExp} */
searchQuery: Object,
/** @type {boolean} */
title: String,
......@@ -32,17 +41,52 @@ Polymer({
value: false,
},
/** @private {!Array<!print_preview.Destination>} */
displayedDestinations_: {
type: Array,
computed: 'computeDisplayedDestinations_(destinations, searchQuery)',
},
/** @type {boolean} */
footerHidden_: {
type: Boolean,
computed: 'computeFooterHidden_(destinations, showAll_)',
computed: 'computeFooterHidden_(displayedDestinations_, showAll_)',
},
/** @private {boolean} */
hasDestinations_: {
type: Boolean,
computed: 'computeHasDestinations_(destinations)',
computed: 'computeHasDestinations_(displayedDestinations_)',
},
},
/**
* @return {!Array<!print_preview.Destination>}
* @private
*/
computeDisplayedDestinations_: function() {
if (!this.searchQuery)
return assert(this.destinations);
return this.destinations.filter(destination => {
return destination.matches(assert(this.searchQuery));
});
},
/**
* @param {!print_preview.Destination} destination The destination to get the
* search hint for.
* @return {string} The property or properties matching the search query.
* @private
*/
getSearchHint_: function(destination) {
if (!this.searchQuery)
return '';
let hint = '';
destination.extraPropertiesToMatch.some(property => {
if (property.match(this.searchQuery))
hint += property;
});
return hint;
},
/**
......@@ -50,7 +94,7 @@ Polymer({
* @private
*/
computeFooterHidden_: function() {
return this.destinations.length < SHORT_DESTINATION_LIST_SIZE ||
return this.displayedDestinations_.length < SHORT_DESTINATION_LIST_SIZE ||
this.showAll_;
},
......@@ -59,7 +103,7 @@ Polymer({
* @private
*/
computeHasDestinations_: function() {
return this.destinations.length != 0;
return this.displayedDestinations_.length > 0;
},
/**
......@@ -81,11 +125,6 @@ Polymer({
return offlineOrInvalid ? 'stale' : '';
},
/** @private string */
totalDestinations_: function() {
return this.i18n('destinationCount', this.destinations.length.toString());
},
/** @private */
onActionLinkTap_: function() {
print_preview.NativeLayer.getInstance().managePrinters();
......@@ -95,5 +134,18 @@ Polymer({
onShowAllTap_: function() {
this.showAll_ = true;
},
/**
* @param {!Event} e Event containing the destination that was selected.
* @private
*/
onDestinationSelected_: function(e) {
this.fire(
'destination-selected', /** @type {!{model: Object}} */ (e).model.item);
},
reset: function() {
this.showAll_ = false;
},
});
})();
......@@ -88,7 +88,9 @@
</print-preview-settings-section>
<template is="cr-lazy-render" id="destinationDialog">
<print-preview-destination-dialog
destination-store="[[destinationStore]]" user-info="[[userInfo]]">
destination-store="[[destinationStore]]"
recent-destinations="[[recentDestinations]]"
user-info="[[userInfo]]">
</print-preview-destination-dialog>
</template>
</template>
......
......@@ -12,6 +12,9 @@ Polymer({
/** @type {?print_preview.DestinationStore} */
destinationStore: Object,
/** @type {!Array<!print_preview.RecentDestination>} */
recentDestinations: Array,
/** @type {!print_preview.UserInfo} */
userInfo: Object,
......
......@@ -371,8 +371,7 @@ Polymer({
this.recentDestinations.splice(indexFound, 1);
// Add the most recent destination
this.recentDestinations.splice(0, 0, newDestination);
this.notifyPath('recentDestinations');
this.splice('recentDestinations', 0, 0, newDestination);
// Persist sticky settings.
this.stickySettingsChanged_();
......
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_search_field/cr_search_field_behavior.html">
<link rel="import" href="print_preview_shared_css.html">
<dom-module id="print-preview-search-box">
<template>
<style include="print-preview-shared">
:host {
display: flex;
position: relative;
user-select: none;
}
.search-box-icon {
display: inline-block;
height: 1em;
left: 8px;
position: absolute;
right: 8px;
top: 6px;
user-select: none;
width: 1em;
}
.search-box-input {
text-indent: 2em;
width: 100%;
}
.search-box-input::-webkit-search-cancel-button {
-webkit-appearance: none;
}
</style>
<img src="../images/search.png" class="search-box-icon" alt="">
<input type="search" id="searchInput" class="search-box-input"
on-search="onSearchTermSearch" on-input="onSearchTermInput"
incremental aria-label$="[[label]]" placeholder="[[label]]">
</template>
<script src="print_preview_search_box.js"></script>
</dom-module>
// Copyright 2018 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.
(function() {
'use strict';
/** @type {!RegExp} */
const SANITIZE_REGEX = /[-[\]{}()*+?.,\\^$|#\s]/g;
Polymer({
is: 'print-preview-search-box',
behaviors: [CrSearchFieldBehavior],
properties: {
/** @type {?RegExp} */
searchQuery: {
type: Object,
notify: true,
},
},
listeners: {
'search-changed': 'onSearchChanged_',
},
/** @return {!HTMLInputElement} */
getSearchInput: function() {
return this.$.searchInput;
},
/**
* @param {!CustomEvent} e Event containing the new search.
*/
onSearchChanged_: function(e) {
const safeQuery = e.detail.trim().replace(SANITIZE_REGEX, '\\$&');
this.searchQuery =
safeQuery.length > 0 ? new RegExp(`(${safeQuery})`, 'ig') : null;
},
});
})();
......@@ -220,9 +220,7 @@
type="chrome_html" />
<structure name="IDR_PRINT_PREVIEW_NEW_DESTINATION_DIALOG_HTML"
file="new/destination_dialog.html"
type="chrome_html"
flattenhtml="true"
allowexternalscript="true" />
type="chrome_html" />
<structure name="IDR_PRINT_PREVIEW_NEW_DESTINATION_DIALOG_JS"
file="new/destination_dialog.js"
type="chrome_html" />
......@@ -233,6 +231,14 @@
<structure name="IDR_PRINT_PREVIEW_NEW_DESTINATION_LIST_JS"
file="new/destination_list.js"
type="chrome_html" />
<structure name="IDR_PRINT_PREVIEW_NEW_PRINT_PREVIEW_SEARCH_BOX_HTML"
file="new/print_preview_search_box.html"
type="chrome_html"
flattenhtml="true"
allowexternalscript="true" />
<structure name="IDR_PRINT_PREVIEW_NEW_PRINT_PREVIEW_SEARCH_BOX_JS"
file="new/print_preview_search_box.js"
type="chrome_html" />
<structure name="IDR_PRINT_PREVIEW_NEW_PRINT_PREVIEW_SHARED_CSS_HTML"
file="new/print_preview_shared_css.html"
type="chrome_html"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment