bone_tree 0.5.6 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +26 -3
- data/Gemfile +5 -12
- data/Rakefile +7 -9
- data/bone_tree.gemspec +30 -14
- data/config.rb +8 -0
- data/lib/assets/javascripts/bone_tree.js +277 -981
- data/lib/assets/stylesheets/bone_tree.css +108 -0
- data/lib/bone_tree/rails.rb +5 -0
- data/lib/bone_tree/sprockets.rb +3 -0
- data/lib/{version.rb → bone_tree/version.rb} +1 -1
- data/lib/bone_tree.rb +11 -6
- data/source/index.html.haml +10 -382
- data/source/javascripts/{_backbone.js → backbone.js} +282 -142
- data/source/javascripts/bone_tree/models/directory.js.coffee +109 -0
- data/source/javascripts/bone_tree/models/file.js.coffee +12 -0
- data/source/javascripts/bone_tree/models/node.js.coffee +24 -0
- data/source/javascripts/bone_tree/models/settings.js.coffee +5 -0
- data/source/javascripts/bone_tree/{_namespace.js.coffee → namespace.js.coffee} +1 -1
- data/source/javascripts/bone_tree/views/directory.js.coffee +56 -0
- data/source/javascripts/bone_tree/views/file.js.coffee +25 -0
- data/source/javascripts/bone_tree/views/tree.js.coffee +87 -0
- data/source/javascripts/bone_tree.js.coffee +2 -1
- data/source/stylesheets/bone_tree.css.sass +0 -38
- data/spec/javascripts/directory_spec.coffee +26 -0
- data/spec/javascripts/helpers/spec_helper.coffee +3 -4
- data/spec/javascripts/sorting_spec.coffee +12 -0
- data/spec/javascripts/support/jasmine.yml +6 -4
- metadata +143 -36
- data/Gemfile.lock +0 -190
- data/docs/index.html +0 -222
- data/docs/resources/base.css +0 -70
- data/docs/resources/index.css +0 -20
- data/docs/resources/module.css +0 -24
- data/docs/source/javascripts/bone_tree/_namespace.js.html +0 -45
- data/docs/source/javascripts/bone_tree/models/_directory.js.html +0 -126
- data/docs/source/javascripts/bone_tree/models/_file.js.html +0 -112
- data/docs/source/javascripts/bone_tree/models/_nodes.js.html +0 -174
- data/docs/source/javascripts/bone_tree/models/_settings.js.html +0 -75
- data/docs/source/javascripts/bone_tree/views/_directory.js.html +0 -94
- data/docs/source/javascripts/bone_tree/views/_file.js.html +0 -82
- data/docs/source/javascripts/bone_tree/views/_menu.js.html +0 -110
- data/docs/source/javascripts/bone_tree/views/_tree.js.html +0 -432
- data/source/javascripts/_jquery.min.js +0 -5
- data/source/javascripts/_underscore.js +0 -999
- data/source/javascripts/bone_tree/models/_directory.js.coffee +0 -63
- data/source/javascripts/bone_tree/models/_file.js.coffee +0 -55
- data/source/javascripts/bone_tree/models/_nodes.js.coffee +0 -117
- data/source/javascripts/bone_tree/models/_settings.js.coffee +0 -25
- data/source/javascripts/bone_tree/views/_directory.js.coffee +0 -73
- data/source/javascripts/bone_tree/views/_file.js.coffee +0 -51
- data/source/javascripts/bone_tree/views/_menu.js.coffee +0 -97
- data/source/javascripts/bone_tree/views/_tree.js.coffee +0 -498
- data/spec/javascripts/directory_view_spec.coffee +0 -91
- data/spec/javascripts/file_view_spec.coffee +0 -70
- data/spec/javascripts/menu_view_spec.coffee +0 -42
- data/spec/javascripts/nodes_spec.coffee +0 -37
- data/spec/javascripts/tree_view_spec.coffee +0 -39
@@ -1,7 +1,7 @@
|
|
1
1
|
(function() {
|
2
2
|
var __slice = [].slice;
|
3
3
|
|
4
|
-
window.BoneTree = {};
|
4
|
+
window.BoneTree || (window.BoneTree = {});
|
5
5
|
|
6
6
|
BoneTree.namespace = function(target, name, block) {
|
7
7
|
var item, top, _i, _len, _ref, _ref1;
|
@@ -21,99 +21,36 @@
|
|
21
21
|
(function() {
|
22
22
|
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
23
23
|
__hasProp = {}.hasOwnProperty,
|
24
|
-
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; };
|
24
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
25
25
|
|
26
26
|
BoneTree.namespace("BoneTree.Models", function(Models) {
|
27
27
|
Models.Node = (function(_super) {
|
28
28
|
|
29
29
|
__extends(Node, _super);
|
30
30
|
|
31
|
-
Node.name = 'Node';
|
32
|
-
|
33
31
|
function Node() {
|
34
|
-
this.
|
32
|
+
this.name = __bind(this.name, this);
|
33
|
+
|
34
|
+
this.isFile = __bind(this.isFile, this);
|
35
35
|
|
36
|
-
this.
|
36
|
+
this.isDirectory = __bind(this.isDirectory, this);
|
37
37
|
return Node.__super__.constructor.apply(this, arguments);
|
38
38
|
}
|
39
39
|
|
40
|
-
/*
|
41
|
-
Internal: An abstract super class for File and Directory objects to inherit from.
|
42
|
-
*/
|
43
|
-
|
44
|
-
|
45
40
|
Node.prototype.initialize = function() {
|
46
|
-
/*
|
47
|
-
Internal: Initialize a new Node object. Set it up to contain a collection of
|
48
|
-
children nodes.
|
49
|
-
*/
|
50
41
|
return this.collection = new Models.Nodes;
|
51
42
|
};
|
52
43
|
|
53
|
-
Node.prototype.
|
54
|
-
|
55
|
-
Public: Returns a String with the nodeType capitalized so that it may be used
|
56
|
-
to instatiate the appropriate view type
|
57
|
-
|
58
|
-
Examples
|
59
|
-
|
60
|
-
file = new BoneTree.Models.File
|
61
|
-
directory = new BoneTree.Models.Directory
|
62
|
-
|
63
|
-
file.constantize()
|
64
|
-
# => 'File'
|
65
|
-
|
66
|
-
directory.constantize()
|
67
|
-
# => 'Directory'
|
68
|
-
|
69
|
-
# use it to create a new view of the appropriate type
|
70
|
-
view = new BoneTree.Views[file.constantize()]
|
71
|
-
|
72
|
-
Returns a String of the nodeType with the first letter capitalized.
|
73
|
-
*/
|
74
|
-
|
75
|
-
var nodeType;
|
76
|
-
nodeType = this.get('nodeType');
|
77
|
-
return nodeType[0].toUpperCase() + nodeType.substring(1);
|
44
|
+
Node.prototype.isDirectory = function() {
|
45
|
+
return this instanceof Models.Directory;
|
78
46
|
};
|
79
47
|
|
80
|
-
Node.prototype.
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
file = new BoneTree.Models.File
|
88
|
-
name: "file"
|
89
|
-
extension: "coffee"
|
90
|
-
|
91
|
-
noExt = new BoneTree.Models.File
|
92
|
-
name: "file2"
|
93
|
-
|
94
|
-
directory = new BoneTree.Model.Directory
|
95
|
-
name: "source"
|
96
|
-
|
97
|
-
file.nameWithExtension()
|
98
|
-
# => "file.coffee"
|
99
|
-
|
100
|
-
noExt.nameWithExtension()
|
101
|
-
# => "file2"
|
102
|
-
|
103
|
-
directory.nameWithExtension()
|
104
|
-
# => "source"
|
105
|
-
|
106
|
-
Returns a String. If the extension exists then the node name plus the extension
|
107
|
-
are returned. If there is no extension, then just the node name is returned.
|
108
|
-
*/
|
109
|
-
|
110
|
-
var extension, name, _ref;
|
111
|
-
_ref = this.attributes, extension = _ref.extension, name = _ref.name;
|
112
|
-
extension || (extension = "");
|
113
|
-
if (extension !== "") {
|
114
|
-
extension = "." + extension;
|
115
|
-
}
|
116
|
-
return name + extension;
|
48
|
+
Node.prototype.isFile = function() {
|
49
|
+
return this instanceof Models.File;
|
50
|
+
};
|
51
|
+
|
52
|
+
Node.prototype.name = function() {
|
53
|
+
return this.get('path').split('/').last();
|
117
54
|
};
|
118
55
|
|
119
56
|
return Node;
|
@@ -123,47 +60,18 @@
|
|
123
60
|
|
124
61
|
__extends(Nodes, _super);
|
125
62
|
|
126
|
-
Nodes.name = 'Nodes';
|
127
|
-
|
128
63
|
function Nodes() {
|
129
64
|
return Nodes.__super__.constructor.apply(this, arguments);
|
130
65
|
}
|
131
66
|
|
132
|
-
/*
|
133
|
-
Internal: A collection of node models. Since Node is an abstract super
|
134
|
-
class, in practice this collection will hold File objects
|
135
|
-
and Directory objects.
|
136
|
-
*/
|
137
|
-
|
138
|
-
|
139
67
|
Nodes.prototype.comparator = function(node) {
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
tree.addFile('/source/file1.coffee')
|
148
|
-
tree.addFile('/source/file2.coffee')
|
149
|
-
tree.addFile('main.coffee')
|
150
|
-
|
151
|
-
tree.render()
|
152
|
-
|
153
|
-
# even though 'main' comes before 'source' alphabetically it is placed
|
154
|
-
# after the 'source' directory due to the sortPriority of the Directory object.
|
155
|
-
tree.toAscii()
|
156
|
-
# => "
|
157
|
-
-source
|
158
|
-
-file1.coffee
|
159
|
-
-file2.coffee
|
160
|
-
-main.coffee
|
161
|
-
"
|
162
|
-
*/
|
163
|
-
|
164
|
-
var name, sortPriority, _ref;
|
165
|
-
_ref = node.attributes, name = _ref.name, sortPriority = _ref.sortPriority;
|
166
|
-
return sortPriority + name;
|
68
|
+
var sortPriority;
|
69
|
+
if (node.isDirectory()) {
|
70
|
+
sortPriority = 0;
|
71
|
+
} else {
|
72
|
+
sortPriority = 1;
|
73
|
+
}
|
74
|
+
return sortPriority + node.name();
|
167
75
|
};
|
168
76
|
|
169
77
|
Nodes.prototype.model = Models.Node;
|
@@ -177,206 +85,225 @@
|
|
177
85
|
(function() {
|
178
86
|
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
179
87
|
__hasProp = {}.hasOwnProperty,
|
180
|
-
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; }
|
88
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
89
|
+
__slice = [].slice;
|
181
90
|
|
182
91
|
BoneTree.namespace("BoneTree.Models", function(Models) {
|
183
|
-
Models.Directory = (function(_super) {
|
92
|
+
return Models.Directory = (function(_super) {
|
184
93
|
|
185
94
|
__extends(Directory, _super);
|
186
95
|
|
187
|
-
Directory.name = 'Directory';
|
188
|
-
|
189
96
|
function Directory() {
|
190
|
-
this.
|
97
|
+
this.updateChildren = __bind(this.updateChildren, this);
|
98
|
+
|
99
|
+
this.toAscii = __bind(this.toAscii, this);
|
100
|
+
|
101
|
+
this.toArray = __bind(this.toArray, this);
|
102
|
+
|
103
|
+
this.getFile = __bind(this.getFile, this);
|
104
|
+
|
105
|
+
this.files = __bind(this.files, this);
|
106
|
+
|
107
|
+
this.getDirectory = __bind(this.getDirectory, this);
|
108
|
+
|
109
|
+
this.directories = __bind(this.directories, this);
|
110
|
+
|
111
|
+
this.remove = __bind(this.remove, this);
|
112
|
+
|
113
|
+
this.add = __bind(this.add, this);
|
191
114
|
return Directory.__super__.constructor.apply(this, arguments);
|
192
115
|
}
|
193
116
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
117
|
+
Directory.prototype.add = function(filePath, fileData) {
|
118
|
+
var Directory, File, currentDirectory, dirs, file, fileName, _i, _ref;
|
119
|
+
if (fileData == null) {
|
120
|
+
fileData = {};
|
121
|
+
}
|
122
|
+
Directory = Models.Directory, File = Models.File;
|
123
|
+
_ref = filePath.split('/'), dirs = 2 <= _ref.length ? __slice.call(_ref, 0, _i = _ref.length - 1) : (_i = 0, []), fileName = _ref[_i++];
|
124
|
+
currentDirectory = this;
|
125
|
+
dirs.each(function(directoryName) {
|
126
|
+
var directory;
|
127
|
+
if (directoryName === '') {
|
128
|
+
return;
|
129
|
+
}
|
130
|
+
directory = currentDirectory.directories().select(function(dir) {
|
131
|
+
return dir.name() === directoryName;
|
132
|
+
}).first();
|
133
|
+
if (!directory) {
|
134
|
+
directory = new Directory({
|
135
|
+
path: filePath.substring(0, filePath.indexOf(directoryName) + directoryName.length)
|
136
|
+
});
|
137
|
+
currentDirectory.collection.add(directory);
|
138
|
+
}
|
139
|
+
return currentDirectory = directory;
|
140
|
+
});
|
141
|
+
if (file = currentDirectory.getFile(fileName)) {
|
142
|
+
return file.set(fileData);
|
143
|
+
} else {
|
144
|
+
file = new File(_.extend(fileData, {
|
145
|
+
path: filePath
|
146
|
+
}));
|
147
|
+
currentDirectory.collection.add(file);
|
148
|
+
return file;
|
149
|
+
}
|
150
|
+
};
|
151
|
+
|
152
|
+
Directory.prototype.remove = function(path) {
|
153
|
+
var directory, file;
|
154
|
+
if (file = this.getFile(path)) {
|
155
|
+
return file.destroy();
|
156
|
+
} else if (directory = this.getDirectory(path)) {
|
157
|
+
return directory.destroy();
|
158
|
+
}
|
216
159
|
};
|
217
160
|
|
218
|
-
Directory.prototype.
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
161
|
+
Directory.prototype.directories = function() {
|
162
|
+
return this.collection.filter(function(node) {
|
163
|
+
return node.isDirectory();
|
164
|
+
});
|
165
|
+
};
|
166
|
+
|
167
|
+
Directory.prototype.getDirectory = function(directoryPath) {
|
168
|
+
var first, match, rest, _ref;
|
169
|
+
_ref = directoryPath.split('/'), first = _ref[0], rest = 2 <= _ref.length ? __slice.call(_ref, 1) : [];
|
170
|
+
match = this.collection.find(function(node) {
|
171
|
+
return node.name() === first;
|
172
|
+
});
|
173
|
+
if (match != null ? match.isDirectory() : void 0) {
|
174
|
+
if (rest.length) {
|
175
|
+
return match.getDirectory(rest.join('/'));
|
176
|
+
} else {
|
177
|
+
return match;
|
178
|
+
}
|
179
|
+
}
|
180
|
+
return void 0;
|
181
|
+
};
|
182
|
+
|
183
|
+
Directory.prototype.files = function() {
|
184
|
+
return this.collection.filter(function(node) {
|
185
|
+
return node.isFile();
|
186
|
+
});
|
187
|
+
};
|
188
|
+
|
189
|
+
Directory.prototype.getFile = function(filePath) {
|
190
|
+
var first, match, rest, _ref;
|
191
|
+
_ref = filePath.split('/'), first = _ref[0], rest = 2 <= _ref.length ? __slice.call(_ref, 1) : [];
|
192
|
+
match = this.collection.find(function(node) {
|
193
|
+
return node.name() === first;
|
194
|
+
});
|
195
|
+
if (match != null ? match.isDirectory() : void 0) {
|
196
|
+
if (rest.length) {
|
197
|
+
return match.getFile(rest.join('/'));
|
198
|
+
} else {
|
199
|
+
return void 0;
|
200
|
+
}
|
201
|
+
} else {
|
202
|
+
return match;
|
203
|
+
}
|
204
|
+
};
|
205
|
+
|
206
|
+
Directory.prototype.toArray = function() {
|
207
|
+
var results,
|
208
|
+
_this = this;
|
209
|
+
results = [this];
|
210
|
+
this.collection.each(function(node) {
|
211
|
+
return results = results.concat(node.toArray());
|
212
|
+
});
|
213
|
+
return results;
|
214
|
+
};
|
215
|
+
|
216
|
+
Directory.prototype.toAscii = function(indentation) {
|
217
|
+
var nodeAscii;
|
218
|
+
if (indentation == null) {
|
219
|
+
indentation = '';
|
220
|
+
}
|
221
|
+
nodeAscii = ["" + indentation + "+" + (this.name())];
|
222
|
+
this.collection.each(function(node) {
|
223
|
+
return nodeAscii.push(node.toAscii(indentation + ' '));
|
224
|
+
});
|
225
|
+
return nodeAscii.join('\n');
|
226
|
+
};
|
227
|
+
|
228
|
+
Directory.prototype.updateChildren = function(previousPath, newPath) {
|
229
|
+
var directoryPath,
|
230
|
+
_this = this;
|
231
|
+
this.directories().each(function(directory) {
|
232
|
+
return directory.updateChildren(previousPath, newPath);
|
233
|
+
});
|
234
|
+
directoryPath = this.get('path');
|
235
|
+
if (directoryPath.indexOf(newPath) === -1) {
|
236
|
+
this.set({
|
237
|
+
path: this.get('path').replace(previousPath, newPath)
|
238
|
+
});
|
239
|
+
}
|
240
|
+
return this.files().each(function(file) {
|
241
|
+
var filePath;
|
242
|
+
filePath = file.get('path');
|
243
|
+
if (filePath.indexOf(newPath) === -1) {
|
244
|
+
return file.set({
|
245
|
+
path: file.get('path').replace(previousPath, newPath)
|
246
|
+
});
|
247
|
+
}
|
240
248
|
});
|
241
249
|
};
|
242
250
|
|
243
251
|
return Directory;
|
244
252
|
|
245
253
|
})(Models.Node);
|
246
|
-
return Models.Directory.find = function(currentDirectory, name) {
|
247
|
-
/*
|
248
|
-
Internal: Check to see if there is a directory with the matching name
|
249
|
-
contained within currentDirectory.
|
250
|
-
|
251
|
-
* currentDirectory - A Directory object to search for the matching directory name.
|
252
|
-
|
253
|
-
* name - A String name used to check for matching directory
|
254
|
-
names in currentDirectory.
|
255
|
-
|
256
|
-
Returns The Directory object with the matching name if it exists and undefined otherwise.
|
257
|
-
*/
|
258
|
-
return currentDirectory.collection.find(function(dir) {
|
259
|
-
return dir.get('name') === name;
|
260
|
-
});
|
261
|
-
};
|
262
254
|
});
|
263
255
|
|
264
256
|
}).call(this);
|
265
257
|
(function() {
|
266
|
-
var
|
267
|
-
|
268
|
-
|
258
|
+
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
259
|
+
__hasProp = {}.hasOwnProperty,
|
260
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
269
261
|
|
270
262
|
BoneTree.namespace("BoneTree.Models", function(Models) {
|
271
|
-
Models.File = (function(_super) {
|
263
|
+
return Models.File = (function(_super) {
|
272
264
|
|
273
265
|
__extends(File, _super);
|
274
266
|
|
275
|
-
File.name = 'File';
|
276
|
-
|
277
267
|
function File() {
|
268
|
+
this.toAscii = __bind(this.toAscii, this);
|
269
|
+
|
270
|
+
this.toArray = __bind(this.toArray, this);
|
278
271
|
return File.__super__.constructor.apply(this, arguments);
|
279
272
|
}
|
280
273
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
* nodeType - A String denoting what type of node this object is.
|
291
|
-
The two types are "file" and "directory".
|
292
|
-
*/
|
293
|
-
|
294
|
-
|
295
|
-
File.prototype.defaults = {
|
296
|
-
name: "New File",
|
297
|
-
sortPriority: "1",
|
298
|
-
nodeType: "file"
|
274
|
+
File.prototype.toArray = function() {
|
275
|
+
return [this];
|
276
|
+
};
|
277
|
+
|
278
|
+
File.prototype.toAscii = function(indentation) {
|
279
|
+
if (indentation == null) {
|
280
|
+
indentation = '';
|
281
|
+
}
|
282
|
+
return "" + indentation + "-" + (this.name());
|
299
283
|
};
|
300
284
|
|
301
285
|
return File;
|
302
286
|
|
303
287
|
})(Models.Node);
|
304
|
-
return Models.File.createFromFileName = function(fileName, fileData) {
|
305
|
-
/*
|
306
|
-
Public: Class method to create a new File object based on the fileName
|
307
|
-
and fileData passed in.
|
308
|
-
|
309
|
-
* fileName - A String representing the name of the file to be created.
|
310
|
-
files with '.' in the name will be parsed out and only the
|
311
|
-
string after the final '.' will be considered the extension.
|
312
|
-
|
313
|
-
* fileData - An Object of attributes to associate with the file.
|
314
|
-
|
315
|
-
Examples
|
316
|
-
|
317
|
-
data = {
|
318
|
-
contents: alert 'this is the code in the file'
|
319
|
-
createdAt: 1330846900589
|
320
|
-
language: 'CoffeeScript'
|
321
|
-
}
|
322
|
-
|
323
|
-
BoneTree.Models.File.createFromFileName('example.coffee', data)
|
324
|
-
# => <File>
|
325
|
-
|
326
|
-
Returns the File object just created.
|
327
|
-
*/
|
328
|
-
|
329
|
-
var data, extension, name, names, _i, _ref;
|
330
|
-
_ref = fileName.split("."), names = 2 <= _ref.length ? __slice.call(_ref, 0, _i = _ref.length - 1) : (_i = 0, []), extension = _ref[_i++];
|
331
|
-
name = names.join('.');
|
332
|
-
data = _.extend({}, fileData, {
|
333
|
-
name: name,
|
334
|
-
extension: extension
|
335
|
-
});
|
336
|
-
return new Models.File(data);
|
337
|
-
};
|
338
288
|
});
|
339
289
|
|
340
290
|
}).call(this);
|
341
291
|
(function() {
|
342
292
|
var __hasProp = {}.hasOwnProperty,
|
343
|
-
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; };
|
293
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
344
294
|
|
345
295
|
BoneTree.namespace("BoneTree.Models", function(Models) {
|
346
296
|
return Models.Settings = (function(_super) {
|
347
297
|
|
348
298
|
__extends(Settings, _super);
|
349
299
|
|
350
|
-
Settings.name = 'Settings';
|
351
|
-
|
352
300
|
function Settings() {
|
353
301
|
return Settings.__super__.constructor.apply(this, arguments);
|
354
302
|
}
|
355
303
|
|
356
|
-
/*
|
357
|
-
Internal: A configuration object. Consumers of the API don't need to
|
358
|
-
worry about this. It is used internally to manage the options
|
359
|
-
passed into the file tree.
|
360
|
-
|
361
|
-
* defaults
|
362
|
-
* beforeAdd - A Function that is invoked before each file is added to the tree.
|
363
|
-
It is passed the raw file attributes and should return true if
|
364
|
-
that file should be added to the tree and false if not. The
|
365
|
-
default implementation is to return true.
|
366
|
-
* confirmDeletes - A Boolean. If true, the tree will prompt the user, making
|
367
|
-
sure they want to delete the file (default: false).
|
368
|
-
* showExtensions - A Boolean. If true, files display their extensions. Internally,
|
369
|
-
extensions are always kept track of but by default they are
|
370
|
-
hidden (default: false).
|
371
|
-
* viewCache - An Object that stores views when they are created and is used
|
372
|
-
to look them up to prevent extra views from being created.
|
373
|
-
*/
|
374
|
-
|
375
|
-
|
376
304
|
Settings.prototype.defaults = {
|
377
305
|
confirmDeletes: false,
|
378
|
-
showExtensions: false
|
379
|
-
viewCache: {}
|
306
|
+
showExtensions: false
|
380
307
|
};
|
381
308
|
|
382
309
|
return Settings;
|
@@ -388,16 +315,16 @@
|
|
388
315
|
(function() {
|
389
316
|
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
390
317
|
__hasProp = {}.hasOwnProperty,
|
391
|
-
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; };
|
318
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
392
319
|
|
393
320
|
BoneTree.namespace("BoneTree.Views", function(Views) {
|
394
321
|
return Views.Directory = (function(_super) {
|
395
322
|
|
396
323
|
__extends(Directory, _super);
|
397
324
|
|
398
|
-
Directory.name = 'Directory';
|
399
|
-
|
400
325
|
function Directory() {
|
326
|
+
this.toggleOpen = __bind(this.toggleOpen, this);
|
327
|
+
|
401
328
|
this.displayChildren = __bind(this.displayChildren, this);
|
402
329
|
|
403
330
|
this.render = __bind(this.render, this);
|
@@ -406,80 +333,59 @@
|
|
406
333
|
return Directory.__super__.constructor.apply(this, arguments);
|
407
334
|
}
|
408
335
|
|
409
|
-
/*
|
410
|
-
Internal: View that renders a Directory node and controls its behavior (class: 'directory', tag: 'ul').
|
411
|
-
*/
|
412
|
-
|
413
|
-
|
414
336
|
Directory.prototype.className = 'directory';
|
415
337
|
|
416
338
|
Directory.prototype.tagName = 'ul';
|
417
339
|
|
418
340
|
Directory.prototype.initialize = function(options) {
|
419
|
-
/*
|
420
|
-
Internal: Initialize a new directory node. Adds associated model cid to the
|
421
|
-
view element. Binds change handler to the `change:open` event that
|
422
|
-
toggles the display of directory contents. Binds change handler to
|
423
|
-
the `change:name` event that re-renders a sorted file tree.
|
424
|
-
|
425
|
-
* options - Passes in settings object, which is used for access to the
|
426
|
-
tree view root in order to proxy events to it.
|
427
|
-
*/
|
428
|
-
|
429
341
|
var _this = this;
|
430
|
-
this.
|
342
|
+
this.tree = options.tree;
|
431
343
|
this.$el.attr('data-cid', this.model.cid);
|
432
|
-
this.
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
344
|
+
this.open = false;
|
345
|
+
this.model.bind('change:path', function(model) {
|
346
|
+
var newPath, path, previousPath;
|
347
|
+
_this.tree.render().trigger('rename', model, name);
|
348
|
+
previousPath = model.previous('path');
|
349
|
+
if ((path = model.get('path')).indexOf('/') === 0) {
|
350
|
+
newPath = path.replace('/', '');
|
351
|
+
} else {
|
352
|
+
newPath = path;
|
353
|
+
}
|
354
|
+
return model.updateChildren(previousPath, newPath);
|
439
355
|
});
|
440
356
|
this.model.collection.bind('add', this.render);
|
441
357
|
this.model.collection.bind('remove', function(model, collection) {
|
442
|
-
_this.
|
358
|
+
_this.tree.trigger('remove', model);
|
443
359
|
return _this.render();
|
444
360
|
});
|
445
|
-
return this.displayChildren(this.
|
361
|
+
return this.displayChildren(this.open);
|
446
362
|
};
|
447
363
|
|
448
364
|
Directory.prototype.appendView = function(node) {
|
449
|
-
/*
|
450
|
-
Internal: Appends a view based on the underlying node model to this view.
|
451
|
-
|
452
|
-
node - A Node model. Either a File or a Directory. This is the model the
|
453
|
-
created view will be associated with.
|
454
|
-
*/
|
455
|
-
|
456
365
|
var view;
|
457
|
-
view = this.
|
366
|
+
view = this.tree.findOrCreateView(node);
|
458
367
|
return this.$el.append(view.render().$el);
|
459
368
|
};
|
460
369
|
|
461
370
|
Directory.prototype.render = function() {
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
Returns `this` view.
|
466
|
-
*/
|
467
|
-
this.$el.text(this.model.get('name'));
|
468
|
-
this.model.collection.sort().each(this.appendView);
|
371
|
+
this.$el.text(this.model.name());
|
372
|
+
this.model.collection.each(this.appendView);
|
373
|
+
this.displayChildren(this.$el.hasClass('open'));
|
469
374
|
return this;
|
470
375
|
};
|
471
376
|
|
472
377
|
Directory.prototype.displayChildren = function(open) {
|
473
|
-
/*
|
474
|
-
Internal: Toggles display of the children Files or Diretories of this view.
|
475
|
-
*/
|
476
|
-
|
477
378
|
var fileDirChildren;
|
478
379
|
fileDirChildren = this.$el.children('.directory, .file');
|
479
380
|
this.$el.toggleClass('open', open);
|
480
381
|
return fileDirChildren.toggle(open);
|
481
382
|
};
|
482
383
|
|
384
|
+
Directory.prototype.toggleOpen = function() {
|
385
|
+
this.open = !this.open;
|
386
|
+
return this.displayChildren(this.open);
|
387
|
+
};
|
388
|
+
|
483
389
|
return Directory;
|
484
390
|
|
485
391
|
})(Backbone.View);
|
@@ -489,70 +395,39 @@
|
|
489
395
|
(function() {
|
490
396
|
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
491
397
|
__hasProp = {}.hasOwnProperty,
|
492
|
-
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; };
|
398
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
493
399
|
|
494
400
|
BoneTree.namespace("BoneTree.Views", function(Views) {
|
495
401
|
return Views.File = (function(_super) {
|
496
402
|
|
497
403
|
__extends(File, _super);
|
498
404
|
|
499
|
-
File.name = 'File';
|
500
|
-
|
501
405
|
function File() {
|
502
406
|
this.render = __bind(this.render, this);
|
503
407
|
return File.__super__.constructor.apply(this, arguments);
|
504
408
|
}
|
505
409
|
|
506
|
-
/*
|
507
|
-
Internal: View that renders a File node and controls its behavior (class: 'file', tag: 'li').
|
508
|
-
*/
|
509
|
-
|
510
|
-
|
511
|
-
File.prototype.className = 'file';
|
512
|
-
|
513
410
|
File.prototype.tagName = 'li';
|
514
411
|
|
515
412
|
File.prototype.initialize = function(options) {
|
516
|
-
/*
|
517
|
-
Internal: Initialize a new file node. Adds associated model cid to the
|
518
|
-
view element. Binds change handlers to the `change:name` and
|
519
|
-
`change:extension` events. These take care of resorting the file
|
520
|
-
nodes.
|
521
|
-
|
522
|
-
* options - Passes in settings object, which is used to control
|
523
|
-
whether or not file extensions are shown.
|
524
|
-
*/
|
525
|
-
|
526
413
|
var _this = this;
|
527
414
|
this.settings = options.settings;
|
528
|
-
this
|
529
|
-
this.model.bind('change:
|
530
|
-
|
531
|
-
treeView = _this.settings.get('treeView');
|
532
|
-
return treeView.render().trigger('rename', model, model.nameWithExtension());
|
533
|
-
});
|
534
|
-
return this.model.bind('change:extension', function(model, extension) {
|
535
|
-
var treeView;
|
536
|
-
_this.$el.attr('class', "file " + extension);
|
537
|
-
treeView = _this.settings.get('treeView');
|
538
|
-
return treeView.render().trigger('rename', model, model.nameWithExtension());
|
415
|
+
this.tree = options.tree;
|
416
|
+
return this.model.bind('change:path', function(model) {
|
417
|
+
return _this.render();
|
539
418
|
});
|
540
419
|
};
|
541
420
|
|
542
421
|
File.prototype.render = function() {
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
*/
|
549
|
-
if (this.model.get('hidden')) {
|
550
|
-
return "";
|
551
|
-
}
|
422
|
+
var extension, name;
|
423
|
+
name = this.model.name();
|
424
|
+
extension = name.extension();
|
425
|
+
this.$el.attr('data-cid', this.model.cid);
|
426
|
+
this.$el.attr('class', "file " + extension);
|
552
427
|
if (this.settings.get('showExtensions')) {
|
553
|
-
this.$el.text(
|
428
|
+
this.$el.text(name);
|
554
429
|
} else {
|
555
|
-
this.$el.text(
|
430
|
+
this.$el.text(name.withoutExtension());
|
556
431
|
}
|
557
432
|
return this;
|
558
433
|
};
|
@@ -566,130 +441,7 @@
|
|
566
441
|
(function() {
|
567
442
|
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
568
443
|
__hasProp = {}.hasOwnProperty,
|
569
|
-
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; };
|
570
|
-
|
571
|
-
BoneTree.namespace("BoneTree.Views", function(Views) {
|
572
|
-
return Views.Menu = (function(_super) {
|
573
|
-
|
574
|
-
__extends(Menu, _super);
|
575
|
-
|
576
|
-
Menu.name = 'Menu';
|
577
|
-
|
578
|
-
function Menu() {
|
579
|
-
this.render = __bind(this.render, this);
|
580
|
-
|
581
|
-
this.rename = __bind(this.rename, this);
|
582
|
-
|
583
|
-
this["delete"] = __bind(this["delete"], this);
|
584
|
-
|
585
|
-
this.contextMenu = __bind(this.contextMenu, this);
|
586
|
-
return Menu.__super__.constructor.apply(this, arguments);
|
587
|
-
}
|
588
|
-
|
589
|
-
/*
|
590
|
-
Internal: View that controls the context menu (class: 'filetree\_context\_menu').
|
591
|
-
|
592
|
-
Events
|
593
|
-
|
594
|
-
* contextMenu - Prevents the standard browser context menu from appearing
|
595
|
-
when right clicking within the file tree context menu.
|
596
|
-
|
597
|
-
* click .rename - Prompts the user to rename a file.
|
598
|
-
|
599
|
-
* click .delete - Deletes a node from the file tree.
|
600
|
-
*/
|
601
|
-
|
602
|
-
|
603
|
-
Menu.prototype.className = 'filetree_context_menu';
|
604
|
-
|
605
|
-
Menu.prototype.events = {
|
606
|
-
'contextmenu': 'contextMenu',
|
607
|
-
'click .rename': 'rename',
|
608
|
-
'click .delete': 'delete'
|
609
|
-
};
|
610
|
-
|
611
|
-
Menu.prototype.initialize = function(options) {
|
612
|
-
/*
|
613
|
-
Internal: Initialize a new menu widget.
|
614
|
-
|
615
|
-
* options - An Object. Internally used to pass the settings configuration
|
616
|
-
into the menu. This controls whether or not the user is
|
617
|
-
prompted to confirm deleting a file.
|
618
|
-
*/
|
619
|
-
return this.settings = options.settings;
|
620
|
-
};
|
621
|
-
|
622
|
-
Menu.prototype.contextMenu = function(e) {
|
623
|
-
/*
|
624
|
-
Internal: Kill the default browser behavior for the contextmenu event.
|
625
|
-
*/
|
626
|
-
e.preventDefault();
|
627
|
-
return e.stopPropagation();
|
628
|
-
};
|
629
|
-
|
630
|
-
Menu.prototype["delete"] = function(e) {
|
631
|
-
/*
|
632
|
-
Internal: Deletes a node from the file tree. If the confirmDeletes setting
|
633
|
-
is set, prompts the user for delete confirmation.
|
634
|
-
*/
|
635
|
-
if (this.settings.get('confirmDeletes')) {
|
636
|
-
if (confirm("Are you sure you want to delete '" + (this.model.nameWithExtension()) + "'?")) {
|
637
|
-
this.model.destroy();
|
638
|
-
}
|
639
|
-
} else {
|
640
|
-
this.model.destroy();
|
641
|
-
}
|
642
|
-
return this.$el.hide();
|
643
|
-
};
|
644
|
-
|
645
|
-
Menu.prototype.rename = function(e) {
|
646
|
-
/*
|
647
|
-
Internal: Prompts the user to rename a File or Directory.
|
648
|
-
*/
|
649
|
-
|
650
|
-
var extension, fileName, newName, _ref;
|
651
|
-
if (newName = prompt("New Name", this.model.nameWithExtension())) {
|
652
|
-
_ref = newName.split("."), fileName = _ref[0], extension = _ref[1];
|
653
|
-
if (extension == null) {
|
654
|
-
extension = "";
|
655
|
-
}
|
656
|
-
this.model.set({
|
657
|
-
name: fileName,
|
658
|
-
extension: extension
|
659
|
-
});
|
660
|
-
}
|
661
|
-
return this.$el.hide();
|
662
|
-
};
|
663
|
-
|
664
|
-
Menu.prototype.render = function() {
|
665
|
-
/*
|
666
|
-
Internal: Renders the <ul> that contains the context menu choices
|
667
|
-
'Rename' and 'Delete'.
|
668
|
-
|
669
|
-
Returns `this`, the menu view.
|
670
|
-
*/
|
671
|
-
this.$el.html(this.template());
|
672
|
-
return this;
|
673
|
-
};
|
674
|
-
|
675
|
-
Menu.prototype.template = function() {
|
676
|
-
/*
|
677
|
-
Internal: html template for the context menu.
|
678
|
-
*/
|
679
|
-
return "<ul>\n <li class='rename'>Rename</li>\n <hr/>\n <li class='delete'>Delete</li>\n</ul>";
|
680
|
-
};
|
681
|
-
|
682
|
-
return Menu;
|
683
|
-
|
684
|
-
})(Backbone.View);
|
685
|
-
});
|
686
|
-
|
687
|
-
}).call(this);
|
688
|
-
(function() {
|
689
|
-
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
690
|
-
__hasProp = {}.hasOwnProperty,
|
691
|
-
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; },
|
692
|
-
__slice = [].slice;
|
444
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
693
445
|
|
694
446
|
BoneTree.namespace("BoneTree.Views", function(Views) {
|
695
447
|
var Models;
|
@@ -698,8 +450,6 @@
|
|
698
450
|
|
699
451
|
__extends(Tree, _super);
|
700
452
|
|
701
|
-
Tree.name = 'Tree';
|
702
|
-
|
703
453
|
function Tree() {
|
704
454
|
this.render = __bind(this.render, this);
|
705
455
|
|
@@ -707,78 +457,38 @@
|
|
707
457
|
|
708
458
|
this._openDirectory = __bind(this._openDirectory, this);
|
709
459
|
|
710
|
-
this.
|
460
|
+
this.getViewFromClick = __bind(this.getViewFromClick, this);
|
711
461
|
|
712
462
|
this.toAscii = __bind(this.toAscii, this);
|
713
463
|
|
714
|
-
this.
|
715
|
-
|
716
|
-
this._getFile = __bind(this._getFile, this);
|
464
|
+
this.getFile = __bind(this.getFile, this);
|
717
465
|
|
718
466
|
this.getDirectory = __bind(this.getDirectory, this);
|
719
467
|
|
720
|
-
this.
|
721
|
-
|
722
|
-
this.filterNodes = __bind(this.filterNodes, this);
|
723
|
-
|
724
|
-
this._contextMenu = __bind(this._contextMenu, this);
|
725
|
-
|
726
|
-
this._closeMenu = __bind(this._closeMenu, this);
|
727
|
-
|
728
|
-
this.closeDirectories = __bind(this.closeDirectories, this);
|
729
|
-
|
730
|
-
this.getModelByCid = __bind(this.getModelByCid, this);
|
468
|
+
this.toArray = __bind(this.toArray, this);
|
731
469
|
|
732
470
|
this.findOrCreateView = __bind(this.findOrCreateView, this);
|
733
471
|
|
734
|
-
this.
|
735
|
-
|
736
|
-
this.addFromJSON = __bind(this.addFromJSON, this);
|
472
|
+
this.remove = __bind(this.remove, this);
|
737
473
|
|
738
|
-
this.
|
474
|
+
this.add = __bind(this.add, this);
|
739
475
|
return Tree.__super__.constructor.apply(this, arguments);
|
740
476
|
}
|
741
477
|
|
742
|
-
/*
|
743
|
-
Public: The base tree object. Events from other objects are proxied to the tree
|
744
|
-
so API consumers only need to know about this top level object.
|
745
|
-
*/
|
746
|
-
|
747
|
-
|
748
478
|
Tree.prototype.className = 'tree';
|
749
479
|
|
750
480
|
Tree.prototype.events = {
|
751
|
-
'
|
752
|
-
'
|
753
|
-
'click .directory': '_openDirectory',
|
754
|
-
'click .file': '_openFile'
|
481
|
+
'mousedown .directory': '_openDirectory',
|
482
|
+
'mousedown .file': '_openFile'
|
755
483
|
};
|
756
484
|
|
757
485
|
Tree.prototype.initialize = function() {
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
sure they want to delete the file (default: false).
|
764
|
-
* showExtensions - A Boolean. If true, files display their extensions. Internally,
|
765
|
-
extensions are always kept track of but by default they are
|
766
|
-
hidden (default: false).
|
767
|
-
*/
|
768
|
-
|
769
|
-
var settingsConfig,
|
770
|
-
_this = this;
|
771
|
-
$(document).click(this._closeMenu);
|
772
|
-
this._currentFileData = null;
|
773
|
-
settingsConfig = _.extend({}, this.options, {
|
774
|
-
treeView: this
|
775
|
-
});
|
776
|
-
this.settings = new Models.Settings(settingsConfig);
|
777
|
-
this.menuView = new Views.Menu({
|
778
|
-
settings: this.settings
|
486
|
+
var _this = this;
|
487
|
+
this.viewCache = {};
|
488
|
+
this.settings = new Models.Settings(this.options);
|
489
|
+
this.root = new Models.Directory({
|
490
|
+
path: '/'
|
779
491
|
});
|
780
|
-
this.menuView.render().$el.appendTo($('body'));
|
781
|
-
this.root = new Models.Node;
|
782
492
|
this.root.collection.bind('add', this.render);
|
783
493
|
return this.root.collection.bind('remove', function(model, collection) {
|
784
494
|
_this.$("[data-cid='" + model.cid + "']").remove();
|
@@ -787,497 +497,83 @@
|
|
787
497
|
});
|
788
498
|
};
|
789
499
|
|
790
|
-
Tree.prototype.
|
791
|
-
var
|
792
|
-
if (filePath
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
path: filePath
|
798
|
-
});
|
799
|
-
if (this._currentFileData.autoOpen == null) {
|
800
|
-
this._currentFileData.autoOpen = true;
|
801
|
-
}
|
802
|
-
if (this._currentFileData.hidden == null) {
|
803
|
-
this._currentFileData.hidden = false;
|
500
|
+
Tree.prototype.add = function(filePath, fileData) {
|
501
|
+
var file, _i, _len, _results;
|
502
|
+
if (Object.isArray(filePath)) {
|
503
|
+
_results = [];
|
504
|
+
for (_i = 0, _len = filePath.length; _i < _len; _i++) {
|
505
|
+
file = filePath[_i];
|
506
|
+
_results.push(this.add(file.path, file));
|
804
507
|
}
|
508
|
+
return _results;
|
805
509
|
} else {
|
806
|
-
return this.
|
807
|
-
}
|
808
|
-
_ref = filePath.split('/'), dirs = 2 <= _ref.length ? __slice.call(_ref, 0, _i = _ref.length - 1) : (_i = 0, []), fileName = _ref[_i++];
|
809
|
-
if (file = this._getFile(filePath)) {
|
810
|
-
return file.set(this._currentFileData);
|
811
|
-
} else {
|
812
|
-
return this.addToTree(this.root, dirs, fileName);
|
510
|
+
return this.root.add(filePath, fileData);
|
813
511
|
}
|
814
512
|
};
|
815
513
|
|
816
|
-
Tree.prototype.
|
817
|
-
|
818
|
-
if (currentPath == null) {
|
819
|
-
currentPath = "";
|
820
|
-
}
|
821
|
-
/*
|
822
|
-
Public: Creates a file tree from a JSON representation. Expects the
|
823
|
-
JSON object to have a `name` property at each level, specifying
|
824
|
-
the name of the file or directory, and a files array if the
|
825
|
-
current node has child directories or files.
|
826
|
-
|
827
|
-
* data - An Object that represents hierarchical file data.
|
828
|
-
|
829
|
-
* currentPath - A String representing the current location in the tree.
|
830
|
-
Defaults to the file tree root. (default: "")
|
831
|
-
|
832
|
-
Examples
|
833
|
-
|
834
|
-
data = {
|
835
|
-
name: "My Project"
|
836
|
-
files: [
|
837
|
-
{ name: "Empty Folder" }
|
838
|
-
{ name: "SomeFile.coffee" }
|
839
|
-
{ name: "AnotherFile.coffee" }
|
840
|
-
{
|
841
|
-
name: "Folder with Files inside"
|
842
|
-
files: [
|
843
|
-
{ name: "NestedFile.coffee" }
|
844
|
-
]
|
845
|
-
}
|
846
|
-
]
|
847
|
-
}
|
848
|
-
|
849
|
-
tree.addFromJSON(data)
|
850
|
-
# => <Tree>
|
851
|
-
|
852
|
-
Returns the Tree view object.
|
853
|
-
*/
|
854
|
-
|
855
|
-
name = "";
|
856
|
-
if (data.name != null) {
|
857
|
-
name = data.name + '/';
|
858
|
-
delete data.name;
|
859
|
-
}
|
860
|
-
if (data.extension != null) {
|
861
|
-
name = name.replace('/', '.' + data.extension);
|
862
|
-
delete data.extension;
|
863
|
-
}
|
864
|
-
currentPath += name;
|
865
|
-
if (data.files != null) {
|
866
|
-
_ref = data.files;
|
867
|
-
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
868
|
-
file = _ref[_i];
|
869
|
-
this.addFromJSON(file, currentPath);
|
870
|
-
}
|
871
|
-
} else {
|
872
|
-
this.file(currentPath, data);
|
873
|
-
}
|
874
|
-
return this;
|
514
|
+
Tree.prototype.remove = function(path) {
|
515
|
+
return this.root.remove(path);
|
875
516
|
};
|
876
517
|
|
877
|
-
Tree.prototype.
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
* currentDirectory - A Node object representing which directory we are
|
883
|
-
adding the current Directory or File to.
|
884
|
-
* remainingDirectories - A '/' separated String representing the remaining
|
885
|
-
directories to add.
|
886
|
-
* fileName - The String name of the file to be added. This can
|
887
|
-
include the extension name separated by a '.'.
|
888
|
-
|
889
|
-
Examples
|
890
|
-
|
891
|
-
tree.addToTree(@root, '/source/subdirectory/', 'main.coffee')
|
892
|
-
# => <File>
|
893
|
-
|
894
|
-
Returns the File object if it was created and null if no file was given.
|
895
|
-
*/
|
896
|
-
|
897
|
-
var file, matchingDirectory, newDirectory, newNode, nextDirectoryName;
|
898
|
-
if (remainingDirectories.length) {
|
899
|
-
nextDirectoryName = remainingDirectories.shift();
|
900
|
-
if (matchingDirectory = Models.Directory.find(currentDirectory, nextDirectoryName)) {
|
901
|
-
matchingDirectory.set({
|
902
|
-
open: true
|
903
|
-
});
|
904
|
-
return this.addToTree(matchingDirectory, remainingDirectories, fileName);
|
905
|
-
} else {
|
906
|
-
newNode = new Models.Directory({
|
907
|
-
name: nextDirectoryName,
|
908
|
-
open: true
|
909
|
-
});
|
910
|
-
newDirectory = currentDirectory.collection.add(newNode);
|
911
|
-
return this.addToTree(newNode, remainingDirectories, fileName);
|
912
|
-
}
|
518
|
+
Tree.prototype.findOrCreateView = function(node) {
|
519
|
+
var type, view;
|
520
|
+
if (node.isDirectory()) {
|
521
|
+
type = 'Directory';
|
913
522
|
} else {
|
914
|
-
|
915
|
-
return null;
|
916
|
-
}
|
917
|
-
file = Models.File.createFromFileName(fileName, this._currentFileData);
|
918
|
-
this._currentFileData = null;
|
919
|
-
currentDirectory.collection.add(file);
|
920
|
-
if (file.get('autoOpen')) {
|
921
|
-
this.trigger('openFile', file);
|
922
|
-
}
|
923
|
-
return file;
|
523
|
+
type = 'File';
|
924
524
|
}
|
925
|
-
|
926
|
-
|
927
|
-
Tree.prototype.findOrCreateView = function(node) {
|
928
|
-
/*
|
929
|
-
Internal: Look up existing view in the view cache or Create a new view
|
930
|
-
of the correct type (either File or Directory).
|
931
|
-
|
932
|
-
* node - A Node object. Either a File object or a Directory object.
|
933
|
-
This is the model that the view will be associated with.
|
934
|
-
|
935
|
-
Examples
|
936
|
-
|
937
|
-
file = new BoneTree.Models.File
|
938
|
-
|
939
|
-
# This will create a new view since we just created the File
|
940
|
-
tree.findOrCreateView(file)
|
941
|
-
# => <FileView>
|
942
|
-
|
943
|
-
Returns the view corresponding to the model passed in.
|
944
|
-
*/
|
945
|
-
|
946
|
-
var type, view, viewCache;
|
947
|
-
type = node.constantize();
|
948
|
-
viewCache = this.settings.get('viewCache');
|
949
|
-
if (!(view = viewCache[node.cid])) {
|
950
|
-
view = viewCache[node.cid] = new Views[type]({
|
525
|
+
if (!(view = this.viewCache[node.cid])) {
|
526
|
+
view = this.viewCache[node.cid] = new Views[type]({
|
951
527
|
model: node,
|
952
|
-
settings: this.settings
|
528
|
+
settings: this.settings,
|
529
|
+
tree: this
|
953
530
|
});
|
954
531
|
}
|
955
532
|
return view;
|
956
533
|
};
|
957
534
|
|
958
|
-
Tree.prototype.
|
959
|
-
|
960
|
-
viewCache = this.settings.get('viewCache');
|
961
|
-
for (modelCid in viewCache) {
|
962
|
-
view = viewCache[modelCid];
|
963
|
-
if (modelCid === cid) {
|
964
|
-
return view.model;
|
965
|
-
}
|
966
|
-
}
|
535
|
+
Tree.prototype.toArray = function() {
|
536
|
+
return this.root.toArray();
|
967
537
|
};
|
968
538
|
|
969
|
-
Tree.prototype.
|
970
|
-
|
971
|
-
Public: Close all the directories in the file tree.
|
972
|
-
|
973
|
-
Examples
|
974
|
-
|
975
|
-
tree.closeDirectories()
|
976
|
-
# => <Tree>
|
977
|
-
|
978
|
-
Returns the Tree view object.
|
979
|
-
*/
|
980
|
-
|
981
|
-
var directories;
|
982
|
-
directories = _.filter(this.flatten(), function(node) {
|
983
|
-
return node.get('nodeType') === 'directory';
|
984
|
-
});
|
985
|
-
_.invoke(directories, 'set', {
|
986
|
-
open: false
|
987
|
-
});
|
988
|
-
return this;
|
539
|
+
Tree.prototype.getDirectory = function(directoryPath) {
|
540
|
+
return this.root.getDirectory(directoryPath);
|
989
541
|
};
|
990
542
|
|
991
|
-
Tree.prototype.
|
992
|
-
|
993
|
-
Internal: Close the context menu. This is called every click on
|
994
|
-
the document and closes the menu unless you are clicking
|
995
|
-
within it. This shouldn't be called directly, it is called
|
996
|
-
automatically by Backbone from user interactions.
|
997
|
-
|
998
|
-
Returns the Menu view object.
|
999
|
-
*/
|
1000
|
-
if (!$(e.currentTarget).is('.menu')) {
|
1001
|
-
this.menuView.$el.hide();
|
1002
|
-
}
|
1003
|
-
return this.menuView;
|
543
|
+
Tree.prototype.getFile = function(filePath) {
|
544
|
+
return this.root.getFile(filePath);
|
1004
545
|
};
|
1005
546
|
|
1006
|
-
Tree.prototype.
|
1007
|
-
|
1008
|
-
Internal: Open the context menu. This prevents the default browser
|
1009
|
-
context menu event. This shouldn't be called directly, it is
|
1010
|
-
called automatically by Backbone from user interations.
|
1011
|
-
|
1012
|
-
Returns the Menu view object.
|
1013
|
-
*/
|
1014
|
-
|
1015
|
-
var model;
|
1016
|
-
e.preventDefault();
|
1017
|
-
model = this.getModelFromClick(e);
|
1018
|
-
this.menuView.model = model;
|
1019
|
-
this.menuView.$el.css({
|
1020
|
-
left: e.pageX,
|
1021
|
-
top: e.pageY
|
1022
|
-
}).show();
|
1023
|
-
return this.menuView;
|
547
|
+
Tree.prototype.toAscii = function() {
|
548
|
+
return '\n' + this.root.toAscii();
|
1024
549
|
};
|
1025
550
|
|
1026
|
-
Tree.prototype.
|
1027
|
-
/*
|
1028
|
-
Internal: Returns file tree nodes that match the nodeType and nodeName.
|
1029
|
-
|
1030
|
-
* nodeType - A String that represents the nodeType to match. Choices are
|
1031
|
-
'file' or 'directory'.
|
1032
|
-
* nodeName - A String that represents the name of the node to match.
|
1033
|
-
|
1034
|
-
Examples
|
1035
|
-
|
1036
|
-
# Add some files to the tree
|
1037
|
-
tree.file('/source/main.coffee')
|
1038
|
-
tree.file('/source/player.coffee')
|
1039
|
-
|
1040
|
-
# returns an array containing the File 'main.coffee'
|
1041
|
-
tree.filterNodes('file', 'main')
|
1042
|
-
# => [<File>]
|
1043
|
-
|
1044
|
-
Returns an Array of nodes that match the filter criteria.
|
1045
|
-
*/
|
1046
|
-
|
1047
|
-
var results,
|
1048
|
-
_this = this;
|
1049
|
-
results = _.filter(this.flatten(), function(node) {
|
1050
|
-
return node.get('nodeType') === nodeType && node.get('name') === nodeName;
|
1051
|
-
});
|
1052
|
-
return results;
|
1053
|
-
};
|
1054
|
-
|
1055
|
-
Tree.prototype.flatten = function(currentNode, results) {
|
1056
|
-
var _this = this;
|
1057
|
-
if (currentNode == null) {
|
1058
|
-
currentNode = this.root;
|
1059
|
-
}
|
1060
|
-
if (results == null) {
|
1061
|
-
results = [];
|
1062
|
-
}
|
1063
|
-
/*
|
1064
|
-
Internal: Returns a one dimensional ordered array representing the
|
1065
|
-
Directory and File nodes in the tree.
|
1066
|
-
|
1067
|
-
* currentNode - The node to start at when flattening
|
1068
|
-
* nodeName - A String that represents the name of the node to match.
|
1069
|
-
|
1070
|
-
Examples
|
1071
|
-
|
1072
|
-
# Add some files to the tree
|
1073
|
-
tree.file('/source/main.coffee', {aFile: true})
|
1074
|
-
tree.file('/source/player.coffee', {playerData: {x: 50, y: 30}})
|
1075
|
-
|
1076
|
-
# returns an array containing the File 'main.coffee'
|
1077
|
-
tree.filterNodes('file', 'main')
|
1078
|
-
# => [<File>]
|
1079
|
-
|
1080
|
-
Returns an Array of nodes that match the filter criteria.
|
1081
|
-
*/
|
1082
|
-
|
1083
|
-
currentNode.collection.each(function(node) {
|
1084
|
-
results.push(node);
|
1085
|
-
if (node.collection.length) {
|
1086
|
-
return _this.flatten(node, results);
|
1087
|
-
}
|
1088
|
-
});
|
1089
|
-
return results;
|
1090
|
-
};
|
1091
|
-
|
1092
|
-
Tree.prototype.getDirectory = function(directoryName) {
|
1093
|
-
/*
|
1094
|
-
Public: Returns an array of directories matching the given directoryName.
|
1095
|
-
|
1096
|
-
* directoryName - A String naming the directory to match.
|
1097
|
-
|
1098
|
-
Examples
|
1099
|
-
|
1100
|
-
# Add some files to the tree
|
1101
|
-
tree.file('/source/main.coffee', {size: 4039})
|
1102
|
-
tree.file('/source/player.coffee', {size: 399})
|
1103
|
-
tree.file('/directory2/file.coffee', {size: 23})
|
1104
|
-
|
1105
|
-
# returns an array containing the Directory 'source'
|
1106
|
-
tree.getDirectory('source')
|
1107
|
-
# => [<Directory>]
|
1108
|
-
|
1109
|
-
Returns an Array of Directory nodes that match directoryName.
|
1110
|
-
*/
|
1111
|
-
return this.filterNodes('directory', directoryName);
|
1112
|
-
};
|
1113
|
-
|
1114
|
-
Tree.prototype._getFile = function(filePath) {
|
1115
|
-
/*
|
1116
|
-
Internal: Returns a file at the specified location.
|
1117
|
-
|
1118
|
-
* fileName - A String describing the file path.
|
1119
|
-
|
1120
|
-
Examples
|
1121
|
-
|
1122
|
-
# Add some files to the tree
|
1123
|
-
tree.file('/source/main.coffee', {size: 30459})
|
1124
|
-
tree.file('/source/player.coffee', {size: 943})
|
1125
|
-
tree.file('/directory2/main.coffee', {size: 4945})
|
1126
|
-
|
1127
|
-
# returns an array containing both the files named main.
|
1128
|
-
tree._getFile('source/main.coffee')
|
1129
|
-
# => <File>
|
1130
|
-
|
1131
|
-
Returns a File at the given location.
|
1132
|
-
*/
|
1133
|
-
|
1134
|
-
var filtered, nodes;
|
1135
|
-
if (filePath[0] === '/') {
|
1136
|
-
filePath = filePath.replace('/', '');
|
1137
|
-
}
|
1138
|
-
nodes = this.flatten();
|
1139
|
-
filtered = _.filter(nodes, function(node) {
|
1140
|
-
return node.get('nodeType') === 'file' && node.get('path') === filePath;
|
1141
|
-
});
|
1142
|
-
return filtered[0];
|
1143
|
-
};
|
1144
|
-
|
1145
|
-
Tree.prototype.files = function(directoryName) {
|
1146
|
-
/*
|
1147
|
-
Public: Returns an array of files contained within the directory
|
1148
|
-
matching directoryName.
|
1149
|
-
|
1150
|
-
* directoryName - A String naming the directory to look inside.
|
1151
|
-
|
1152
|
-
Examples
|
1153
|
-
|
1154
|
-
# Add some files to the tree
|
1155
|
-
tree.file('/source/main.coffee', {main: true})
|
1156
|
-
tree.file('/source/player.coffee', {active: true})
|
1157
|
-
tree.file('/directory2/main.coffee', {active: true})
|
1158
|
-
|
1159
|
-
# returns an array containing the files 'player.coffee' and 'main.coffee'
|
1160
|
-
tree.files('source')
|
1161
|
-
# => [<File>, <File>]
|
1162
|
-
|
1163
|
-
Returns an Array of File nodes that are contained in the
|
1164
|
-
Directory matching directoryName.
|
1165
|
-
*/
|
1166
|
-
|
1167
|
-
var directory, nodesInDirectory;
|
1168
|
-
if (directoryName == null) {
|
1169
|
-
return _.filter(this.flatten(), function(node) {
|
1170
|
-
return node.get('nodeType') === 'file';
|
1171
|
-
});
|
1172
|
-
}
|
1173
|
-
directory = this.getDirectory(directoryName)[0];
|
1174
|
-
if (!directory) {
|
1175
|
-
return [];
|
1176
|
-
}
|
1177
|
-
nodesInDirectory = this.flatten(directory);
|
1178
|
-
return _.filter(nodesInDirectory, function(node) {
|
1179
|
-
return node.get('nodeType') === 'file';
|
1180
|
-
});
|
1181
|
-
};
|
1182
|
-
|
1183
|
-
Tree.prototype.toAscii = function(collection, indentation, output) {
|
1184
|
-
var n, rootCollection, spaces, _i,
|
1185
|
-
_this = this;
|
1186
|
-
if (indentation == null) {
|
1187
|
-
indentation = 0;
|
1188
|
-
}
|
1189
|
-
if (output == null) {
|
1190
|
-
output = "\n";
|
1191
|
-
}
|
1192
|
-
/*
|
1193
|
-
Internal: A String representation of the filetree.
|
1194
|
-
|
1195
|
-
* collection - A NodeCollection object describing which folder to start at.
|
1196
|
-
* indentation - A Number describing how many spaces to indent the next filetree element (default: 0).
|
1197
|
-
* output - A String representing the current filetree output (default: "\n").
|
1198
|
-
|
1199
|
-
Examples
|
1200
|
-
|
1201
|
-
# Add some files to the tree
|
1202
|
-
tree.file('/source/main.coffee', {main: true})
|
1203
|
-
tree.file('/source/player.coffee', {active: true})
|
1204
|
-
tree.file('/directory2/main.coffee', {active: false})
|
1205
|
-
|
1206
|
-
tree.toAscii()
|
1207
|
-
# => "
|
1208
|
-
-directory2
|
1209
|
-
-main.coffee
|
1210
|
-
-source
|
1211
|
-
-main.coffee
|
1212
|
-
-player.coffee
|
1213
|
-
"
|
1214
|
-
|
1215
|
-
Returns a String representation of the sorted nodes of the file tree.
|
1216
|
-
*/
|
1217
|
-
|
1218
|
-
rootCollection = collection || this.root.collection;
|
1219
|
-
spaces = "";
|
1220
|
-
for (n = _i = 0; 0 <= indentation ? _i <= indentation : _i >= indentation; n = 0 <= indentation ? ++_i : --_i) {
|
1221
|
-
spaces += " ";
|
1222
|
-
}
|
1223
|
-
rootCollection.each(function(nodes) {
|
1224
|
-
var typeChar;
|
1225
|
-
typeChar = nodes.get('type') === 'directory' ? '+' : '-';
|
1226
|
-
output += spaces + typeChar + nodes.nameWithExtension() + '\n';
|
1227
|
-
return output = _this.toAscii(nodes.collection, indentation + 1, output);
|
1228
|
-
});
|
1229
|
-
return output;
|
1230
|
-
};
|
1231
|
-
|
1232
|
-
Tree.prototype.getModelFromClick = function(e) {
|
1233
|
-
/*
|
1234
|
-
Internal: Look up a model based on the cid of the clicked view element.
|
1235
|
-
|
1236
|
-
Returns the Node corresponding to the view element that the user clicked on.
|
1237
|
-
*/
|
1238
|
-
|
551
|
+
Tree.prototype.getViewFromClick = function(e) {
|
1239
552
|
var cid;
|
1240
553
|
e.stopPropagation();
|
1241
|
-
this.menuView.$el.hide();
|
1242
554
|
cid = $(e.currentTarget).data('cid');
|
1243
|
-
return this.
|
555
|
+
return this.viewCache[cid];
|
1244
556
|
};
|
1245
557
|
|
1246
558
|
Tree.prototype._openDirectory = function(e) {
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
var model;
|
1252
|
-
model = this.getModelFromClick(e);
|
1253
|
-
return model.toggleOpen();
|
559
|
+
var view;
|
560
|
+
e.stopPropagation();
|
561
|
+
view = this.getViewFromClick(e);
|
562
|
+
return view.toggleOpen();
|
1254
563
|
};
|
1255
564
|
|
1256
565
|
Tree.prototype._openFile = function(e) {
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
*/
|
1261
|
-
|
1262
|
-
var model;
|
1263
|
-
model = this.getModelFromClick(e);
|
1264
|
-
return this.trigger('openFile', model);
|
566
|
+
var view;
|
567
|
+
view = this.getViewFromClick(e);
|
568
|
+
return this.trigger('openFile', view.model);
|
1265
569
|
};
|
1266
570
|
|
1267
571
|
Tree.prototype.render = function() {
|
1268
|
-
/*
|
1269
|
-
Internal: Call render on each of the nodes underneath the root node.
|
1270
|
-
Also calls sort on each of the subcollections.
|
1271
|
-
*/
|
1272
|
-
|
1273
572
|
var _this = this;
|
1274
|
-
this.root.collection.
|
573
|
+
this.root.collection.each(function(node) {
|
1275
574
|
var view;
|
1276
|
-
node.collection.sort();
|
1277
575
|
view = _this.findOrCreateView(node);
|
1278
|
-
|
1279
|
-
return _this.$el.append(view.render().$el);
|
1280
|
-
}
|
576
|
+
return _this.$el.append(view.render().$el);
|
1281
577
|
});
|
1282
578
|
return this;
|
1283
579
|
};
|