CanJS File Navigator (Simple)
Finished version of the CanJS File Navigator Guide (Simple)
by donejs
HTML
<script src="https://unpkg.com/can@3/dist/global/can.all.js"></script>
<script type="text/stache" id="entities-template">
<span on:click="toggleOpen()">{{name}}</span>
{{#if isOpen}}
<ul>
{{#each ./children}}
<li class="{{type}} {{#if hasChildren}}hasChildren{{/if}}">
{{#eq type 'file'}}
📝 <span>{{name}}</span>
{{else}}
📁 {{>entities}}
{{/eq}}
</li>
{{/each}}
</ul>
{{/if}}
</script>
<script type="text/javascript">
var entityId = 1;
var makeEntities = function(parentId, depth){
if (depth > 5) {
return [];
}
var entitiesCount = can.fixture.rand(6);
var entities = [];
for(var i = 0 ; i< entitiesCount; i++) {
// The id for this entity
var id = ""+(entityId++);
// If the entity is a folder or file
var isFolder = Math.random() > 0.3;
// The children for this folder.
var children = isFolder ? makeEntities(id, depth+1) : [];
var entity = {
id: id,
name: (isFolder ? "Folder" : "File")+" "+id,
parentId: parentId,
type: (isFolder ? "folder" : "file"),
hasChildren: children.length ? true : false
};
entities.push(entity);
if(isFolder) {
entity.children = children;
}
}
return entities;
};
var rootEntityData = {
id: "0",
name: "ROOT/",
hasChildren: true,
type: "folder",
children: makeEntities("0", 0)
};
</script>
CSS
body {
padding: 10px;
}
@import url('https://fonts.googleapis.com/css?family=Roboto+Mono:400,700');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Roboto Mono", "Lucida Console", Monaco, monospace;
font-size: 14px;
color: #000;
}
ul {
list-style: none;
}
li {
padding-left: 20px;
position: relative;
line-height: 2em;
}
li:before{
position: absolute;
left: 5px;
top: -2px;
content: '';
display: block;
height: 1em;
border-bottom: 1px solid #bbb;
width: 10px;
}
li:after {
position: absolute;
left: 5px;
bottom: 0;
content: '';
display: block;
border-left: 1px solid #bbb;
height: 100%;
}
.loading {
color: black;
padding-left: 20px;
padding-top: 10px;
padding-bottom: 10px;
}
.loading:after {
content: "...";
}
.hasChildren > a-folder > span, .hasChildren > span {
transition: all .1s ease-in-out;
cursor: pointer;
border-bottom: 1px dotted #000;
}
.hasChildren > a-folder > span:hover, .hasChildren > span:hover {
opacity: .5;
}
JavaScript
var Entity = can.DefineMap.extend("Entity", {
id: "string",
name: "string",
parentId: "string",
hasChildren: "boolean",
type: "string",
children: [{
type: function(entity) {
return new Entity(entity)
}
}],
isOpen: {type: "boolean", value: false},
toggleOpen: function(){
this.isOpen = !this.isOpen;
}
});
var rootEntity = new Entity(rootEntityData);
var template = can.stache.from("entities-template");
can.stache.registerPartial("entities", template);
var frag = template(rootEntity);
document.body.appendChild( frag );