Add logic to handle remote service requests by serving a separate HTML front-end...
[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.net.XhrIo');
20 goog.require('goog.string.format');
21 goog.require('goog.Uri.QueryData');
22
23 armadillo.App = function() {
24 }
25
26 /**
27 * Runs the main front end.
28 */
29 armadillo.App.prototype.frontEndMain = function() {
30 var start_path = '/';
31 if (window.location.hash) {
32 start_path = window.location.hash.substr(1);
33 }
34 this.list(start_path);
35 goog.events.listen(window, goog.events.EventType.HASHCHANGE,
36 this.hashChanged_, false, this);
37
38 this.clearError(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 * Performs a remote service request, which is essentially an API call that uses
48 * the JavaScript frontend rather than the backend.
49 */
50 armadillo.App.prototype.serviceRequestMain = function() {
51 document.write(window.location);
52 console.log(window.location);
53 };
54
55 /**
56 * Starts a new XHR service request from the backend.
57 * @param {string} action Action to perform.
58 * @param {Object} extra_data Extra data to add.
59 * @param {Function} callback XHR callback.
60 */
61 armadillo.App.prototype.sendRequest = function(action, extra_data, callback) {
62 var data = new goog.Uri.QueryData();
63 data.set('action', action);
64 data.extend(extra_data);
65 goog.net.XhrIo.send('/service', callback, 'POST', data);
66 };
67
68 /**
69 * Updates the directory listing for a given path.
70 * @param {string} path Path to list; relative to jail.
71 */
72 armadillo.App.prototype.list = function(path) {
73 var callback = function(e) {
74 var data = e.target.getResponseJson();
75 if (data['error']) {
76 app.showError(data['message']);
77 return; // Error.
78 } else {
79 app.clearError(true);
80 }
81
82 // Update the listing.
83 goog.dom.setTextContent(goog.dom.getElement('pwd'), path);
84 app.currentPath_ = path;
85 window.location.hash = path;
86 document.title = path + ' - Armadillo';
87 var list = goog.dom.getElement('ls');
88 goog.dom.removeChildren(list);
89
90 // Add a previous directory entry.
91 if (path != '/' && path != '')
92 goog.array.insertAt(data, '../', 0);
93
94 // Add items for each entry.
95 goog.array.forEach(data, function(file) {
96 var fileObject = new armadillo.File(file, path);
97 goog.dom.appendChild(list, fileObject.draw());
98 });
99 }
100 this.sendRequest('list', {'path':path}, callback);
101 };
102
103 /**
104 * Navigates to a subpath. Can only handle directories.
105 * @param {string} target Relative path to |currentPath_|.
106 */
107 armadillo.App.prototype.navigate = function(target) {
108 if (target == '../') {
109 this.list(this.stripLastPathComponent(this.currentPath_));
110 } else {
111 this.list(this.currentPath_ + target);
112 }
113 };
114
115 /**
116 * Event for when the hash changes.
117 * @param {Event} e
118 */
119 armadillo.App.prototype.hashChanged_ = function(e) {
120 if (window.location.hash.length)
121 this.list(window.location.hash.substr(1));
122 };
123
124 /**
125 * Checks whether a path is a directory.
126 * @param {string} path
127 * @returns boolean
128 */
129 armadillo.App.prototype.isDirectory = function(path) {
130 return path[path.length - 1] == '/';
131 };
132
133 /**
134 * Gets the current path of the directory being displayed, absolute to root.
135 * @returns string
136 */
137 armadillo.App.prototype.getCurrentPath = function() {
138 return this.currentPath_;
139 };
140
141 /**
142 * Strips the last path component from a path.
143 * @param {string} path
144 * @returns string
145 */
146 armadillo.App.prototype.stripLastPathComponent = function(path) {
147 for (var i = path.length - 1; i >= 0; --i) {
148 if (path[i] == '/') {
149 if (i != path.length - 1) {
150 return path.substring(0, i + 1);
151 }
152 }
153 }
154 return '/';
155 };
156
157 /**
158 * Joins all the arguments together as a path.
159 * @param {string...} varargs Components to join
160 */
161 armadillo.App.prototype.joinPath = function() {
162 var path = '';
163 var sep = '/';
164 var last = arguments.length - 1;
165 goog.array.forEach(arguments, function (c, i) {
166 if (c == sep && i != 0)
167 return;
168 path += c;
169 if (c[c.length - 1] != sep && i != last)
170 path += sep;
171 });
172 return path;
173 };
174
175 /**
176 * Clears the error message.
177 * @param {bool?} animate Whether or not to animate out.
178 */
179 armadillo.App.prototype.clearError = function(animate) {
180 var elm = goog.dom.getElement('error');
181 var anim = new goog.fx.dom.FadeOutAndHide(elm, 500);
182 if (!goog.dom.getTextContent(elm) || !animate) {
183 anim.hide();
184 return;
185 }
186 goog.events.listenOnce(anim, goog.fx.Animation.EventType.END, function() {
187 goog.dom.setTextContent(elm, '');
188 });
189 anim.play();
190 };
191
192 /**
193 * Shows an error message.
194 * @param {string} message
195 */
196 armadillo.App.prototype.showError = function(message) {
197 var elm = goog.dom.getElement('error');
198 goog.dom.setTextContent(elm, message);
199 var anim = new goog.fx.dom.FadeInAndShow(elm, 1000);
200 anim.play();
201 };