blob: c6f40cec334f116084e88ba6f62f754e60b70cab [file] [log] [blame]
// 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.
/**
* @fileoverview
* app-management-dom-switch is used to select one element to be displayed at a
* time from a group of elements. When an element is selected, it is attached
* to the DOM. When another element is selected, the first element is
* detached, meaning only one of the elements is attached at a time.
*
* The elements are selected by giving them each a route-id attribute, then
* setting the route property of the dom-switch equal to the route-id of the
* element to be shown.
*
* Data binding from the parent element of the dom-switch to its child
* elements works as usual.
*
* Usage:
* <parent-element>
* <app-management-dom-switch id="view-selector">
* <template>
* <view-one route-id="view-one" title="[[parentProperty]]"></view-one>
* <view-two route-id="view-two"></view-two>
* <view-three route-id="view-three"></view-three>
* </template>
* </app-management-dom-switch>
* </parent-element>
*
* this.$['view-selector'].route = 'view-two';
*/
Polymer({
is: 'app-management-dom-switch',
behaviors: [Polymer.Templatizer],
properties: {
/**
* Should contain the route-id of one of the elements within the dom-switch.
* @private {?string}
*/
route: {
type: String,
observer: 'onRouteChanged_',
},
/**
* The template instance.
* @private {?Element}
*/
instance_: {
type: Object,
value: null,
},
/**
* Maps the route-id of each element within the dom-switch to the element
* itself.
* @private {Object<string, Element>}
*/
children_: {
type: Object,
value: () => ({}),
},
/**
* The element whose route-id corresponds to the current route. This is the
* only element within the dom-switch which is attached to the DOM.
* @private {?Element}
*/
selectedChild_: {
type: Object,
value: null,
},
},
attached: function() {
const template = this.getContentChildren()[0];
this.templatize(template);
// This call stamps all the child elements of the dom-switch at once
// (calling their created Polymer lifecycle callbacks). If optimisations
// are required in the future, it may be possible to only stamp children
// on demand as they are rendered.
this.instance_ = this.stamp({});
const children = this.instance_.root.children;
for (const child of children) {
this.children_[child.getAttribute('route-id')] = child;
}
},
/**
* @param {string} newRouteId
*/
onRouteChanged_: function(newRouteId) {
const newSelectedChild = this.children_[newRouteId];
assert(
newSelectedChild,
'The route must be equal to the route-id of a child element.');
if (this.selectedChild_) {
this.parentNode.replaceChild(newSelectedChild, this.selectedChild_);
} else {
this.parentNode.insertBefore(newSelectedChild, this);
}
this.selectedChild_ = newSelectedChild;
},
/**
* TODO(dpapad): Delete this method once migration to Polymer 2 has finished.
* @param {string} prop
* @param {Object} value
*/
_forwardParentProp: function(prop, value) {
if (this.instance_) {
this.instance_[prop] = value;
}
},
/**
* TODO(dpapad): Delete this method once migration to Polymer 2 has finished.
* @param {string} path
* @param {Object} value
*/
_forwardParentPath: function(path, value) {
if (this.instance_) {
this.instance_.notifyPath(path, value, true);
}
},
/**
* @param {string} prop
* @param {Object} value
*/
_forwardHostPropV2: function(prop, value) {
if (this.instance_) {
this.instance_.forwardHostProp(prop, value);
}
},
});