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