| <!-- |
| 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> |