Start changing the Actor from a flying pop-up to a zippy expander.
[armadillo.git] / web_frontend / actor.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.Actor');
11 goog.provide('armadillo.Actor.TileControlRenderer_');
12
13 goog.require('armadillo.PathControl');
14 goog.require('goog.array');
15 goog.require('goog.dom');
16 goog.require('goog.events');
17 goog.require('goog.events.EventHandler');
18 goog.require('goog.style');
19 goog.require('goog.ui.Container');
20 goog.require('goog.ui.Dialog');
21
22 /**
23 * The Actor is a popup that displays the various actions that can be performed
24 * on a given File.
25 * @param {armadillo.File} file The file to act on.
26 * @param {goog.dom.DomHelper} opt_domHelper
27 * @constructor
28 */
29 armadillo.Actor = function(file, opt_domHelper) {
30 goog.ui.Container.call(this, null, null, opt_domHelper);
31
32 /**
33 * The file object on which this acts.
34 * @type {armadillo.File}
35 */
36 this.file_ = file;
37
38 /**
39 * Registrar for all the Actor's events.
40 * @type {goog.events.EventHandler}
41 */
42 this.eh_ = new goog.events.EventHandler();
43
44 /**
45 * The UI element used for a specific action.
46 * @type {goog.Disposable}
47 */
48 this.actionObject_ = null;
49 }
50 goog.inherits(armadillo.Actor, goog.ui.Container);
51
52 /**
53 * The different options that the Actor can perform.
54 */
55 armadillo.Actor.options_ = {
56 OPEN : 'open',
57 MOVE : 'move',
58 RENAME : 'rename',
59 DELETE : 'delete'
60 };
61
62 /**
63 * String values for the options.
64 */
65 armadillo.Actor.optionStrings_ = {
66 'open' : 'Open',
67 'move' : 'Move',
68 'rename' : 'Rename',
69 'delete' : 'Delete'
70 };
71
72 /**
73 * Disposer
74 * @protected
75 */
76 armadillo.Actor.prototype.disposeInternal = function() {
77 armadillo.Actor.superClass_.disposeInternal.call(this);
78
79 this.eh_.dispose();
80
81 // Remove the actor display element.
82 goog.dom.removeNode(this.element_);
83 this.element_ = null;
84
85 if (this.actionObject_) {
86 this.actionObject_.dispose();
87 this.actionObject_ = null;
88 }
89
90 this.file_ = null;
91 };
92
93 /**
94 * Decorates the given element into a path control.
95 * @param {Element} element
96 */
97 armadillo.Actor.prototype.decorateInternal = function(element) {
98 this.element_ = element;
99 goog.dom.classes.add(this.element_, 'actor');
100 this.dom_.removeChildren(this.element_);
101 for (var option in armadillo.Actor.options_) {
102 var tile = this.createTile_(option);
103 if (tile) {
104 this.addChild(tile, true);
105 }
106 }
107 };
108
109 /**
110 * Creates the DOM Element that is inserted into the popup.
111 * @param {armadillo.Actor.options_} Key of the option to create
112 * @returns {goog.ui.Control}
113 */
114 armadillo.Actor.prototype.createTile_ = function(option) {
115 var value = armadillo.Actor.options_[option];
116
117 // Create the title element.
118 var title = this.dom_.createDom('span', 'title',
119 armadillo.Actor.optionStrings_[value]);
120
121 var tile = new goog.ui.Control(title, new armadillo.Actor.TileControlRenderer_());
122 tile.actorOption = value;
123
124 // Cannot open non-directory files.
125 if (value == armadillo.Actor.options_.OPEN && !this.file_.isDirectory()) {
126 return null;
127 }
128
129 this.eh_.listen(tile, goog.ui.Component.EventType.ACTION,
130 this.tileClickHandler_, false, this);
131 return tile;
132 };
133
134 /**
135 * Click handler for individual tiles.
136 * @param {Event} e
137 */
138 armadillo.Actor.prototype.tileClickHandler_ = function(e) {
139 var option = e.target.actorOption;
140 if (option == armadillo.Actor.options_.OPEN) {
141 // TODO: assert that this.file_.isDirectory().
142 app.navigate(this.file_.getName());
143 } else if (option == armadillo.Actor.options_.MOVE ||
144 option == armadillo.Actor.options_.RENAME) {
145 this.performMove_();
146 } else if (option == armadillo.Actor.options_.DELETE) {
147 this.performDelete_();
148 }
149 this.hide();
150 };
151
152 /**
153 * Subroutine to handle bringing up the move confirmation UI.
154 * @private
155 */
156 armadillo.Actor.prototype.performMove_ = function() {
157 this.actionObject_ = this.createActionDialog_();
158 this.actionObject_.setTitle('Move File');
159
160 var editor = new armadillo.PathControl(this.file_.getFullPath(), true);
161 this.actionObject_.addChild(editor, true);
162
163 var closeCallback = function(e) {
164 if (e.key != goog.ui.Dialog.DefaultButtonKeys.CANCEL) {
165 var newPath = editor.getPath();
166 this.file_.move(newPath);
167 }
168 this.dispose();
169 };
170 // Will be removed when the event source closes.
171 this.eh_.listen(this.actionObject_, goog.ui.Dialog.SELECT_EVENT,
172 closeCallback, false, this);
173
174 this.actionObject_.setVisible(true);
175 var position = goog.style.getPosition(this.actionObject_.getElement());
176 goog.style.setPosition(this.actionObject_.getElement(), position.x, '10%');
177 };
178
179 /**
180 * Subroutine to handle bringing up the delete confirmation UI.
181 * @private
182 */
183 armadillo.Actor.prototype.performDelete_ = function() {
184 this.actionObject_ = this.createActionDialog_();
185 this.actionObject_.setTitle('Confirm Delete');
186
187 var container = this.actionObject_.getContentElement();
188 var content = goog.dom.createDom('span', null,
189 'Are you sure you want to delete:',
190 goog.dom.createElement('br'),
191 goog.dom.createDom('strong', null, this.file_.getName()));
192 goog.dom.appendChild(container, content);
193
194 var closeCallback = function(e) {
195 if (e.key != goog.ui.Dialog.DefaultButtonKeys.CANCEL) {
196 this.file_.remove();
197 }
198 this.dispose();
199 };
200 // Will be removed when the event source closes.
201 this.eh_.listen(this.actionObject_, goog.ui.Dialog.SELECT_EVENT,
202 closeCallback, false, this);
203
204 this.actionObject_.setVisible(true);
205 };
206
207 /**
208 * Creates a new instance of a Dialog that has some basic properties set that
209 * are common to performing actions.
210 * @private
211 */
212 armadillo.Actor.prototype.createActionDialog_ = function() {
213 var confirm = new goog.ui.Dialog();
214 confirm.setDisposeOnHide(true);
215 confirm.setEscapeToCancel(true);
216 confirm.setModal(true);
217 confirm.setDraggable(false);
218 confirm.setHasTitleCloseButton(false);
219 return confirm;
220 };
221
222 /**
223 * Event handler for when this.popup_ closes.
224 * @param {Event} e
225 */
226 armadillo.Actor.prototype.onPopupClosed_ = function(e) {
227 // If an action is not being performed, then dispose the Actor. Otherwise,
228 // this will get cleaned up after the actionObject_ closes.
229 if (!this.actionObject_) {
230 this.file_.setHighlight(armadillo.File.Highlight.SELECTED);
231 this.dispose();
232 }
233 };
234
235 /**
236 * Tile Control Renderer
237 * @constructor
238 */
239 armadillo.Actor.TileControlRenderer_ = function() {
240 goog.ui.ControlRenderer.call(this);
241 };
242 goog.inherits(armadillo.Actor.TileControlRenderer_, goog.ui.ControlRenderer);
243
244 /**
245 * Returns the control's contents wrapped in a DIV, with the renderer's own
246 * CSS class and additional state-specific classes applied to it.
247 * @param {goog.ui.Control} control Control to render.
248 * @return {Element} Root element for the control.
249 */
250 armadillo.Actor.TileControlRenderer_.prototype.createDom = function(control) {
251 // Create and return DIV wrapping contents.
252 return control.getDomHelper().createDom('div', 'tile', control.getContent());
253 };