Better handling of clearing the error in the list callback.
[armadillo.git] / web_frontend / main.js
1 //
2 // Armadillo File Manager
3 // Copyright (c) 2010, 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.net.XhrIo');
20 goog.require('goog.string.format');
21 goog.require('goog.Uri.QueryData');
22
23 armadillo.App = function() {
24 var start_path = '/';
25 if (window.location.hash) {
26 start_path = window.location.hash.substr(1);
27 }
28 this.list(start_path);
29 goog.events.listen(window, goog.events.EventType.HASHCHANGE,
30 this.hashChanged_, false, this);
31
32 this.clearError(false);
33 /**
34 * If this is the first load, we don't want to flash the error animating
35 * out. This will be set to true in the list callback.
36 * @type {bool}
37 */
38 this.initialized_ = false;
39
40 var version = goog.string.format('Armadillo %d.%d (%d)',
41 armadillo.Version.MAJOR, armadillo.Version.MINOR,
42 armadillo.Version.BUILD);
43 goog.dom.setTextContent(goog.dom.getElement('footer'), version)
44 }
45
46 /**
47 * Starts a new XHR service request from the backend.
48 * @param {string} action Action to perform.
49 * @param {Object} extra_data Extra data to add.
50 * @param {Function} callback XHR callback.
51 */
52 armadillo.App.prototype.sendRequest = function(action, extra_data, callback) {
53 var data = new goog.Uri.QueryData();
54 data.set('action', action);
55 data.extend(extra_data);
56 goog.net.XhrIo.send('/service', callback, 'POST', data);
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(e) {
65 var data = e.target.getResponseJson();
66 if (data['error']) {
67 app.showError(data['message']);
68 return; // Error.
69 } else {
70 app.clearError(app.initialized_);
71 }
72
73 // Update the listing.
74 goog.dom.setTextContent(goog.dom.getElement('pwd'), path);
75 app.currentPath_ = path;
76 window.location.hash = path;
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 app.initialized_ = true;
91 }
92 this.sendRequest('list', {'path':path}, callback);
93 };
94
95 /**
96 * Navigates to a subpath. Can only handle directories.
97 * @param {string} target Relative path to |currentPath_|.
98 */
99 armadillo.App.prototype.navigate = function(target) {
100 if (target == '../') {
101 this.list(this.stripLastPathComponent(this.currentPath_));
102 } else {
103 this.list(this.currentPath_ + target);
104 }
105 };
106
107 /**
108 * Event for when the hash changes.
109 * @param {Event} e
110 */
111 armadillo.App.prototype.hashChanged_ = function(e) {
112 if (window.location.hash.length)
113 this.list(window.location.hash.substr(1));
114 };
115
116 /**
117 * Checks whether a path is a directory.
118 * @param {string} path
119 * @returns boolean
120 */
121 armadillo.App.prototype.isDirectory = function(path) {
122 return path[path.length - 1] == '/';
123 };
124
125 /**
126 * Gets the current path of the directory being displayed, absolute to root.
127 * @returns string
128 */
129 armadillo.App.prototype.getCurrentPath = function() {
130 return this.currentPath_;
131 };
132
133 /**
134 * Strips the last path component from a path.
135 * @param {string} path
136 * @returns string
137 */
138 armadillo.App.prototype.stripLastPathComponent = function(path) {
139 for (var i = path.length - 1; i >= 0; --i) {
140 if (path[i] == '/') {
141 if (i != path.length - 1) {
142 return path.substring(0, i + 1);
143 }
144 }
145 }
146 return '/';
147 };
148
149 /**
150 * Joins all the arguments together as a path.
151 * @param {string...} varargs Components to join
152 */
153 armadillo.App.prototype.joinPath = function() {
154 var path = '';
155 var sep = '/';
156 var last = arguments.length - 1;
157 goog.array.forEach(arguments, function (c, i) {
158 if (c == sep && i != 0)
159 return;
160 path += c;
161 if (c[c.length - 1] != sep && i != last)
162 path += sep;
163 });
164 return path;
165 };
166
167 /**
168 * Clears the error message.
169 * @param {bool?} animate Whether or not to animate out.
170 */
171 armadillo.App.prototype.clearError = function(animate) {
172 var elm = goog.dom.getElement('error');
173 var anim = new goog.fx.dom.FadeOutAndHide(elm, 500);
174 if (animate)
175 anim.play();
176 else
177 anim.hide();
178 goog.events.listenOnce(anim, goog.fx.Animation.EventType.END, function() {
179 goog.dom.setTextContent(elm, '');
180 });
181 };
182
183 /**
184 * Shows an error message.
185 * @param {string} message
186 */
187 armadillo.App.prototype.showError = function(message) {
188 var elm = goog.dom.getElement('error');
189 goog.dom.setTextContent(elm, message);
190 var anim = new goog.fx.dom.FadeInAndShow(elm, 1000);
191 anim.play();
192 };