Rewrite the path menus in jQuery
[armadillo.git] / web_frontend / path_control.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.PathControl');
11
12 goog.require('goog.array');
13
14 /**
15 * Creates a new path editing control for a given path.
16 * @param {string} path The path to create an editor for
17 * @param {bool} editLastComponent Whether the last component should be shown as an edit box
18 * @param {DomHelper} opt_domHelper Optional DOM helper
19 * @constructor
20 */
21 armadillo.PathControl = function(path, editLastComponent, opt_domHelper) {
22 /**
23 * Full path of the control.
24 * @type {string}
25 */
26 this.path_ = null;
27
28 /**
29 * The name of the file at the |path_|.
30 * @type {string}
31 */
32 this.name_ = null;
33 this.setPath(path);
34
35 /**
36 * Whether or not the last component is editable.
37 * @type {bool}
38 */
39 this.editableLastComponent_ = editLastComponent;
40
41 /**
42 * Control UI for the name component of the path.
43 * @type {goog.ui.Control}
44 */
45 this.nameControl_ = null;
46 };
47
48 /**
49 * Sets the path.
50 * @param {string} path
51 */
52 armadillo.PathControl.prototype.setPath = function(path) {
53 this.path_ = app.stripLastPathComponent(path);
54 this.name_ = path.substr(this.path_.length);
55 };
56
57 /**
58 * Gets the new path.
59 * @returns {string}
60 */
61 armadillo.PathControl.prototype.getPath = function() {
62 return app.joinPath(this.path_, this.name_);
63 };
64
65 /**
66 * Gets the name control.
67 * @returns {goog.ui.Control}
68 */
69 armadillo.PathControl.prototype.getNameControl = function() {
70 return this.nameControl_;
71 };
72
73 /**
74 * Creates a new path control object.
75 */
76 armadillo.PathControl.prototype.createDom = function() {
77 this.decorateInternal($.createDom('div'));
78 return this.element_;
79 };
80
81 /**
82 * Decorates the given element into a path control.
83 * @param {Element} element
84 */
85 armadillo.PathControl.prototype.decorateInternal = function(element) {
86 this.element_ = element;
87 var components = this.path_.split('/');
88
89 // If this is an item that lives at the root, generate a special node for
90 // moving between items at the top level.
91 components[0] = '/';
92
93 // If the last component is emtpy, do not use it because it means a directory
94 // is being moved.
95 if (components[components.length - 1] == '') {
96 goog.array.removeAt(components, components.length - 1);
97 }
98
99 var path = '';
100 $.each(components, function (i, part) {
101 this.element_.append(this.createComponentNode_(path, part), true);
102 path = app.joinPath(path, part);
103 }.bind(this));
104
105 if (this.editableLastComponent_) {
106 this.nameControl_ = $.createDom('input');
107 this.nameControl_.attr({
108 'type' : 'text',
109 'name' : 'pathName',
110 'value' : this.name_
111 });
112
113 this.nameControl_.bind('change keydown', this.nameChanged_.bind(this));
114 } else {
115 this.nameControl_ = $.createDom('span').text(this.name_);
116 }
117
118 this.element_.append(this.nameControl_);
119 };
120
121 /**
122 * @inheritDoc
123 */
124 armadillo.PathControl.prototype.enterDocument = function() {
125 armadillo.PathControl.superClass_.enterDocument.call(this);
126 this.nameControl_.getElement().focus();
127 };
128
129 /**
130 * Creates a node for a single path component.
131 * @param {string} path The path up to this point.
132 * @param {string} name The current component after |path|.
133 */
134 armadillo.PathControl.prototype.createComponentNode_ = function(path, name) {
135 var menu = $.createDom('select');
136 this.fetchMenuContents_(path, name, menu);
137
138 var option = $.createDom('option');
139 option.text(name).attr('selected', 'selected');
140
141 menu.append(option);
142 menu.change(this.componentChanged_.bind(this));
143
144 return menu;
145 };
146
147 /**
148 * Queries the back-end for all the items at a given path and attaches them to
149 * the given menu.
150 * @param {string} path The path to get a list of items in
151 * @param {string} name The name to select
152 * @param {goog.ui.Menu} The menu to attach items to
153 */
154 armadillo.PathControl.prototype.fetchMenuContents_ = function(path, name, menu) {
155 var callback = function(e) {
156 var data = e.target.getResponseJson();
157 if (data['error']) {
158 app.showError(data['message']);
159 return;
160 }
161 if (path == '') {
162 // If this is the root path element, make sure the root is accessible for
163 // moving items.
164 goog.array.insertAt(data, '/', 0);
165 }
166 menu.empty();
167 $.each(data, function (i, caption) {
168 // It only makes sense to be able to move into directories.
169 if (!app.isDirectory(caption)) {
170 return;
171 }
172 var item = $.createDom('option');
173 item.val(app.joinPath(path, name, caption)).text(caption);
174 menu.append(item);
175 if (caption == name) {
176 item.attr('selected', 'selected');
177 }
178 });
179 };
180 app.sendRequest('list', {'path' : app.joinPath(path, name)}, callback);
181 };
182
183 /**
184 * Handler for changing a component of the control.
185 * @param {Event} e
186 */
187 armadillo.PathControl.prototype.componentChanged_ = function(e) {
188 this.path_ = $(e.target).val();
189 this.element_.empty();
190 this.decorateInternal(this.element_);
191 };
192
193 /**
194 * Handler for changing the editable name component.
195 * @param {Event} e
196 */
197 armadillo.PathControl.prototype.nameChanged_ = function(e) {
198 console.log(e);
199 // TODO: assert(this.editableLastComponent_)
200 this.name_ = e.target.value;
201 e.stopPropagation();
202 return true;
203 };