bone_tree 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +190 -0
- data/Guardfile +14 -0
- data/README +1 -0
- data/Rakefile +21 -0
- data/app/assets/images/bonetree.png +0 -0
- data/app/assets/images/crushed_bone.png +0 -0
- data/app/assets/index.html +439 -0
- data/app/assets/javascripts/bone_tree.js +1292 -0
- data/app/assets/stylesheets/bone_tree.css +186 -0
- data/app/assets/stylesheets/bone_tree_repo.css +73 -0
- data/bone_tree-0.0.1.gem +0 -0
- data/bone_tree.gemspec +20 -0
- data/config.rb +26 -0
- data/config.ru +4 -0
- data/docs/index.html +222 -0
- data/docs/resources/base.css +70 -0
- data/docs/resources/index.css +20 -0
- data/docs/resources/module.css +24 -0
- data/docs/source/javascripts/bone_tree/_namespace.js.html +45 -0
- data/docs/source/javascripts/bone_tree/models/_directory.js.html +126 -0
- data/docs/source/javascripts/bone_tree/models/_file.js.html +112 -0
- data/docs/source/javascripts/bone_tree/models/_nodes.js.html +174 -0
- data/docs/source/javascripts/bone_tree/models/_settings.js.html +75 -0
- data/docs/source/javascripts/bone_tree/views/_directory.js.html +94 -0
- data/docs/source/javascripts/bone_tree/views/_file.js.html +82 -0
- data/docs/source/javascripts/bone_tree/views/_menu.js.html +110 -0
- data/docs/source/javascripts/bone_tree/views/_tree.js.html +432 -0
- data/lib/version.rb +4 -0
- data/source/images/bonetree.png +0 -0
- data/source/images/crushed_bone.png +0 -0
- data/source/index.html.haml +438 -0
- data/source/javascripts/_backbone.js +1293 -0
- data/source/javascripts/_jquery.min.js +5 -0
- data/source/javascripts/_underscore.js +999 -0
- data/source/javascripts/bone_tree/_namespace.js.coffee +7 -0
- data/source/javascripts/bone_tree/models/_directory.js.coffee +63 -0
- data/source/javascripts/bone_tree/models/_file.js.coffee +55 -0
- data/source/javascripts/bone_tree/models/_nodes.js.coffee +117 -0
- data/source/javascripts/bone_tree/models/_settings.js.coffee +25 -0
- data/source/javascripts/bone_tree/views/_directory.js.coffee +73 -0
- data/source/javascripts/bone_tree/views/_file.js.coffee +49 -0
- data/source/javascripts/bone_tree/views/_menu.js.coffee +97 -0
- data/source/javascripts/bone_tree/views/_tree.js.coffee +498 -0
- data/source/javascripts/bone_tree.js.coffee +1 -0
- data/source/layout.haml +13 -0
- data/source/stylesheets/bone_tree.css.sass +107 -0
- data/source/stylesheets/bone_tree_repo.css.sass +65 -0
- data/spec/javascripts/directory_view_spec.coffee +91 -0
- data/spec/javascripts/file_view_spec.coffee +70 -0
- data/spec/javascripts/helpers/spec_helper.coffee +7 -0
- data/spec/javascripts/menu_view_spec.coffee +42 -0
- data/spec/javascripts/nodes_spec.coffee +37 -0
- data/spec/javascripts/support/jasmine.yml +8 -0
- data/spec/javascripts/support/jasmine_config.rb +23 -0
- data/spec/javascripts/support/jasmine_runner.rb +32 -0
- data/spec/javascripts/tree_view_spec.coffee +39 -0
- metadata +123 -0
@@ -0,0 +1,7 @@
|
|
1
|
+
window.BoneTree = {}
|
2
|
+
|
3
|
+
BoneTree.namespace = (target, name, block) ->
|
4
|
+
[target, name, block] = [(if typeof exports isnt 'undefined' then exports else window), arguments...] if arguments.length < 3
|
5
|
+
top = target
|
6
|
+
target = target[item] or= {} for item in name.split '.'
|
7
|
+
block target, top
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#= require ./_nodes
|
2
|
+
|
3
|
+
BoneTree.namespace "BoneTree.Models", (Models) ->
|
4
|
+
class Models.Directory extends Models.Node
|
5
|
+
###
|
6
|
+
Public: Object representing a directory.
|
7
|
+
|
8
|
+
* defaults
|
9
|
+
* name - A String naming the directory (default: "New Directory").
|
10
|
+
* sortPriority - A String representing the priority with which the
|
11
|
+
node is sorted. Directories have sortPriority "0"
|
12
|
+
allowing them to be sorted before Files which have
|
13
|
+
sortPriority "1".
|
14
|
+
* nodeType - A String denoting what type of node this object is.
|
15
|
+
The two types are "file" and "directory".
|
16
|
+
* open - The state of the directory. Controls whether or not
|
17
|
+
to display files and directories contained within this
|
18
|
+
Directory (default: false).
|
19
|
+
|
20
|
+
###
|
21
|
+
defaults:
|
22
|
+
name: "New Directory"
|
23
|
+
open: false
|
24
|
+
sortPriority: "0"
|
25
|
+
nodeType: "directory"
|
26
|
+
|
27
|
+
toggleOpen: =>
|
28
|
+
###
|
29
|
+
Public: Toggle the open state of this Directory.
|
30
|
+
|
31
|
+
Examples
|
32
|
+
|
33
|
+
dir = new BoneTree.Models.Directory
|
34
|
+
|
35
|
+
dir.get('open')
|
36
|
+
# => false
|
37
|
+
|
38
|
+
dir.toggleOpen()
|
39
|
+
dir.get('open')
|
40
|
+
# => true
|
41
|
+
|
42
|
+
Returns this Directory.
|
43
|
+
###
|
44
|
+
currentState = @get 'open'
|
45
|
+
|
46
|
+
@set {open: not currentState}
|
47
|
+
|
48
|
+
Models.Directory.find = (currentDirectory, name) ->
|
49
|
+
###
|
50
|
+
Internal: Check to see if there is a directory with the matching name
|
51
|
+
contained within currentDirectory.
|
52
|
+
|
53
|
+
* currentDirectory - A Directory object to search for the matching directory name.
|
54
|
+
|
55
|
+
* name - A String name used to check for matching directory
|
56
|
+
names in currentDirectory.
|
57
|
+
|
58
|
+
Returns The Directory object with the matching name if it exists and undefined otherwise.
|
59
|
+
###
|
60
|
+
currentDirectory.collection.find (dir) ->
|
61
|
+
dir.get('name') is name
|
62
|
+
|
63
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
#= require ./_nodes
|
2
|
+
|
3
|
+
BoneTree.namespace "BoneTree.Models", (Models) ->
|
4
|
+
class Models.File extends Models.Node
|
5
|
+
###
|
6
|
+
Public: Object representing file data in the tree.
|
7
|
+
|
8
|
+
* defaults
|
9
|
+
* name - A String naming the file (default: "New File").
|
10
|
+
* sortPriority - A String representing the priority with which the
|
11
|
+
node is sorted. Directories have sortPriority "0"
|
12
|
+
allowing them to be sorted before Files which have
|
13
|
+
sortPriority "1".
|
14
|
+
* nodeType - A String denoting what type of node this object is.
|
15
|
+
The two types are "file" and "directory".
|
16
|
+
|
17
|
+
###
|
18
|
+
defaults:
|
19
|
+
name: "New File"
|
20
|
+
sortPriority: "1"
|
21
|
+
nodeType: "file"
|
22
|
+
|
23
|
+
Models.File.createFromFileName = (fileName, fileData) ->
|
24
|
+
###
|
25
|
+
Public: Class method to create a new File object based on the fileName
|
26
|
+
and fileData passed in.
|
27
|
+
|
28
|
+
* fileName - A String representing the name of the file to be created.
|
29
|
+
files with '.' in the name will be parsed out and only the
|
30
|
+
string after the final '.' will be considered the extension.
|
31
|
+
|
32
|
+
* fileData - An Object of attributes to associate with the file.
|
33
|
+
|
34
|
+
Examples
|
35
|
+
|
36
|
+
data = {
|
37
|
+
contents: alert 'this is the code in the file'
|
38
|
+
createdAt: 1330846900589
|
39
|
+
language: 'CoffeeScript'
|
40
|
+
}
|
41
|
+
|
42
|
+
BoneTree.Models.File.createFromFileName('example.coffee', data)
|
43
|
+
# => <File>
|
44
|
+
|
45
|
+
Returns the File object just created.
|
46
|
+
###
|
47
|
+
|
48
|
+
# Make sure that files like jquery.min.js work
|
49
|
+
[names..., extension] = fileName.split "."
|
50
|
+
name = names.join('.')
|
51
|
+
|
52
|
+
data = _.extend({}, fileData, {name: name, extension: extension})
|
53
|
+
|
54
|
+
return new Models.File(data)
|
55
|
+
|
@@ -0,0 +1,117 @@
|
|
1
|
+
BoneTree.namespace "BoneTree.Models", (Models) ->
|
2
|
+
class Models.Node extends Backbone.Model
|
3
|
+
###
|
4
|
+
Internal: An abstract super class for File and Directory objects to inherit from.
|
5
|
+
|
6
|
+
###
|
7
|
+
initialize: ->
|
8
|
+
###
|
9
|
+
Internal: Initialize a new Node object. Set it up to contain a collection of
|
10
|
+
children nodes.
|
11
|
+
|
12
|
+
###
|
13
|
+
@collection = new Models.Nodes
|
14
|
+
|
15
|
+
constantize: =>
|
16
|
+
###
|
17
|
+
Public: Returns a String with the nodeType capitalized so that it may be used
|
18
|
+
to instatiate the appropriate view type
|
19
|
+
|
20
|
+
Examples
|
21
|
+
|
22
|
+
file = new BoneTree.Models.File
|
23
|
+
directory = new BoneTree.Models.Directory
|
24
|
+
|
25
|
+
file.constantize()
|
26
|
+
# => 'File'
|
27
|
+
|
28
|
+
directory.constantize()
|
29
|
+
# => 'Directory'
|
30
|
+
|
31
|
+
# use it to create a new view of the appropriate type
|
32
|
+
view = new BoneTree.Views[file.constantize()]
|
33
|
+
|
34
|
+
Returns a String of the nodeType with the first letter capitalized.
|
35
|
+
###
|
36
|
+
nodeType = @get('nodeType')
|
37
|
+
|
38
|
+
nodeType[0].toUpperCase() + nodeType.substring(1)
|
39
|
+
|
40
|
+
nameWithExtension: =>
|
41
|
+
###
|
42
|
+
Public: Returns the node name with the extension if it has
|
43
|
+
one and just the node name if there is no extension.
|
44
|
+
|
45
|
+
Examples
|
46
|
+
|
47
|
+
file = new BoneTree.Models.File
|
48
|
+
name: "file"
|
49
|
+
extension: "coffee"
|
50
|
+
|
51
|
+
noExt = new BoneTree.Models.File
|
52
|
+
name: "file2"
|
53
|
+
|
54
|
+
directory = new BoneTree.Model.Directory
|
55
|
+
name: "source"
|
56
|
+
|
57
|
+
file.nameWithExtension()
|
58
|
+
# => "file.coffee"
|
59
|
+
|
60
|
+
noExt.nameWithExtension()
|
61
|
+
# => "file2"
|
62
|
+
|
63
|
+
directory.nameWithExtension()
|
64
|
+
# => "source"
|
65
|
+
|
66
|
+
Returns a String. If the extension exists then the node name plus the extension
|
67
|
+
are returned. If there is no extension, then just the node name is returned.
|
68
|
+
###
|
69
|
+
{extension, name} = @attributes
|
70
|
+
|
71
|
+
extension ||= ""
|
72
|
+
|
73
|
+
if extension isnt ""
|
74
|
+
extension = "." + extension
|
75
|
+
|
76
|
+
return name + extension
|
77
|
+
|
78
|
+
class Models.Nodes extends Backbone.Collection
|
79
|
+
###
|
80
|
+
Internal: A collection of node models. Since Node is an abstract super
|
81
|
+
class, in practice this collection will hold File objects
|
82
|
+
and Directory objects.
|
83
|
+
|
84
|
+
###
|
85
|
+
comparator: (node) ->
|
86
|
+
###
|
87
|
+
Internal: Function that determines how the file tree is sorted. Directories
|
88
|
+
are sorted before files. After node type sort
|
89
|
+
priority, nodes are sorted by name.
|
90
|
+
|
91
|
+
Examples
|
92
|
+
|
93
|
+
tree.addFile('/source/file1.coffee')
|
94
|
+
tree.addFile('/source/file2.coffee')
|
95
|
+
tree.addFile('main.coffee')
|
96
|
+
|
97
|
+
tree.render()
|
98
|
+
|
99
|
+
# even though 'main' comes before 'source' alphabetically it is placed
|
100
|
+
# after the 'source' directory due to the sortPriority of the Directory object.
|
101
|
+
tree.toAscii()
|
102
|
+
# => "
|
103
|
+
-source
|
104
|
+
-file1.coffee
|
105
|
+
-file2.coffee
|
106
|
+
-main.coffee
|
107
|
+
"
|
108
|
+
|
109
|
+
###
|
110
|
+
{name, sortPriority} = node.attributes
|
111
|
+
|
112
|
+
return sortPriority + name
|
113
|
+
|
114
|
+
model: Models.Node
|
115
|
+
|
116
|
+
|
117
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
BoneTree.namespace "BoneTree.Models", (Models) ->
|
2
|
+
class Models.Settings extends Backbone.Model
|
3
|
+
###
|
4
|
+
Internal: A configuration object. Consumers of the API don't need to
|
5
|
+
worry about this. It is used internally to manage the options
|
6
|
+
passed into the file tree.
|
7
|
+
|
8
|
+
* defaults
|
9
|
+
* beforeAdd - A Function that is invoked before each file is added to the tree.
|
10
|
+
It is passed the raw file attributes and should return true if
|
11
|
+
that file should be added to the tree and false if not. The
|
12
|
+
default implementation is to return true.
|
13
|
+
* confirmDeletes - A Boolean. If true, the tree will prompt the user, making
|
14
|
+
sure they want to delete the file (default: false).
|
15
|
+
* showExtensions - A Boolean. If true, files display their extensions. Internally,
|
16
|
+
extensions are always kept track of but by default they are
|
17
|
+
hidden (default: false).
|
18
|
+
* viewCache - An Object that stores views when they are created and is used
|
19
|
+
to look them up to prevent extra views from being created.
|
20
|
+
###
|
21
|
+
defaults:
|
22
|
+
confirmDeletes: false
|
23
|
+
showExtensions: false
|
24
|
+
viewCache: {}
|
25
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
BoneTree.namespace "BoneTree.Views", (Views) ->
|
2
|
+
class Views.Directory extends Backbone.View
|
3
|
+
###
|
4
|
+
Internal: View that renders a Directory node and controls its behavior (class: 'directory', tag: 'ul').
|
5
|
+
|
6
|
+
###
|
7
|
+
className: 'directory'
|
8
|
+
tagName: 'ul'
|
9
|
+
|
10
|
+
initialize: (options) ->
|
11
|
+
###
|
12
|
+
Internal: Initialize a new directory node. Adds associated model cid to the
|
13
|
+
view element. Binds change handler to the `change:open` event that
|
14
|
+
toggles the display of directory contents. Binds change handler to
|
15
|
+
the `change:name` event that re-renders a sorted file tree.
|
16
|
+
|
17
|
+
* options - Passes in settings object, which is used for access to the
|
18
|
+
tree view root in order to proxy events to it.
|
19
|
+
|
20
|
+
###
|
21
|
+
@settings = options.settings
|
22
|
+
|
23
|
+
@$el.attr 'data-cid', @model.cid
|
24
|
+
|
25
|
+
@model.bind 'change:open', (model, open) =>
|
26
|
+
@displayChildren(open)
|
27
|
+
|
28
|
+
@model.bind 'change:name', (model, name) =>
|
29
|
+
treeView = @settings.get 'treeView'
|
30
|
+
treeView.render().trigger 'rename', model, name
|
31
|
+
|
32
|
+
@model.collection.bind 'add', @render
|
33
|
+
|
34
|
+
@model.collection.bind 'remove', (model, collection) =>
|
35
|
+
@settings.get('treeView').trigger 'remove', model
|
36
|
+
@render()
|
37
|
+
|
38
|
+
@displayChildren(@model.get('open'))
|
39
|
+
|
40
|
+
appendView: (node) =>
|
41
|
+
###
|
42
|
+
Internal: Appends a view based on the underlying node model to this view.
|
43
|
+
|
44
|
+
node - A Node model. Either a File or a Directory. This is the model the
|
45
|
+
created view will be associated with.
|
46
|
+
|
47
|
+
###
|
48
|
+
view = @settings.get('treeView').findOrCreateView(node)
|
49
|
+
|
50
|
+
@$el.append view.render().$el
|
51
|
+
|
52
|
+
render: =>
|
53
|
+
###
|
54
|
+
Internal: Set the text of the view element based on the underlying model name.
|
55
|
+
|
56
|
+
Returns `this` view.
|
57
|
+
###
|
58
|
+
@$el.text @model.get('name')
|
59
|
+
|
60
|
+
@model.collection.sort().each @appendView
|
61
|
+
|
62
|
+
return @
|
63
|
+
|
64
|
+
displayChildren: (open) =>
|
65
|
+
###
|
66
|
+
Internal: Toggles display of the children Files or Diretories of this view.
|
67
|
+
|
68
|
+
###
|
69
|
+
fileDirChildren = @$el.children('.directory, .file')
|
70
|
+
|
71
|
+
@$el.toggleClass('open', open)
|
72
|
+
fileDirChildren.toggle(open)
|
73
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
BoneTree.namespace "BoneTree.Views", (Views) ->
|
2
|
+
class Views.File extends Backbone.View
|
3
|
+
###
|
4
|
+
Internal: View that renders a File node and controls its behavior (class: 'file', tag: 'li').
|
5
|
+
|
6
|
+
###
|
7
|
+
className: 'file'
|
8
|
+
tagName: 'li'
|
9
|
+
|
10
|
+
initialize: (options) ->
|
11
|
+
###
|
12
|
+
Internal: Initialize a new file node. Adds associated model cid to the
|
13
|
+
view element. Binds change handlers to the `change:name` and
|
14
|
+
`change:extension` events. These take care of resorting the file
|
15
|
+
nodes.
|
16
|
+
|
17
|
+
* options - Passes in settings object, which is used to control
|
18
|
+
whether or not file extensions are shown.
|
19
|
+
|
20
|
+
###
|
21
|
+
@settings = options.settings
|
22
|
+
|
23
|
+
@$el.attr('data-cid', @model.cid).addClass(@model.get('extension'))
|
24
|
+
|
25
|
+
@model.bind 'change:name', (model, name) =>
|
26
|
+
treeView = @settings.get('treeView')
|
27
|
+
treeView.render().trigger 'rename', model, model.nameWithExtension()
|
28
|
+
|
29
|
+
@model.bind 'change:extension', (model, extension) =>
|
30
|
+
@$el.attr('class', "file #{extension}")
|
31
|
+
|
32
|
+
treeView = @settings.get('treeView')
|
33
|
+
treeView.render().trigger 'rename', model, model.nameWithExtension()
|
34
|
+
|
35
|
+
render: =>
|
36
|
+
###
|
37
|
+
Internal: Sets the text of the file node according to the underlying model
|
38
|
+
name. If the 'showExtensions' setting is set, renders the
|
39
|
+
full file name with extension, otherwise renders just the file
|
40
|
+
name attribute.
|
41
|
+
|
42
|
+
###
|
43
|
+
if @settings.get('showExtensions')
|
44
|
+
@$el.text @model.nameWithExtension()
|
45
|
+
else
|
46
|
+
@$el.text @model.get('name')
|
47
|
+
|
48
|
+
return @
|
49
|
+
|
@@ -0,0 +1,97 @@
|
|
1
|
+
BoneTree.namespace "BoneTree.Views", (Views) ->
|
2
|
+
class Views.Menu extends Backbone.View
|
3
|
+
###
|
4
|
+
Internal: View that controls the context menu (class: 'filetree\_context\_menu').
|
5
|
+
|
6
|
+
Events
|
7
|
+
|
8
|
+
* contextMenu - Prevents the standard browser context menu from appearing
|
9
|
+
when right clicking within the file tree context menu.
|
10
|
+
|
11
|
+
* click .rename - Prompts the user to rename a file.
|
12
|
+
|
13
|
+
* click .delete - Deletes a node from the file tree.
|
14
|
+
|
15
|
+
###
|
16
|
+
className: 'filetree_context_menu'
|
17
|
+
|
18
|
+
events:
|
19
|
+
'contextmenu': 'contextMenu'
|
20
|
+
'click .rename': 'rename'
|
21
|
+
'click .delete': 'delete'
|
22
|
+
|
23
|
+
initialize: (options) ->
|
24
|
+
###
|
25
|
+
Internal: Initialize a new menu widget.
|
26
|
+
|
27
|
+
* options - An Object. Internally used to pass the settings configuration
|
28
|
+
into the menu. This controls whether or not the user is
|
29
|
+
prompted to confirm deleting a file.
|
30
|
+
|
31
|
+
###
|
32
|
+
@settings = options.settings
|
33
|
+
|
34
|
+
contextMenu: (e) =>
|
35
|
+
###
|
36
|
+
Internal: Kill the default browser behavior for the contextmenu event.
|
37
|
+
|
38
|
+
###
|
39
|
+
e.preventDefault()
|
40
|
+
e.stopPropagation()
|
41
|
+
|
42
|
+
delete: (e) =>
|
43
|
+
###
|
44
|
+
Internal: Deletes a node from the file tree. If the confirmDeletes setting
|
45
|
+
is set, prompts the user for delete confirmation.
|
46
|
+
|
47
|
+
###
|
48
|
+
if @settings.get('confirmDeletes')
|
49
|
+
if confirm "Are you sure you want to delete '#{@model.nameWithExtension()}'?"
|
50
|
+
@model.destroy()
|
51
|
+
else
|
52
|
+
@model.destroy()
|
53
|
+
|
54
|
+
@$el.hide()
|
55
|
+
|
56
|
+
rename: (e) =>
|
57
|
+
###
|
58
|
+
Internal: Prompts the user to rename a File or Directory.
|
59
|
+
|
60
|
+
###
|
61
|
+
if newName = prompt "New Name", @model.nameWithExtension()
|
62
|
+
[fileName, extension] = newName.split "."
|
63
|
+
|
64
|
+
extension ?= ""
|
65
|
+
|
66
|
+
@model.set
|
67
|
+
name: fileName
|
68
|
+
extension: extension
|
69
|
+
|
70
|
+
@$el.hide()
|
71
|
+
|
72
|
+
render: =>
|
73
|
+
###
|
74
|
+
Internal: Renders the <ul> that contains the context menu choices
|
75
|
+
'Rename' and 'Delete'.
|
76
|
+
|
77
|
+
Returns `this`, the menu view.
|
78
|
+
###
|
79
|
+
|
80
|
+
@$el.html @template()
|
81
|
+
|
82
|
+
return @
|
83
|
+
|
84
|
+
template: ->
|
85
|
+
###
|
86
|
+
Internal: html template for the context menu.
|
87
|
+
|
88
|
+
###
|
89
|
+
"""
|
90
|
+
<ul>
|
91
|
+
<li class='rename'>Rename</li>
|
92
|
+
<hr/>
|
93
|
+
<li class='delete'>Delete</li>
|
94
|
+
</ul>
|
95
|
+
"""
|
96
|
+
|
97
|
+
|