blob: 4f24c012f8080a9f60d6a8b40f5776698c5abdb0 [file] [log] [blame]
<!--
tree-node elements are nested to create a tree menu
<tree-node label="" icon="" iconalt="" itemtitle="" open highlight loading>
Example:
<tree-node id="root" label="Location">
<tree-node label="California" highlight></tree-node>
</tree-node>
(see demo.html for a full example)
Attributes:
label: (string) displayed text of the tree node
icon: (string) optional Polymer icon name; see
https://www.polymer-project.org/components/core-icons/demo.html)
iconalt: (string) alt text for item icon
itemtitle: (string) title text for item
open: (Boolean) expand to display nested children
highlight: (Boolean) adds "highlight" CSS class to item
loading: (Boolean) displays loading spinner
isExpandable: (Boolean) displays the expand/collapse icon even if there are no children
Events:
Attach one event listener to the root (or above),
or individual listeners to each node.
Don't forget to return false from the callback function to stop propagation.
@event activate node item was clicked or tapped
@event openchange node was expanded or collapsed
The listener functions take a single parameter:
@param {event} e the custom event object
For both, e.detail.node is the affected tree-node.
For the activate event, e.shiftKey, e.altKey, e.ctrlKey, and e.metaKey
contain the state of those keyboard keys.
author: wmleler@
-->
<polymer-element name="tree-node" attributes="label icon emptytext">
<template>
<link rel="stylesheet" href="tree-node.css">
<div class="indent" aria-expanded="{{open}}"
aria-owns="{{isParent && open?'children':''}}">
<div class="row">
<template if="{{showEmptyIcon}}">
<core-icon id="expander"
icon="remove"
alt="{{emptytext}}"
title="{{emptytext}}">
</core-icon>
</template>
<template if="{{!showEmptyIcon}}">
<a class="expander-anchor"
href="javascript:void(0);"
on-click="{{openme}}"
tabindex="{{isParent?'0':'-1'}}">
<core-icon id="expander"
class="{{isParent?'':'notParent'}}"
icon="{{open?'expand-more':'chevron-right'}}"
alt="{{open?'Collapse':'Expand'}}"
title="{{open?'Collapse':'Expand'}}"
>
</core-icon>
</a>
</template>
<paper-spinner active="{{loading}}" aria-label="loading">
</paper-spinner>
<a href="javascript:void(0);"
on-click="{{activate}}"
role="treeitem"
aria-selected="{{highlight}}"
class="item{{highlight?' highlight':''}}"
title="{{itemtitle}}">
<span class="itemcontent">
<template if="{{icon}}">
<core-icon class="itemicon" icon="{{icon}}" alt="{{iconalt}}">
</core-icon>
</template>
<span class="itemtext">
{{label}}
</span>
</span>
</a>
</div>
<template if="{{isParent && open}}">
<div id="children" role="group">
<content></content>
</div>
</template>
</div>
</template>
<script>
Polymer('tree-node', {
publish: {
emptytext: 'No children',
iconalt: 'item icon',
itemtitle: 'item',
open: false,
highlight: false,
loading: false,
isExpandable: false
},
isParent: false,
showEmptyIcon: false,
ready: function() {
this.isExpandableChanged();
this.onMutation(this, this.childrenUpdated);
},
childrenUpdated: function(observer, mutations) {
this.isExpandableChanged();
this.onMutation(this, this.childrenUpdated);
this.updateShowEmptyIcon();
},
isExpandableChanged: function() {
this.isParent = !!this.firstElementChild || this.isExpandable;
},
openChanged: function() {
this.updateShowEmptyIcon();
},
loadingChanged: function() {
this.updateShowEmptyIcon();
},
updateShowEmptyIcon: function() {
var me = this;
setTimeout(function() {
me.showEmptyIcon = (
!me.firstElementChild &&
!me.loading &&
me.isExpandable &&
me.open
);
}, 30); // delay showing the empty icon by a bit so it is less jarring
},
openme: function(e, d, sender) {
this.open = !this.open;
this.fire('openchange', { node: this });
},
activate: function(event, detail, sender) {
this.fire('activate', { node: this,
shiftKey: event.shiftKey, altKey: event.altKey,
ctrlKey: event.ctrlKey, metaKey: event.metaKey });
}
});
</script>
</polymer-element>