github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/server/camlistored/ui/filetree.js (about) 1 /* 2 Copyright 2011 The Camlistore Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 goog.provide('cam.FiletreePage'); 18 19 goog.require('goog.dom'); 20 goog.require('goog.events.EventType'); 21 goog.require('goog.ui.Component'); 22 23 goog.require('cam.ServerConnection'); 24 25 // @param {cam.ServerType.DiscoveryDocument} config Global config of the current server this page is being rendered for. 26 // @param {goog.dom.DomHelper=} opt_domHelper DOM helper to use. 27 // @extends {goog.ui.Component} 28 // @constructor 29 cam.FiletreePage = function(config, opt_domHelper) { 30 goog.base(this, opt_domHelper); 31 32 this.config_ = config; 33 this.connection_ = new cam.ServerConnection(config); 34 35 }; 36 goog.inherits(cam.FiletreePage, goog.ui.Component); 37 38 cam.FiletreePage.prototype.indentStep_ = 20; 39 40 function getDirBlobrefParam() { 41 var blobRef = getQueryParam('d'); 42 return (blobRef && isPlausibleBlobRef(blobRef)) ? blobRef : null; 43 } 44 45 // Returns the first value from the query string corresponding to |key|. Returns null if the key isn't present. 46 getQueryParam = function(key) { 47 var params = document.location.search.substring(1).split('&'); 48 for (var i = 0; i < params.length; ++i) { 49 var parts = params[i].split('='); 50 if (parts.length == 2 && decodeURIComponent(parts[0]) == key) 51 return decodeURIComponent(parts[1]); 52 } 53 return null; 54 }; 55 56 // Returns true if the passed-in string might be a blobref. 57 isPlausibleBlobRef = function(blobRef) { 58 return /^\w+-[a-f0-9]+$/.test(blobRef); 59 }; 60 61 cam.FiletreePage.prototype.enterDocument = function() { 62 cam.FiletreePage.superClass_.enterDocument.call(this); 63 var blobref = getDirBlobrefParam(); 64 65 if (blobref) { 66 this.connection_.describeWithThumbnails( 67 blobref, 68 0, 69 goog.bind(this.handleDescribeBlob_, this, blobref), 70 function(msg) { 71 alert("failed to get blob description: " + msg); 72 } 73 ); 74 } 75 } 76 77 // @param {string} blobref blob to describe. 78 // @param {cam.ServerType.DescribeResponse} describeResult Object of properties for the node. 79 cam.FiletreePage.prototype.handleDescribeBlob_ = 80 function(blobref, describeResult) { 81 var meta = describeResult.meta; 82 if (!meta[blobref]) { 83 alert("didn't get blob " + blobref); 84 return; 85 } 86 var binfo = meta[blobref]; 87 if (!binfo) { 88 alert("Error describing blob " + blobref); 89 return; 90 } 91 if (binfo.camliType != "directory") { 92 alert("Does not contain a directory"); 93 return; 94 } 95 this.connection_.getBlobContents( 96 blobref, 97 goog.bind(function(data) { 98 var finfo = JSON.parse(data); 99 var fileName = finfo.fileName; 100 var curDir = document.getElementById('curDir'); 101 curDir.innerHTML = "<a href='./?b=" + blobref + "'>" + fileName + "</a>"; 102 this.buildTree_(); 103 }, this), 104 function(msg) { 105 alert("failed to get blobcontents: " + msg); 106 } 107 ); 108 } 109 110 cam.FiletreePage.prototype.buildTree_ = function() { 111 var blobref = getDirBlobrefParam(); 112 var children = goog.dom.getElement("children"); 113 this.connection_.getFileTree(blobref, 114 goog.bind(function(jres) { 115 this.onChildrenFound_(children, 0, jres); 116 }, this) 117 ); 118 } 119 120 // @param {string} div node used as root for the tree 121 // @param {number} depth how deep we are in the tree, for indenting 122 // @param {cam.ServerType.DescribeResponse} jres describe result 123 cam.FiletreePage.prototype.onChildrenFound_ = function(div, depth, jres) { 124 var indent = depth// cam.FiletreePage.prototype.indentStep_; 125 div.innerHTML = ""; 126 for (var i = 0; i < jres.children.length; i++) { 127 var children = jres.children; 128 var pdiv = goog.dom.createElement("div"); 129 var alink = goog.dom.createElement("a"); 130 alink.style.paddingLeft=indent + "px" 131 alink.id = children[i].blobRef; 132 switch (children[i].type) { 133 case 'directory': 134 goog.dom.setTextContent(alink, "+ " + children[i].name); 135 goog.events.listen(alink, 136 goog.events.EventType.CLICK, 137 goog.bind(function (b, d) { 138 this.unFold_(b, d); 139 }, this, alink.id, depth), 140 false, this 141 ); 142 break; 143 case 'file': 144 goog.dom.setTextContent(alink, " " + children[i].name); 145 alink.href = "./?b=" + alink.id; 146 break; 147 default: 148 alert("not a file or dir"); 149 break; 150 } 151 var newPerm = goog.dom.createElement("span"); 152 newPerm.className = "cam-filetree-newp"; 153 goog.dom.setTextContent(newPerm, "P"); 154 goog.events.listen(newPerm, 155 goog.events.EventType.CLICK, 156 this.newPermWithContent_(alink.id), 157 false, this 158 ); 159 goog.dom.appendChild(pdiv, alink); 160 goog.dom.appendChild(pdiv, newPerm); 161 goog.dom.appendChild(div, pdiv); 162 } 163 } 164 165 cam.FiletreePage.prototype.newPermWithContent_ = function(content) { 166 var fun = function(e) { 167 this.connection_.createPermanode( 168 goog.bind(function(permanode) { 169 this.connection_.newAddAttributeClaim( 170 permanode, "camliContent", content, 171 function() { 172 alert("permanode created"); 173 }, 174 function(msg) { 175 // TODO(mpl): "cancel" new permanode 176 alert("set permanode content failed: " + msg); 177 } 178 ); 179 }, this), 180 function(msg) { 181 alert("create permanode failed: " + msg); 182 } 183 ); 184 } 185 return goog.bind(fun, this); 186 } 187 188 // @param {string} blobref dir to unfold. 189 // @param {number} depth so we know how much to indent. 190 cam.FiletreePage.prototype.unFold_ = function(blobref, depth) { 191 var node = goog.dom.getElement(blobref); 192 var div = goog.dom.createElement("div"); 193 this.connection_.getFileTree(blobref, 194 goog.bind(function(jres) { 195 this.onChildrenFound_(div, depth+1, jres); 196 insertAfter(node, div); 197 goog.events.removeAll(node); 198 goog.events.listen(node, 199 goog.events.EventType.CLICK, 200 goog.bind(function(b, d) { 201 this.fold_(b, d); 202 }, this, blobref, depth), 203 false, this 204 ); 205 }, this) 206 ); 207 } 208 209 function insertAfter( referenceNode, newNode ) { 210 // nextSibling X2 because of the "P" span 211 referenceNode.parentNode.insertBefore( newNode, referenceNode.nextSibling.nextSibling ); 212 } 213 214 // @param {string} nodeid id of the node to fold. 215 // @param {depth} depth so we know how much to indent. 216 cam.FiletreePage.prototype.fold_ = function(nodeid, depth) { 217 var node = goog.dom.getElement(nodeid); 218 // nextSibling X2 because of the "P" span 219 node.parentNode.removeChild(node.nextSibling.nextSibling); 220 goog.events.removeAll(node); 221 goog.events.listen(node, 222 goog.events.EventType.CLICK, 223 goog.bind(function(b, d) { 224 this.unFold_(b, d); 225 }, this, nodeid, depth), 226 false, this 227 ); 228 }