tree.jsp
:
We use a flexible layout and use no list-style counting, because this would constrain us. Instead we display the key as the "real" key from our<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="portlet" uri="http://java.sun.com/portlet_2_0"%><portlet:defineObjects /> <div id="<portlet:namespace />tree"> <div class="body"> <div class="tree"> <tree :items="items[1]"></tree> </div> <div v-if="openItem"> <p>{{ openItem.text }}</p> </div> </div> </div>
<script> Vue.component('tree', { template: `\ <ol>\ <li v-for="key in Object.keys(items)" :key="key">\ <a :class="{open : isOpen(key)}" @click="open(key)">{{ key }}. {{ items[key].heading }}</a>\ <tree v-if="getSubitems(key) && isOpen(key)" :items="getSubitems(key)"></tree>\ </li>\ </ol>\ `, props: { items: Object }, methods: { getSubitems: function(key) { var levels = key.split("."); var sublevel = this.$root.$data.items[levels.length+1]; if (sublevel) { return sublevel[key]; } }, isOpen: function(key) { if (this.$root.$data.openKey.startsWith(key)) { return true; } else { return false; } }, open: function(key) { this.$root.$data.openKey = key; } } }); var app = new Vue({ el: '#<portlet:namespace />tree', data: function() { return { items : { "1" : { "1": { "heading": "Item A", "text" : "cold" }, "2": { "heading": "Item B", "text" : "warm" }, "3": { "heading": "Item C", "text" : "cold" }, "4": { "heading": "Item D", "text" : "very cold" } }, "2" : { "1": { "1.1": { "heading": "Subitem A 1", "text" : "colder" }, "1.2": { "heading": "Subitem A 2", "text" : "very cold" } }, "2": { "2.1": { "heading": "Subitem B 1", "text" : "colder" }, "2.2": { "heading": "Subitem B 2", "text" : "warmer" } }, "3": { "3.1": { "heading": "Subitem C 1", "text" : "very cold" } } }, "3" : { "2.2" : { "2.2.1" : { "heading": "Deep Subitem", "text": "very hot" } } }, "4" : { "2.2.1" : { "2.2.1.1" : { "heading" : "Another Deep Subitem", "text" : "Congratulations, you made it so deep!" } } } }, openKey: '' } }, computed: { openItem: function() { if (this.openKey) { var level = this.openKey.split(".").length; var levelItems = this.items[level]; if (level == 1) { levelItems = levelItems[this.openKey]; } else { var lastDot = this.openKey.lastIndexOf("."); var parent = this.openKey.substring(0, lastDot); levelItems = levelItems[parent][this.openKey]; } return levelItems; } } } }) </script>
<style> #<portlet:namespace />tree { display: flex; flex-flow: column nowrap; height: 100%; } #<portlet:namespace />tree * { box-sizing: border-box; } #<portlet:namespace />tree ol { list-style-type: none; } #<portlet:namespace />tree .body { display: flex; flex-flow: row nowrap; height: 100%; width: 100%; } #<portlet:namespace />tree .body .tree { max-width: 50%; min-width: 50%; overflow-y: scroll; } #<portlet:namespace />tree .body ol { box-sizing: content-box; padding: 0; } #<portlet:namespace />tree .body a.open+ol>li { padding-left: 10px; } #<portlet:namespace />tree .body li { background: white; line-height: 2em; } #<portlet:namespace />tree .body li:hover { cursor: pointer; } #<portlet:namespace />tree .body li a { background: none; display: block; outline: none; } #<portlet:namespace />tree .body li a:hover { text-decoration: none; } #<portlet:namespace />tree .body li a.open { background: #f7ed4d; } </style>
items
. As a data structure we use some kind of a multi-dimensional hash-list. Each navigation hierarchy is located on the first level of our items
. Why we don't use a nested hierarchy instead, like the following?
"2" : {
"heading" : "Item B",
"text" : "warm",
"2.2" : {
"heading" : "Subitem B",
"text" : "warmer",
"2.2.1" : {
"heading" : "Another Deep subitem",
"text" : "very hot",
"2.2.1.1" : {
"heading" : "Another Deep subitem",
"text" : "Congratulations, you made it so deep!"
}
}
}
}
Wouldn't this be more intuitive? Maybe from the viewpoint of creating the datastructure itself, but this wouldn't serve us well, when it comes to the operations, we want to apply on the items, and we don't want "big" items.So, the list is being created breadth first, not depth first in the
for
loop. With this we don't need to parse the keys of each item to see, if it is a subtree or not, then remember it for later after we displayed the siblings first then go back display the sibling, etc. which would cause us a lot of headache...
We just look into the next hierarchy level and if it has a link to the parent, we display it as another tree. This we can do for each item and we have the freedom to view each item as an independet piece. Of course we start with the
items[1]
at level 1.Enjoy!
No comments:
Post a Comment
Please stick to the Netiquette Guidelines and consider asking questions the smart way ..