Remove the Users map now that it is taken care of by MFE
[armadillo.git] / web_frontend / path_control.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.PathControl');
11 goog.provide('armadillo.PathControl.NameControlRenderer_');
12
13 goog.require('goog.array');
14 goog.require('goog.ui.Control');
15 goog.require('goog.ui.FilteredMenu');
16 goog.require('goog.ui.LabelInput');
17 goog.require('goog.ui.MenuButton');
18 goog.require('goog.ui.MenuItem');
19
20 /**
21 * Creates a new path editing control for a given path.
22 * @param {string} path The path to create an editor for
23 * @param {bool} editLastComponent Whether the last component should be shown as an edit box
24 * @param {DomHelper} opt_domHelper Optional DOM helper
25 * @constructor
26 */
27 armadillo.PathControl = function(path, editLastComponent, opt_domHelper) {
28 goog.ui.Control.call(this, opt_domHelper);
29
30 this.setHandleMouseEvents(false);
31 this.setSupportedState(goog.ui.Component.State.FOCUSED, false);
32
33 /**
34 * Full path of the control.
35 * @type {string}
36 */
37 this.path_ = null;
38
39 /**
40 * The name of the file at the |path_|.
41 * @type {string}
42 */
43 this.name_ = null;
44 this.setPath(path);
45
46 /**
47 * Whether or not the last component is editable.
48 * @type {bool}
49 */
50 this.editableLastComponent_ = editLastComponent;
51
52 /**
53 * Control UI for the name component of the path.
54 * @type {goog.ui.Control}
55 */
56 this.nameControl_ = null;
57
58 /**
59 * Event Handler
60 * @type {goog.events.EventHandler}
61 */
62 this.eh_ = new goog.events.EventHandler();
63 };
64 goog.inherits(armadillo.PathControl, goog.ui.Control);
65
66 /**
67 * Disposer
68 * @protected
69 */
70 armadillo.PathControl.prototype.disposeInternal = function() {
71 armadillo.PathControl.superClass_.disposeInternal.call(this);
72 this.nameControl_ = null;
73
74 this.eh_.dispose();
75 this.eh_ = null;
76 };
77
78 /**
79 * Sets the path.
80 * @param {string} path
81 */
82 armadillo.PathControl.prototype.setPath = function(path) {
83 this.path_ = app.stripLastPathComponent(path);
84 this.name_ = path.substr(this.path_.length);
85 };
86
87 /**
88 * Gets the new path.
89 * @returns {string}
90 */
91 armadillo.PathControl.prototype.getPath = function() {
92 return app.joinPath(this.path_, this.name_);
93 };
94
95 /**
96 * Gets the name control.
97 * @returns {goog.ui.Control}
98 */
99 armadillo.PathControl.prototype.getNameControl = function() {
100 return this.nameControl_;
101 };
102
103 /**
104 * Creates a new path control object.
105 */
106 armadillo.PathControl.prototype.createDom = function() {
107 this.decorateInternal(this.dom_.createElement('div'));
108 };
109
110 /**
111 * @inheritDoc
112 */
113 armadillo.PathControl.prototype.canDecorate = function() {
114 return true;
115 };
116
117 /**
118 * Decorates the given element into a path control.
119 * @param {Element} element
120 */
121 armadillo.PathControl.prototype.decorateInternal = function(element) {
122 this.element_ = element;
123 var components = this.path_.split('/');
124
125 // If this is an item that lives at the root, generate a special node for
126 // moving between items at the top level.
127 components[0] = '/';
128
129 // If the last component is emtpy, do not use it because it means a directory
130 // is being moved.
131 if (components[components.length - 1] == '') {
132 goog.array.removeAt(components, components.length - 1);
133 }
134
135 var path = '';
136 goog.array.forEach(components, function (part, i) {
137 this.addChild(this.createComponentNode_(path, part), true);
138 path = app.joinPath(path, part);
139 }, this);
140
141 if (this.editableLastComponent_) {
142 var attrs = {
143 'type' : 'text',
144 'name' : 'pathName',
145 'value' : this.name_
146 };
147 this.nameControl_ = new goog.ui.Control(this.dom_.createDom('input', attrs),
148 new armadillo.PathControl.NameControlRenderer_());
149 this.nameControl_.setAllowTextSelection(true);
150 this.nameControl_.setHandleMouseEvents(false);
151 this.addChild(this.nameControl_, true);
152
153 this.eh_.listen(this.nameControl_.getElement(), goog.events.EventType.CHANGE,
154 this.nameChanged_, false, this);
155 this.eh_.listen(this.nameControl_.getElement(), goog.events.EventType.KEYDOWN,
156 this.nameChanged_, false, this);
157 } else {
158 this.nameControl_ = new goog.ui.Control(this.name_);
159 this.addChild(this.nameControl_, true);
160 }
161 goog.dom.classes.add(this.nameControl_.getElement(), 'goog-inline-block');
162 };
163
164 /**
165 * @inheritDoc
166 */
167 armadillo.PathControl.prototype.enterDocument = function() {
168 armadillo.PathControl.superClass_.enterDocument.call(this);
169 this.nameControl_.getElement().focus();
170 };
171
172 /**
173 * Creates a node for a single path component.
174 * @param {string} path The path up to this point.
175 * @param {string} name The current component after |path|.
176 */
177 armadillo.PathControl.prototype.createComponentNode_ = function(path, name) {
178 var menu = new goog.ui.FilteredMenu();
179 menu.setFilterLabel(name);
180 menu.setAllowMultiple(false);
181 menu.setOpenFollowsHighlight(true);
182 goog.events.listen(menu, goog.ui.Component.EventType.ACTION,
183 this.componentChanged_, false, this);
184 this.fetchMenuContents_(path, name, menu);
185
186 var button = new goog.ui.MenuButton(name, menu, null, this.dom_);
187 button.setFocusablePopupMenu(true);
188 button.setScrollOnOverflow(true);
189 button.setVisible(true);
190 return button;
191 };
192
193 /**
194 * Queries the back-end for all the items at a given path and attaches them to
195 * the given menu.
196 * @param {string} path The path to get a list of items in
197 * @param {string} name The name to select
198 * @param {goog.ui.Menu} The menu to attach items to
199 */
200 armadillo.PathControl.prototype.fetchMenuContents_ = function(path, name, menu) {
201 var callback = function(e) {
202 var data = e.target.getResponseJson();
203 if (data['error']) {
204 app.showError(data['message']);
205 return;
206 }
207 if (path == '') {
208 // If this is the root path element, make sure the root is accessible for
209 // moving items.
210 goog.array.insertAt(data, '/', 0);
211 }
212 goog.array.forEach(data, function (caption) {
213 // It only makes sense to be able to move into directories.
214 if (!app.isDirectory(caption)) {
215 return;
216 }
217 var item = new goog.ui.MenuItem(caption);
218 item.setValue(app.joinPath(path, name, caption));
219 menu.addItem(item);
220 if (caption == name) {
221 menu.setHighlighted(item);
222 }
223 });
224 };
225 app.sendRequest('list', {'path' : app.joinPath(path, name)}, callback);
226 };
227
228 /**
229 * Handler for changing a component of the control.
230 * @param {Event} e
231 */
232 armadillo.PathControl.prototype.componentChanged_ = function(e) {
233 this.path_ = e.target.getValue();
234 this.removeChildren(true);
235 this.decorateInternal(this.element_);
236 };
237
238 /**
239 * Handler for changing the editable name component.
240 * @param {Event} e
241 */
242 armadillo.PathControl.prototype.nameChanged_ = function(e) {
243 console.log(e);
244 // TODO: assert(this.editableLastComponent_)
245 this.name_ = e.target.value;
246 e.stopPropagation();
247 return true;
248 };
249
250 /**
251 * Renderer for the Name Control of the Path Control
252 * @constructor_
253 */
254 armadillo.PathControl.NameControlRenderer_ = function() {
255 goog.ui.ControlRenderer.call(this);
256 };
257 goog.inherits(armadillo.PathControl.NameControlRenderer_, goog.ui.ControlRenderer);
258
259 armadillo.PathControl.NameControlRenderer_.prototype.createDom = function(control) {
260 var content = control.getContent();
261 if (content instanceof HTMLElement) {
262 return content;
263 }
264 return armadillo.PathControl.NameControlRenderer_.superClass_.createDom.call(this, control);
265 };