1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
|
/* Copyright (c) 2009, Canonical Ltd. All rights reserved. */
YUI.add('lazr.overlay', function(Y) {
/**
* LAZR-specific overlay implementation.
*
* @module lazr.overlay
*/
var ESCAPE = 27,
CANCEL = 'cancel',
BOUNDING_BOX = 'boundingBox',
CONTENT_BOX = 'contentBox',
BINDUI = "bindUI";
/**
* An Overlay subclass which draws a rounded-corner, drop-shadow
* border around the content.
* TODO PrettyOverlay implements an in-page modal dialog box.
* The background is blocked using a layer, in order to prevent
* clicks on other elements on the page. Pressing Escape or clicking
* the close button at the top-right corner dismisses the box.
*
* Note: Classes extending PrettyOverlay must have a corresponding
* yui3-widget-name-hidden CSS class in order to allow hiding.
* Also, all extending classes must explicitly calls PrettyOverlay's
* bindUI method in order to get the event handlers attached.
*
* @class PrettyOverlay
* @namespace lazr
*/
var PrettyOverlay = function(cfg) {
// Check whether the callsite has set a zIndex... if not, set it
// to 1000, as the YUI.overlay default is zero.
if (cfg && arguments[0].zIndex === undefined){
arguments[0].zIndex = 1000;
}
PrettyOverlay.superclass.constructor.apply(this, arguments);
Y.after(this._bindUIPrettyOverlay, this, BINDUI);
};
PrettyOverlay.NAME = 'pretty-overlay';
PrettyOverlay.ATTRS = {
/**
* The value, in percentage, of the progress bar.
*
* @attribute progress
* @type Float
* @default 100
*/
progress: {
value: 100
},
/**
* Should the progress bar be shown?
* (note that if set to true, headerContent must be supplied).
*
* @attribute progressbar
* @type Boolean
* @default true
*/
progressbar: {
value: true
},
/**
* Title for this step, displayed below the progressbar.
* (you must have a progressbar to have a steptitle)
*
* @attribute steptitle
* @type Boolean
* @default null
*/
steptitle: {
value: null
}
};
Y.extend(PrettyOverlay, Y.Overlay, {
/**
* The div element shown behind the modal dialog.
*
* @private
* @property _blocking_div
* @type Node
*/
_blocking_div: null,
/**
* The key press handler..
*
* @private
* @property _doc_kp_handler
* @type EventHandle
*/
_doc_kp_handler: null,
/**
* The div displaying the prograss bar.
*
* @private
* @property _green_bar
* @type Node
*/
_green_bar: null,
/**
* Create the DOM elements needed by the widget.
*
* @protected
* @method initializer
*/
initializer: function() {
// The 20% width style is here to force
// legacy browsers to include an accessible
// style attribute.
this._green_bar = Y.Node.create([
'<div class="steps">',
'<div class="step-on" style="width:20%;">',
'</div></div>'].join(""));
this._blocking_div = Y.Node.create(
'<div class="blocking-div"></div>');
this.after("renderedChange", function() {
var bounding_box = this.get(BOUNDING_BOX);
var content_box = this.get(CONTENT_BOX);
var content_box_container = bounding_box.one(
".content_box_container");
if (content_box_container) {
content_box_container.appendChild(content_box);
}
this._setupCloseFacilities();
});
this.after('visibleChange', function(e) {
this._setupCloseFacilities();
});
/**
* Fires when the user presses the 'Cancel' button.
*
* @event cancel
* @preventable _defCancel
*/
this.publish(CANCEL, {
defaultFn: this._defaultCancel
});
},
/**
* Event handler to update HTML when steptitle is set.
*
* @private
* @param e {Event.Facade}
* @method _afterSteptitleChange
*/
_afterSteptitleChange: function(e) {
// It's only possible to have a step title
// if you also have a progress bar.
var progress_bar = this.get(BOUNDING_BOX).one(".steps");
if (!progress_bar) {
return;
}
var h2 = progress_bar.one("h2");
if (!h2) {
h2 = Y.Node.create("<h2></h2>");
progress_bar.appendChild(h2);
progress_bar.addClass("contains-steptitle");
}
// We can't just set innerHTML here because Firefox gets it wrong
// so remove all existing nodes and add the steptitle as a textnode
while (h2.hasChildNodes()) {
h2.removeChild(h2.get("firstChild"));
}
h2.appendChild(document.createTextNode(this.get("steptitle")));
},
/**
* Handle the progress change event, adjusting the display
* of the progress bar.
*
* @private
* @param e {Event.Facade}
* @method _afterProgressChange
*/
_afterProgressChange: function(e) {
var width = parseInt(this.get("progress"), 10);
if (width < 0) {
width = 0;
}
if (width > 100) {
width = 100;
}
if (this.get("progressbar") &&
this.get(CONTENT_BOX).one(".steps")) {
// The prograss bar is only being created if
// you both ask for it and supply header content
var progress_steps = this.get(CONTENT_BOX).one(".step-on");
progress_steps.setStyle("width", width + "%");
}
},
/**
* Hook the events for the escape key press and include
* the blocking div.
*
* @protected
* @method _setupCloseFacilities
*/
_setupCloseFacilities: function() {
var self = this;
var visible = this.get('visible');
if (visible) {
Y.one('body').appendChild(this._blocking_div);
// Handle Escape (code 27) on keydown.
this._doc_kp_handler = Y.on('key', function() {
self.fire(CANCEL);
}, document, 'down:27');
} else {
this._removeBlockingDiv();
}
},
/**
* Remove the HTML for the blocking DIV.
*
* @method _removeBlockingDiv
*/
_removeBlockingDiv: function() {
if (this._blocking_div) {
var blocking_div = Y.one(this._blocking_div);
if (blocking_div) {
var parent = blocking_div.get('parentNode');
if (parent) {
parent.removeChild(this._blocking_div);
}
}
}
},
/**
* Destroy the widget (remove its HTML from the page).
*
* @method destructor
*/
destructor: function() {
this._removeBlockingDiv();
if (this._doc_kp_handler) {
this._doc_kp_handler.detach();
}
},
/**
* Bind UI events.
* <p>
* This method is invoked after bindUI is invoked for the Widget class
* using YUI's aop infrastructure.
* </p>
*
* @method _bindUIPrettyOverlay
* @protected
*/
_bindUIPrettyOverlay: function() {
var self = this;
var close_button = this.get(BOUNDING_BOX).one('.close a');
close_button.on('click', function(e) {
e.halt();
self.fire(CANCEL);
});
this._blocking_div.on('click', function(e) {
e.halt();
self.fire(CANCEL);
});
// Ensure that when the overlay is clicked, it doesn't stay
// focused (with the ugly gray border).
var bounding_box = this.get(BOUNDING_BOX);
bounding_box.on('click', function(e) {
bounding_box.blur();
});
this.after('steptitleChange', this._afterSteptitleChange);
this.after('progressChange', this._afterProgressChange);
},
/**
* Event handler for cancel event; hides the widget.
*
* @private
* @method _defaultCancel
*/
_defaultCancel: function(e) {
this.hide();
this._doc_kp_handler.detach();
},
/**
* Overrides the method from WidgetStdMod which creates the separate
* sections in the contentBox to also add the progressbar widget
* after headerContent.
*
* @private
* @method _insertStdModSection
*/
_insertStdModSection: function(content_box, section, section_node) {
PrettyOverlay.superclass._insertStdModSection.apply(
this, arguments);
if (section === Y.WidgetStdMod.HEADER &&
this.get("progressbar"))
{
var nxt = section_node.next();
if (nxt) {
content_box.insertBefore(this._green_bar, nxt);
} else {
content_box.appendChild(this._green_bar);
}
}
this._afterProgressChange();
if (this.get('steptitle')) {
this._afterSteptitleChange();
}
}
});
/**
* The HTML for drawing the border.
*
* The border is implemented using a table. The content area is
* marked with the `content_box_container` class so that the widget
* can find it and insert the content box into it.
*
* @property BOUNDING_TEMPLATE
*/
PrettyOverlay.prototype.BOUNDING_TEMPLATE = [
'<div class="pretty-overlay-window">',
'<div class="content_box_container" id="yui3-pretty-overlay-modal">',
'<div class="close">',
'<a href="#" title="Close" class="close-button"></a>',
'</div>',
'</div>',
'</div>'].join('');
Y.namespace('lazr');
Y.lazr.PrettyOverlay = PrettyOverlay;
}, "0.1", {"skinnable": true, "requires": ["oop", "overlay", "event", "widget", "widget-stack", "widget-position"]});
|