Don't return a null slice from server.ListPath, return an empty one
[armadillo.git] / frontend / main.js
1 //
2 // Armadillo File Manager
3 // Copyright (c) 2010-2011, Robert Sesek <http://www.bluestatic.org>
4 //
5 // This program is free software: you can redistribute it and/or modify it under
6 // the terms of the GNU General Public License as published by the Free Software
7 // Foundation, either version 3 of the License, or any later version.
8 //
9
10 $.namespace('armadillo.App');
11
12 $(document).ready(function() {
13 app = new armadillo.App();
14 });
15
16 armadillo.App = function() {
17 var start_path = '/';
18 if (window.location.hash) {
19 start_path = window.location.hash.substr(1);
20 }
21 this.list(start_path);
22
23 $(window).bind('hashchange', this.hashChanged_.bind(this));
24
25 this.clearError(false);
26
27 $('#mkdir').click(this.mkdirHandler_.bind(this));
28
29 var version = 'Armadillo ' + armadillo.Version.MAJOR + '.' + armadillo.Version.MINOR +
30 ' (' + armadillo.Version.BUILD + ')';
31 $('#footer').text(version);
32 }
33
34 /**
35 * Starts a new XHR service request from the backend.
36 * @param {string} action Action to perform.
37 * @param {Object} data Extra data to add.
38 * @param {Function} callback XHR callback.
39 * @return {jqXHR} The jQuery XHR object.
40 */
41 armadillo.App.prototype.sendRequest = function(action, data, callback) {
42 data.action = action;
43 return $.ajax({
44 url: 'service',
45 type: 'POST',
46 data: data,
47 success: callback
48 });
49 };
50
51 /**
52 * Updates the directory listing for a given path.
53 * @param {string} path Path to list; relative to jail.
54 */
55 armadillo.App.prototype.list = function(path) {
56 var callback = function(data, status, xhr) {
57 if (data['error']) {
58 app.showError(data['message']);
59 return; // Error.
60 } else {
61 app.clearError(true);
62 }
63
64 // Update the listing.
65 $('#pwd').text(path);
66 app.currentPath_ = path;
67 window.location.hash = path;
68 document.title = path + ' - Armadillo';
69
70 var list = $('#ls');
71 list.empty();
72
73 // Add a previous directory entry.
74 if (path != '/' && path != '')
75 data.unshift('../');
76
77 // Add items for each entry.
78 $.each(data, function(i, file) {
79 var fileObject = new armadillo.File(file, path);
80 list.append(fileObject.createDom());
81 });
82 }
83 this.sendRequest('list', {'path':path}, callback);
84 };
85
86 /**
87 * Navigates to a subpath. Can only handle directories.
88 * @param {string} target Relative path to |currentPath_|.
89 */
90 armadillo.App.prototype.navigate = function(target) {
91 if (target == '../') {
92 this.list(this.stripLastPathComponent(this.currentPath_));
93 } else {
94 this.list(this.currentPath_ + target);
95 }
96 };
97
98 /**
99 * Event for when the hash changes.
100 * @param {Event} e
101 */
102 armadillo.App.prototype.hashChanged_ = function(e) {
103 if (window.location.hash.length)
104 this.list(window.location.hash.substr(1));
105 };
106
107 /**
108 * Checks whether a path is a directory.
109 * @param {string} path
110 * @returns boolean
111 */
112 armadillo.App.prototype.isDirectory = function(path) {
113 return path[path.length - 1] == '/';
114 };
115
116 /**
117 * Gets the current path of the directory being displayed, absolute to root.
118 * @returns string
119 */
120 armadillo.App.prototype.getCurrentPath = function() {
121 return this.currentPath_;
122 };
123
124 /**
125 * Strips the last path component from a path.
126 * @param {string} path
127 * @returns string
128 */
129 armadillo.App.prototype.stripLastPathComponent = function(path) {
130 for (var i = path.length - 1; i >= 0; --i) {
131 if (path[i] == '/') {
132 if (i != path.length - 1) {
133 return path.substring(0, i + 1);
134 }
135 }
136 }
137 return '/';
138 };
139
140 /**
141 * Joins all the arguments together as a path.
142 * @param {string...} varargs Components to join
143 */
144 armadillo.App.prototype.joinPath = function() {
145 var path = '';
146 var sep = '/';
147 var last = arguments.length - 1;
148 $.each(arguments, function (i, c) {
149 if (c == sep && i != 0)
150 return;
151 path += c;
152 if (c[c.length - 1] != sep && i != last)
153 path += sep;
154 });
155 return path;
156 };
157
158 /**
159 * Clears the error message.
160 * @param {bool?} animate Whether or not to animate out.
161 */
162 armadillo.App.prototype.clearError = function(animate) {
163 var elm = $('#error');
164 if (!elm.text() || !animate) {
165 elm.hide();
166 return;
167 }
168
169 elm.fadeOut(500, function() {
170 elm.text('');
171 });
172 };
173
174 /**
175 * Shows an error message.
176 * @param {string} message
177 */
178 armadillo.App.prototype.showError = function(message) {
179 $('#error').text(message).fadeIn(1000);
180 };
181
182 /**
183 * Creates a subdirectory in the current path.
184 */
185 armadillo.App.prototype.mkdirHandler_ = function() {
186 var name = prompt('Name the new subdirectory', '');
187 if (name != null && name != '') {
188 var path = this.joinPath(this.getCurrentPath(), name);
189 this.sendRequest('mkdir', {'path':path}, function(data, status, xhr) {
190 if (data['error']) {
191 app.showError(data['message']);
192 } else {
193 app.clearError();
194 app.list(app.getCurrentPath());
195 }
196 });
197 }
198 };