Switch to using jQuery XHR
[armadillo.git] / web_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 goog.provide('armadillo');
11 goog.provide('armadillo.App');
12
13 goog.require('armadillo.File');
14 goog.require('armadillo.Version');
15 goog.require('goog.array');
16 goog.require('goog.dom');
17 goog.require('goog.fx.dom.FadeInAndShow');
18 goog.require('goog.fx.dom.FadeOutAndHide');
19 goog.require('goog.string.format');
20
21 armadillo.App = function() {
22 var start_path = '/';
23 if (window.location.hash) {
24 start_path = window.location.hash.substr(1);
25 }
26 this.list(start_path);
27 goog.events.listen(window, goog.events.EventType.HASHCHANGE,
28 this.hashChanged_, false, this);
29
30 this.clearError(false);
31
32 var mkdir = goog.dom.getElement('mkdir');
33 goog.events.listen(mkdir, goog.events.EventType.CLICK,
34 this.mkdirHandler_, false, this);
35
36 var version = goog.string.format('Armadillo %d.%d (%f)',
37 armadillo.Version.MAJOR, armadillo.Version.MINOR,
38 armadillo.Version.BUILD);
39 goog.dom.setTextContent(goog.dom.getElement('footer'), version)
40 }
41
42 /**
43 * Starts a new XHR service request from the backend.
44 * @param {string} action Action to perform.
45 * @param {Object} data Extra data to add.
46 * @param {Function} callback XHR callback.
47 * @return {jqXHR} The jQuery XHR object.
48 */
49 armadillo.App.prototype.sendRequest = function(action, data, callback) {
50 data.action = action;
51 return $.ajax({
52 url: 'service',
53 type: 'POST',
54 data: data,
55 success: callback
56 });
57 };
58
59 /**
60 * Updates the directory listing for a given path.
61 * @param {string} path Path to list; relative to jail.
62 */
63 armadillo.App.prototype.list = function(path) {
64 var callback = function(data, status, xhr) {
65 if (data['error']) {
66 app.showError(data['message']);
67 return; // Error.
68 } else {
69 app.clearError(true);
70 }
71
72 // Update the listing.
73 goog.dom.setTextContent(goog.dom.getElement('pwd'), path);
74 app.currentPath_ = path;
75 window.location.hash = path;
76 document.title = path + ' - Armadillo';
77 var list = goog.dom.getElement('ls');
78 goog.dom.removeChildren(list);
79
80 // Add a previous directory entry.
81 if (path != '/' && path != '')
82 goog.array.insertAt(data, '../', 0);
83
84 // Add items for each entry.
85 goog.array.forEach(data, function(file) {
86 var fileObject = new armadillo.File(file, path);
87 goog.dom.appendChild(list, fileObject.draw());
88 });
89 }
90 this.sendRequest('list', {'path':path}, callback);
91 };
92
93 /**
94 * Navigates to a subpath. Can only handle directories.
95 * @param {string} target Relative path to |currentPath_|.
96 */
97 armadillo.App.prototype.navigate = function(target) {
98 if (target == '../') {
99 this.list(this.stripLastPathComponent(this.currentPath_));
100 } else {
101 this.list(this.currentPath_ + target);
102 }
103 };
104
105 /**
106 * Event for when the hash changes.
107 * @param {Event} e
108 */
109 armadillo.App.prototype.hashChanged_ = function(e) {
110 if (window.location.hash.length)
111 this.list(window.location.hash.substr(1));
112 };
113
114 /**
115 * Checks whether a path is a directory.
116 * @param {string} path
117 * @returns boolean
118 */
119 armadillo.App.prototype.isDirectory = function(path) {
120 return path[path.length - 1] == '/';
121 };
122
123 /**
124 * Gets the current path of the directory being displayed, absolute to root.
125 * @returns string
126 */
127 armadillo.App.prototype.getCurrentPath = function() {
128 return this.currentPath_;
129 };
130
131 /**
132 * Strips the last path component from a path.
133 * @param {string} path
134 * @returns string
135 */
136 armadillo.App.prototype.stripLastPathComponent = function(path) {
137 for (var i = path.length - 1; i >= 0; --i) {
138 if (path[i] == '/') {
139 if (i != path.length - 1) {
140 return path.substring(0, i + 1);
141 }
142 }
143 }
144 return '/';
145 };
146
147 /**
148 * Joins all the arguments together as a path.
149 * @param {string...} varargs Components to join
150 */
151 armadillo.App.prototype.joinPath = function() {
152 var path = '';
153 var sep = '/';
154 var last = arguments.length - 1;
155 goog.array.forEach(arguments, function (c, i) {
156 if (c == sep && i != 0)
157 return;
158 path += c;
159 if (c[c.length - 1] != sep && i != last)
160 path += sep;
161 });
162 return path;
163 };
164
165 /**
166 * Clears the error message.
167 * @param {bool?} animate Whether or not to animate out.
168 */
169 armadillo.App.prototype.clearError = function(animate) {
170 var elm = goog.dom.getElement('error');
171 var anim = new goog.fx.dom.FadeOutAndHide(elm, 500);
172 if (!goog.dom.getTextContent(elm) || !animate) {
173 anim.hide();
174 return;
175 }
176 goog.events.listenOnce(anim, goog.fx.Animation.EventType.END, function() {
177 goog.dom.setTextContent(elm, '');
178 });
179 anim.play();
180 };
181
182 /**
183 * Shows an error message.
184 * @param {string} message
185 */
186 armadillo.App.prototype.showError = function(message) {
187 var elm = goog.dom.getElement('error');
188 goog.dom.setTextContent(elm, message);
189 var anim = new goog.fx.dom.FadeInAndShow(elm, 1000);
190 anim.play();
191 };
192
193 /**
194 * Creates a subdirectory in the current path.
195 */
196 armadillo.App.prototype.mkdirHandler_ = function() {
197 var name = prompt('Name the new subdirectory', '');
198 if (name != null && name != '') {
199 var path = this.joinPath(this.getCurrentPath(), name);
200 this.sendRequest('mkdir', {'path':path}, function(data, status, xhr) {
201 if (data['error']) {
202 app.showError(data['message']);
203 } else {
204 app.clearError();
205 app.list(app.getCurrentPath());
206 }
207 });
208 }
209 };