Document actor.js's members and store any dialogs/deeper UI in the actionObject_.
[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
12 goog.require('armadillo.PathControl');
13 goog.require('goog.array');
14 goog.require('goog.dom');
15 goog.require('goog.events');
16 goog.require('goog.positioning.ClientPosition');
17 goog.require('goog.positioning.Corner');
18 goog.require('goog.style');
19 goog.require('goog.ui.Dialog');
20 goog.require('goog.ui.Popup');
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 * @constructor
27 */
28 armadillo.Actor = function(file) {
29 goog.Disposable.call(this);
30
31 /**
32 * The file object on which this acts.
33 * @type {armadillo.File}
34 */
35 this.file_ = file;
36
37 /**
38 * The HTML element that draws the actor buttons
39 * @type {Element}
40 */
41 this.element_ = this.createElement_();
42
43 /**
44 * The Container that holds the display element.
45 * @type {goog.ui.Popup}
46 */
47 this.popup_ = new goog.ui.Popup(this.element_);
48
49 /**
50 * The UI element used for a specific action.
51 * @type {goog.Disposable}
52 */
53 this.actionObject_ = null;
54
55 armadillo.Actor.actors_.push(this);
56 }
57 goog.inherits(armadillo.Actor, goog.Disposable);
58
59 /**
60 * An array of all the Actors that have been created.
61 */
62 armadillo.Actor.actors_ = new Array();
63
64 /**
65 * The different options that the Actor can perform.
66 */
67 armadillo.Actor.options_ = {
68 OPEN : 'open',
69 MOVE : 'move',
70 RENAME : 'rename',
71 DELETE : 'delete'
72 };
73
74 /**
75 * String values for the options.
76 */
77 armadillo.Actor.optionStrings_ = {
78 'open' : 'Open',
79 'move' : 'Move',
80 'rename' : 'Rename',
81 'delete' : 'Delete'
82 };
83
84 /**
85 * A global property that should be checked to see if an actor is present,
86 * creating a modal session.
87 */
88 armadillo.Actor.isModal = function() {
89 var isVisible = false;
90 goog.array.forEach(armadillo.Actor.actors_, function (e) {
91 isVisible |= e.popup_.isVisible();
92 });
93 return isVisible;
94 };
95
96 /**
97 * Disposer
98 * @protected
99 */
100 armadillo.Actor.prototype.disposeInternal = function() {
101 armadillo.Actor.superClass_.disposeInternal.call(this);
102
103 // Unlisten the tiles.
104 var tiles = goog.dom.getElementsByClassName('tile', this.element_);
105 goog.array.forEach(tiles, function (tile) {
106 goog.events.unlistenByKey(tile.actorListener);
107 });
108
109 // Remove the actor display element.
110 goog.dom.removeNode(this.element_);
111 this.element_ = null;
112
113 // Kill the popup.
114 this.popup_.dispose();
115 this.popup_ = null;
116
117 if (this.actionObject_) {
118 this.actionObject_.dispose();
119 this.actionObject_ = null;
120 }
121
122 // Remove the actor from the list.
123 goog.array.remove(armadillo.Actor.actors_, this);
124
125 this.file_ = null;
126 };
127
128 /**
129 * Shows the popup.
130 * @param {int} x The X position to show at
131 * @param {int} y The Y position to show at
132 */
133 armadillo.Actor.prototype.show = function(x, y) {
134 if (armadillo.Actor.isModal())
135 return;
136 var firstBodyElement = goog.dom.getFirstElementChild(document.body);
137 goog.dom.insertSiblingBefore(this.element_, firstBodyElement);
138 this.popup_.setPinnedCorner(goog.positioning.Corner.TOP_LEFT);
139 this.popup_.setPosition(new goog.positioning.ClientPosition(x, y));
140 this.popup_.setHideOnEscape(true);
141 this.popup_.setVisible(true);
142 };
143
144 /**
145 * Hides the popup.
146 */
147 armadillo.Actor.prototype.hide = function() {
148 this.popup_.setVisible(false);
149 };
150
151 /**
152 * Creates the DOM Element that is inserted into the popup.
153 * @returns Element
154 */
155 armadillo.Actor.prototype.createElement_ = function() {
156 var root = goog.dom.createDom('div', 'actor');
157 for (var option in armadillo.Actor.options_) {
158 var tile = goog.dom.createDom('div', 'tile');
159 var value = armadillo.Actor.options_[option];
160 // Cannot open non-directory files.
161 if (value == armadillo.Actor.options_.OPEN && !this.file_.isDirectory()) {
162 continue;
163 }
164 var title = goog.dom.createDom('span', 'title',
165 armadillo.Actor.optionStrings_[value]);
166 goog.dom.appendChild(tile, title);
167 goog.dom.appendChild(root, tile);
168 tile.actorOption = value;
169 tile.actorListener = goog.events.listen(tile, goog.events.EventType.CLICK,
170 this.tileClickHandler_, false, this);
171 }
172 return root;
173 };
174
175 /**
176 * Click handler for individual tiles.
177 * @param {Event} e
178 */
179 armadillo.Actor.prototype.tileClickHandler_ = function(e) {
180 var option = e.target.actorOption;
181 if (option == armadillo.Actor.options_.OPEN) {
182 // TODO: assert that this.file_.isDirectory().
183 app.navigate(this.file_.getName());
184 } else if (option == armadillo.Actor.options_.MOVE ||
185 option == armadillo.Actor.options_.RENAME) {
186 this.performMove_();
187 } else if (option == armadillo.Actor.options_.DELETE) {
188 this.performDelete_();
189 }
190 this.hide();
191 };
192
193 /**
194 * Subroutine to handle bringing up the move confirmation UI.
195 * @private
196 */
197 armadillo.Actor.prototype.performMove_ = function() {
198 this.actionObject_ = this.createActionDialog_();
199 this.actionObject_.setTitle('Move File');
200
201 var editor = new armadillo.PathControl(this.file_.getFullPath(), true);
202 this.actionObject_.addChild(editor, true);
203
204 var closeCallback = function(e) {
205 if (e.key != goog.ui.Dialog.DefaultButtonKeys.CANCEL) {
206 var newPath = editor.getPath();
207 this.file_.move(newPath);
208 }
209 this.dispose();
210 };
211 // Will be removed when the event source closes.
212 goog.events.listen(this.actionObject_, goog.ui.Dialog.SELECT_EVENT,
213 closeCallback, false, this);
214
215 this.actionObject_.setVisible(true);
216 var position = goog.style.getPosition(this.actionObject_.getElement());
217 goog.style.setPosition(this.actionObject_.getElement(), position.x, '10%');
218 };
219
220 /**
221 * Subroutine to handle bringing up the delete confirmation UI.
222 * @private
223 */
224 armadillo.Actor.prototype.performDelete_ = function() {
225 this.actionObject_ = this.createActionDialog_();
226 confirm.setTitle('Confirm Delete');
227
228 var container = this.actionObject_.getContentElement();
229 var content = goog.dom.createDom('span', null,
230 'Are you sure you want to delete:',
231 goog.dom.createElement('br'),
232 goog.dom.createDom('strong', null, this.file_.getName()));
233 goog.dom.appendChild(container, content);
234
235 var closeCallback = function(e) {
236 if (e.key != goog.ui.Dialog.DefaultButtonKeys.CANCEL) {
237 this.file_.remove();
238 }
239 this.dispose();
240 };
241 // Will be removed when the event source closes.
242 goog.events.listen(this.actionObject_, goog.ui.Dialog.SELECT_EVENT,
243 closeCallback, false, this);
244
245 this.actionObject_.setVisible(true);
246 };
247
248 /**
249 * Creates a new instance of a Dialog that has some basic properties set that
250 * are common to performing actions.
251 * @private
252 */
253 armadillo.Actor.prototype.createActionDialog_ = function() {
254 var confirm = new goog.ui.Dialog();
255 confirm.setDisposeOnHide(true);
256 confirm.setEscapeToCancel(true);
257 confirm.setModal(true);
258 confirm.setDraggable(false);
259 confirm.setHasTitleCloseButton(false);
260 return confirm;
261 };