Commit 7a3f4d8c authored by Alex Danilo's avatar Alex Danilo Committed by Commit Bot

Add state indicators to display panel.

This CL adds success/failure state indication to the feedback
panel items.

Also adds property setters and attribute handling to control
the visual presentation of the indication state.

If the state indicator is set to something invalid, it defaults
to the circular progress indicator to keep the layout from
collapsing on the left hand side of the panel.

Bug: 947388
Change-Id: I8712619f15963dfd931cb277064132ec82efb1be
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1634572Reviewed-by: default avatarLuciano Pacheco <lucmult@chromium.org>
Commit-Queue: Alex Danilo <adanilo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#666555}
parent f52528b5
// Copyright 2019 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.
/**
* Activity complete indicator custom element for use in PanelEntry(s).
*/
class ActivityComplete extends HTMLElement {
constructor() {
super();
const host = document.createElement('template');
host.innerHTML = this.constructor.template_;
this.attachShadow({mode: 'open'}).appendChild(host.content.cloneNode(true));
}
/**
* Static getter for the custom element template.
* @return {string}
* @private
*/
static get template_() {
return `<style>
.complete {
height: 36px;
width: 36px;
stroke-width: 3px;
fill: none;
}
</style>
<div class='complete'>
<svg xmlns='http://www.w3.org/2000/svg'
viewBox='0 0 36 36'>
<path id='success' display='inherit'
d='M4 20l9 9l22 -22' stroke='#34A853'/>
<g id='failure' display='none' stroke='#EA4335'>
<circle cx='18' cy='18' r='14'/>
<path d='M18 10l0 10M18 23l0 3'/>
</g>
</svg>
</div>`;
}
/**
* Registers this instance to listen to these attribute changes.
* @private
* @return {Array<String>}
*/
static get observedAttributes() {
return ['status'];
}
/**
* Callback triggered by the browser when our attribute values change.
* @param {string} name Attribute that's changed.
* @param {string} oldValue Old value of the attribute.
* @param {string} newValue New value of the attribute.
* @private
*/
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'status') {
if (oldValue != newValue) {
const success = this.shadowRoot.querySelector('#success');
const failure = this.shadowRoot.querySelector('#failure');
switch (newValue) {
case 'success':
success.setAttribute('display', 'inherit');
failure.setAttribute('display', 'none');
break;
case 'failure':
failure.setAttribute('display', 'inherit');
success.setAttribute('display', 'none');
break;
default:
assertNotReached();
break;
}
}
}
}
/**
* Getter for the current state of the progress indication.
* @return {string}
* @public
*/
get status() {
return this.getAttribute('status');
}
/**
* Setter to set the success/failure indication.
* @param {string} status Status value being set.
* @public
*/
set status(status) {
// Reflect the status property into the attribute.
this.setAttribute('status', status);
}
}
window.customElements.define('xf-activity-complete', ActivityComplete);
......@@ -43,20 +43,20 @@ class DisplayPanel extends HTMLElement {
*/
static get template_() {
return `<style>
#container {
align-items: center;
background-color: #FFF;
box-shadow: -2px -1px rgba(60, 64, 67, 0.15),
-1px 2px rgba(60, 64, 67, 0.3),
2px 0px rgba(60, 64, 67, 0.15);
border-radius: 4px;
display: flex;
flex-direction: column;
max-width: 400px;
z-index: 100;
}
</style>
<div id="container"></div>`;
#container {
align-items: stretch;
background-color: #FFF;
box-shadow: -2px -1px rgba(60, 64, 67, 0.15),
-1px 2px rgba(60, 64, 67, 0.3),
2px 0px rgba(60, 64, 67, 0.15);
border-radius: 4px;
display: flex;
flex-direction: column;
max-width: min-content;
z-index: 100;
}
</style>
<div id="container"></div>`;
}
/**
......
......@@ -7,8 +7,11 @@
<html>
<head>
<title>Display Panel test harness</title>
<link rel="stylesheet" href="files_visual_signals.css">
<script type="module" src="display_panel_test.mjs"></script>
<link rel="stylesheet" href="panel/files_visual_signals.css">
<script src="panel/circular_progress.js"></script>
<script src="panel/activity_complete.js"></script>
<script src="panel/panel_item.js"></script>
<script src="panel/display_panel.js"></script>
</head>
<body>
<xf-display-panel id="main-panel">
......
// Copyright 2019 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.
import {DisplayPanel} from './display_panel.mjs';
......@@ -26,6 +26,7 @@ xf-display-panel {
max-width: 216px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.xf-panel-label-text {
......@@ -41,13 +42,26 @@ xf-display-panel {
}
.xf-padder-16 {
min-width: 16px;
width: 16px;
}
.xf-padder-24 {
min-width: 24px;
flex-grow: 16;
width: 24px;
}
xf-circular-progress {
padding: 16px;
}
xf-activity-complete {
padding: 16px;
}
.xf-success {
color: rgb(52, 168, 83);
}
.xf-failure {
color: rgb(234, 67, 53);
}
......@@ -26,9 +26,8 @@ class PanelItem extends HTMLElement {
<div class='xf-panel-item'>
<div class='xf-panel-text'>
<span class='xf-panel-label-text'>
Copying File_With_a_long_name.jpg</span>
<span class='xf-panel-secondary-text'>
To SubFolder A1</span>
Placeholder text</span>
<br/>
</div>
<div class='xf-padder-24'></div>
<button class='xf-button' src='pause-icon.png'
......@@ -38,6 +37,7 @@ class PanelItem extends HTMLElement {
<button class='xf-button' src='cancel-icon.png'
tabindex='-1'>
</button>
<div class='xf-padder-16'></div>
</div>`;
}
......@@ -46,7 +46,9 @@ class PanelItem extends HTMLElement {
* @private
*/
static get observedAttributes() {
return ['indicator', 'progress'];
return [
'indicator', 'progress', 'status', 'primary-text', 'secondary-text'
];
}
/**
......@@ -57,19 +59,43 @@ class PanelItem extends HTMLElement {
* @private
*/
attributeChangedCallback(name, oldValue, newValue) {
/** @type {HTMLElement} */
let indicator;
/** @type {HTMLSpanElement} */
let textNode;
if (oldValue === newValue) {
return;
}
switch (name) {
case 'indicator':
if (oldValue !== newValue) {
if (newValue === 'progress' || newValue === 'largeprogress') {
// Get rid of any existing indicator.
const oldIndicator = this.shadowRoot.querySelector('#indicator');
if (oldIndicator) {
oldIndicator.remove();
}
switch (newValue) {
default: // Always set something so the panel doesn't shrink.
case 'progress':
case 'largeprogress':
indicator = document.createElement('xf-circular-progress');
indicator.setAttribute('id', 'indicator');
if (newValue === 'largeprogress') {
indicator.setAttribute('radius', '14');
} else {
indicator.setAttribute('radius', '10');
}
const itemRoot = this.shadowRoot.querySelector('.xf-panel-item');
itemRoot.prepend(indicator);
}
break;
case 'status':
indicator = document.createElement('xf-activity-complete');
const status = this.getAttribute('status');
if (status) {
indicator.status = status;
}
break;
}
if (indicator) {
const itemRoot = this.shadowRoot.querySelector('.xf-panel-item');
indicator.setAttribute('id', 'indicator');
itemRoot.prepend(indicator);
}
break;
case 'progress':
......@@ -78,8 +104,84 @@ class PanelItem extends HTMLElement {
indicator.progress = Number(newValue);
}
break;
case 'status':
indicator = this.shadowRoot.querySelector('#indicator');
if (indicator) {
indicator.status = newValue;
}
break;
case 'primary-text':
textNode = this.shadowRoot.querySelector('.xf-panel-label-text');
if (textNode) {
textNode.textContent = newValue;
}
break;
case 'secondary-text':
textNode = this.shadowRoot.querySelector('.xf-panel-secondary-text');
if (!textNode) {
const parent = this.shadowRoot.querySelector('.xf-panel-text');
if (!parent) {
return;
}
textNode = document.createElement('span');
textNode.setAttribute('class', 'xf-panel-secondary-text');
parent.appendChild(textNode);
}
// Remove the secondary text node if the text is empty
if (newValue == '') {
textNode.remove();
} else {
textNode.textContent = newValue;
}
break;
}
}
/**
* Setter to set the indicator type.
* @param {string} indicator Progress (optionally large) or status.
*/
set indicator(indicator) {
// Reflect the status property into the attribute.
this.setAttribute('indicator', indicator);
}
/**
* Setter to set the success/failure indication.
* @param {string} status Status value being set.
*/
set status(status) {
// Reflect the status property into the attribute.
this.setAttribute('status', status);
}
/**
* Setter to set the progress property, sent to any child indicator.
* @param {string} progress Progress value being set.
* @public
*/
set progress(progress) {
// Reflect the progress property into the attribute.
this.setAttribute('progress', progress);
}
/**
* Setter to set the primary text on the panel.
* @param {string} text Text to be shown.
*/
set primaryText(text) {
// Reflect the status property into the attribute.
this.setAttribute('primary-text', text);
}
/**
* Setter to set the secondary text on the panel.
* @param {string} text Text to be shown.
*/
set secondaryText(text) {
// Reflect the status property into the attribute.
this.setAttribute('secondary-text', text);
}
}
window.customElements.define('xf-panel-item', PanelItem);
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