Send backend errors using HTTP instead of an ad hoc JSON RPC.
[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 error: function(xhr, status, error) {
49 app.showError(xhr.responseText);
50 console.log(xhr);
51 console.log(status);
52 console.log(error);
53 }
54 });
55 };
56
57 /**
58 * Updates the directory listing for a given path.
59 * @param {string} path Path to list; relative to jail.
60 */
61 armadillo.App.prototype.list = function(path) {
62 var callback = function(data, status, xhr) {
63 if (data['error']) {
64 app.showError(data['message']);
65 return; // Error.
66 } else {
67 app.clearError(true);
68 }
69
70 // Update the listing.
71 $('#pwd').text(path);
72 app.currentPath_ = path;
73 window.location.hash = path;
74 document.title = path + ' - Armadillo';
75
76 var list = $('#ls');
77 list.empty();
78
79 // Add a previous directory entry.
80 if (path != '/' && path != '')
81 data.unshift('../');
82
83 // Add items for each entry.
84 $.each(data, function(i, file) {
85 var fileObject = new armadillo.File(file, path);
86 list.append(fileObject.createDom());
87 });
88 }
89 this.sendRequest('list', {'path':path}, callback);
90 };
91
92 /**
93 * Navigates to a subpath. Can only handle directories.
94 * @param {string} target Relative path to |currentPath_|.
95 */
96 armadillo.App.prototype.navigate = function(target) {
97 if (target == '../') {
98 this.list(this.stripLastPathComponent(this.currentPath_));
99 } else {
100 this.list(this.currentPath_ + target);
101 }
102 };
103
104 /**
105 * Event for when the hash changes.
106 * @param {Event} e
107 */
108 armadillo.App.prototype.hashChanged_ = function(e) {
109 if (window.location.hash.length)
110 this.list(window.location.hash.substr(1));
111 };
112
113 /**
114 * Checks whether a path is a directory.
115 * @param {string} path
116 * @returns boolean
117 */
118 armadillo.App.prototype.isDirectory = function(path) {
119 return path[path.length - 1] == '/';
120 };
121
122 /**
123 * Gets the current path of the directory being displayed, absolute to root.
124 * @returns string
125 */
126 armadillo.App.prototype.getCurrentPath = function() {
127 return this.currentPath_;
128 };
129
130 /**
131 * Strips the last path component from a path.
132 * @param {string} path
133 * @returns string
134 */
135 armadillo.App.prototype.stripLastPathComponent = function(path) {
136 for (var i = path.length - 1; i >= 0; --i) {
137 if (path[i] == '/') {
138 if (i != path.length - 1) {
139 return path.substring(0, i + 1);
140 }
141 }
142 }
143 return '/';
144 };
145
146 /**
147 * Joins all the arguments together as a path.
148 * @param {string...} varargs Components to join
149 */
150 armadillo.App.prototype.joinPath = function() {
151 var path = '';
152 var sep = '/';
153 var last = arguments.length - 1;
154 $.each(arguments, function (i, c) {
155 if (c == sep && i != 0)
156 return;
157 path += c;
158 if (c[c.length - 1] != sep && i != last)
159 path += sep;
160 });
161 return path;
162 };
163
164 /**
165 * Clears the error message.
166 * @param {bool?} animate Whether or not to animate out.
167 */
168 armadillo.App.prototype.clearError = function(animate) {
169 var elm = $('#error');
170 if (!elm.text() || !animate) {
171 elm.hide();
172 return;
173 }
174
175 elm.fadeOut(500, function() {
176 elm.text('');
177 });
178 };
179
180 /**
181 * Shows an error message.
182 * @param {string} message
183 */
184 armadillo.App.prototype.showError = function(message) {
185 $('#error').text(message).fadeIn(1000);
186 };
187
188 /**
189 * Creates a subdirectory in the current path.
190 */
191 armadillo.App.prototype.mkdirHandler_ = function() {
192 var name = prompt('Name the new subdirectory', '');
193 if (name != null && name != '') {
194 var path = this.joinPath(this.getCurrentPath(), name);
195 this.sendRequest('mkdir', {'path':path}, function(data, status, xhr) {
196 if (data['error']) {
197 app.showError(data['message']);
198 } else {
199 app.clearError();
200 app.list(app.getCurrentPath());
201 }
202 });
203 }
204 };