bone_tree 0.5.0
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 +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
|
+
|