vkhater-social_stream-events 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/.gitignore +10 -0
  2. data/Gemfile +5 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +26 -0
  5. data/app/assets/javascripts/0_init.js +4 -0
  6. data/app/assets/javascripts/events.js.coffee +66 -0
  7. data/app/assets/javascripts/social_stream-events.js +1 -0
  8. data/app/assets/stylesheets/events.css.scss +66 -0
  9. data/app/assets/stylesheets/social_stream-events.css +3 -0
  10. data/app/controllers/events_controller.rb +40 -0
  11. data/app/controllers/rooms_controller.rb +7 -0
  12. data/app/helpers/events_helper.rb +16 -0
  13. data/app/models/event.rb +53 -0
  14. data/app/models/room.rb +8 -0
  15. data/app/views/events/_calendar_month.erb +1 -0
  16. data/app/views/events/_event.html.erb +1 -0
  17. data/app/views/events/_new.html.erb +40 -0
  18. data/app/views/events/_sidebar_calendar.html.erb +34 -0
  19. data/app/views/events/create.js.erb +21 -0
  20. data/app/views/events/destroy.js.erb +1 -0
  21. data/app/views/events/index.html.erb +99 -0
  22. data/app/views/rooms/_form.html.erb +31 -0
  23. data/app/views/rooms/_index.html.erb +10 -0
  24. data/app/views/rooms/_settings.html.erb +23 -0
  25. data/app/views/rooms/create.js.erb +7 -0
  26. data/app/views/rooms/destroy.js.erb +1 -0
  27. data/config/locales/en.yml +35 -0
  28. data/config/locales/es.yml +35 -0
  29. data/config/routes.rb +3 -0
  30. data/db/migrate/20111101193523_create_events.rb +13 -0
  31. data/db/migrate/20111120104349_create_rooms.rb +26 -0
  32. data/db/migrate/20111204155637_add_scheduler.rb +33 -0
  33. data/db/migrate/20111218203314_change_scheduler.rb +11 -0
  34. data/lib/generators/social_stream/events/install_generator.rb +24 -0
  35. data/lib/social_stream-events.rb +27 -0
  36. data/lib/social_stream/events/ability.rb +13 -0
  37. data/lib/social_stream/events/engine.rb +29 -0
  38. data/lib/social_stream/events/models/actor.rb +13 -0
  39. data/lib/social_stream/events/version.rb +5 -0
  40. data/lib/social_stream/migrations/events.rb +8 -0
  41. data/lib/social_stream/toolbar_config/events.rb +22 -0
  42. data/lib/social_stream/views/settings/events.rb +18 -0
  43. data/lib/social_stream/views/sidebar/events.rb +15 -0
  44. data/social_stream-events.gemspec +24 -0
  45. data/vendor/assets/images/boxy-ne.png +0 -0
  46. data/vendor/assets/images/boxy-nw.png +0 -0
  47. data/vendor/assets/images/boxy-se.png +0 -0
  48. data/vendor/assets/images/boxy-sw.png +0 -0
  49. data/vendor/assets/javascripts/fullcalendar.js +5210 -0
  50. data/vendor/assets/javascripts/gcal.js +112 -0
  51. data/vendor/assets/javascripts/jquery.boxy.js +570 -0
  52. data/vendor/assets/javascripts/sprintf.js +183 -0
  53. data/vendor/assets/stylesheets/boxy.css +49 -0
  54. data/vendor/assets/stylesheets/fullcalendar.css +618 -0
  55. data/vendor/assets/stylesheets/fullcalendar.print.css +61 -0
  56. metadata +150 -0
@@ -0,0 +1,112 @@
1
+ /*
2
+ * FullCalendar v1.5.2 Google Calendar Plugin
3
+ *
4
+ * Copyright (c) 2011 Adam Shaw
5
+ * Dual licensed under the MIT and GPL licenses, located in
6
+ * MIT-LICENSE.txt and GPL-LICENSE.txt respectively.
7
+ *
8
+ * Date: Sun Aug 21 22:06:09 2011 -0700
9
+ *
10
+ */
11
+
12
+ (function($) {
13
+
14
+
15
+ var fc = $.fullCalendar;
16
+ var formatDate = fc.formatDate;
17
+ var parseISO8601 = fc.parseISO8601;
18
+ var addDays = fc.addDays;
19
+ var applyAll = fc.applyAll;
20
+
21
+
22
+ fc.sourceNormalizers.push(function(sourceOptions) {
23
+ if (sourceOptions.dataType == 'gcal' ||
24
+ sourceOptions.dataType === undefined &&
25
+ (sourceOptions.url || '').match(/^(http|https):\/\/www.google.com\/calendar\/feeds\//)) {
26
+ sourceOptions.dataType = 'gcal';
27
+ if (sourceOptions.editable === undefined) {
28
+ sourceOptions.editable = false;
29
+ }
30
+ }
31
+ });
32
+
33
+
34
+ fc.sourceFetchers.push(function(sourceOptions, start, end) {
35
+ if (sourceOptions.dataType == 'gcal') {
36
+ return transformOptions(sourceOptions, start, end);
37
+ }
38
+ });
39
+
40
+
41
+ function transformOptions(sourceOptions, start, end) {
42
+
43
+ var success = sourceOptions.success;
44
+ var data = $.extend({}, sourceOptions.data || {}, {
45
+ 'start-min': formatDate(start, 'u'),
46
+ 'start-max': formatDate(end, 'u'),
47
+ 'singleevents': true,
48
+ 'max-results': 9999
49
+ });
50
+
51
+ var ctz = sourceOptions.currentTimezone;
52
+ if (ctz) {
53
+ data.ctz = ctz = ctz.replace(' ', '_');
54
+ }
55
+
56
+ return $.extend({}, sourceOptions, {
57
+ url: sourceOptions.url.replace(/\/basic$/, '/full') + '?alt=json-in-script&callback=?',
58
+ dataType: 'jsonp',
59
+ data: data,
60
+ startParam: false,
61
+ endParam: false,
62
+ success: function(data) {
63
+ var events = [];
64
+ if (data.feed.entry) {
65
+ $.each(data.feed.entry, function(i, entry) {
66
+ var startStr = entry['gd$when'][0]['startTime'];
67
+ var start = parseISO8601(startStr, true);
68
+ var end = parseISO8601(entry['gd$when'][0]['endTime'], true);
69
+ var allDay = startStr.indexOf('T') == -1;
70
+ var url;
71
+ $.each(entry.link, function(i, link) {
72
+ if (link.type == 'text/html') {
73
+ url = link.href;
74
+ if (ctz) {
75
+ url += (url.indexOf('?') == -1 ? '?' : '&') + 'ctz=' + ctz;
76
+ }
77
+ }
78
+ });
79
+ if (allDay) {
80
+ addDays(end, -1); // make inclusive
81
+ }
82
+ events.push({
83
+ id: entry['gCal$uid']['value'],
84
+ title: entry['title']['$t'],
85
+ url: url,
86
+ start: start,
87
+ end: end,
88
+ allDay: allDay,
89
+ location: entry['gd$where'][0]['valueString'],
90
+ description: entry['content']['$t']
91
+ });
92
+ });
93
+ }
94
+ var args = [events].concat(Array.prototype.slice.call(arguments, 1));
95
+ var res = applyAll(success, this, args);
96
+ if ($.isArray(res)) {
97
+ return res;
98
+ }
99
+ return events;
100
+ }
101
+ });
102
+
103
+ }
104
+
105
+
106
+ // legacy
107
+ fc.gcalFeed = function(url, sourceOptions) {
108
+ return $.extend({}, sourceOptions, { url: url, dataType: 'gcal' });
109
+ };
110
+
111
+
112
+ })(jQuery);
@@ -0,0 +1,570 @@
1
+ /**
2
+ * Boxy 0.1.4 - Facebook-style dialog, with frills
3
+ *
4
+ * (c) 2008 Jason Frame
5
+ * Licensed under the MIT License (LICENSE)
6
+ */
7
+
8
+ /*
9
+ * jQuery plugin
10
+ *
11
+ * Options:
12
+ * message: confirmation message for form submit hook (default: "Please confirm:")
13
+ *
14
+ * Any other options - e.g. 'clone' - will be passed onto the boxy constructor (or
15
+ * Boxy.load for AJAX operations)
16
+ */
17
+ jQuery.fn.boxy = function(options) {
18
+ options = options || {};
19
+ return this.each(function() {
20
+ var node = this.nodeName.toLowerCase(), self = this;
21
+ if (node == 'a') {
22
+ jQuery(this).click(function() {
23
+ var active = Boxy.linkedTo(this),
24
+ href = this.getAttribute('href'),
25
+ localOptions = jQuery.extend({actuator: this, title: this.title}, options);
26
+
27
+ if (active) {
28
+ active.show();
29
+ } else if (href.indexOf('#') >= 0) {
30
+ var content = jQuery(href.substr(href.indexOf('#'))),
31
+ newContent = content.clone(true);
32
+ content.remove();
33
+ localOptions.unloadOnHide = false;
34
+ new Boxy(newContent, localOptions);
35
+ } else { // fall back to AJAX; could do with a same-origin check
36
+ if (!localOptions.cache) localOptions.unloadOnHide = true;
37
+ Boxy.load(this.href, localOptions);
38
+ }
39
+
40
+ return false;
41
+ });
42
+ } else if (node == 'form') {
43
+ jQuery(this).bind('submit.boxy', function() {
44
+ Boxy.confirm(options.message || 'Please confirm:', function() {
45
+ jQuery(self).unbind('submit.boxy').submit();
46
+ });
47
+ return false;
48
+ });
49
+ }
50
+ });
51
+ };
52
+
53
+ //
54
+ // Boxy Class
55
+
56
+ function Boxy(element, options) {
57
+
58
+ this.boxy = jQuery(Boxy.WRAPPER);
59
+ jQuery.data(this.boxy[0], 'boxy', this);
60
+
61
+ this.visible = false;
62
+ this.options = jQuery.extend({}, Boxy.DEFAULTS, options || {});
63
+
64
+ if (this.options.modal) {
65
+ this.options = jQuery.extend(this.options, {center: true, draggable: false});
66
+ }
67
+
68
+ // options.actuator == DOM element that opened this boxy
69
+ // association will be automatically deleted when this boxy is remove()d
70
+ if (this.options.actuator) {
71
+ jQuery.data(this.options.actuator, 'active.boxy', this);
72
+ }
73
+
74
+ this.setContent(element || "<div></div>");
75
+ this._setupTitleBar();
76
+
77
+ this.boxy.css('display', 'none').appendTo(document.body);
78
+ this.toTop();
79
+
80
+ if (this.options.fixed) {
81
+ if (jQuery.browser.msie && jQuery.browser.version < 7) {
82
+ this.options.fixed = false; // IE6 doesn't support fixed positioning
83
+ } else {
84
+ this.boxy.addClass('fixed');
85
+ }
86
+ }
87
+
88
+ if (this.options.center && Boxy._u(this.options.x, this.options.y)) {
89
+ this.center();
90
+ } else {
91
+ this.moveTo(
92
+ Boxy._u(this.options.x) ? this.options.x : Boxy.DEFAULT_X,
93
+ Boxy._u(this.options.y) ? this.options.y : Boxy.DEFAULT_Y
94
+ );
95
+ }
96
+
97
+ if (this.options.show) this.show();
98
+
99
+ };
100
+
101
+ Boxy.EF = function() {};
102
+
103
+ jQuery.extend(Boxy, {
104
+
105
+ WRAPPER: "<table cellspacing='0' cellpadding='0' border='0' class='boxy-wrapper'>" +
106
+ "<tr><td class='top-left'></td><td class='top'></td><td class='top-right'></td></tr>" +
107
+ "<tr><td class='left'></td><td class='boxy-inner'></td><td class='right'></td></tr>" +
108
+ "<tr><td class='bottom-left'></td><td class='bottom'></td><td class='bottom-right'></td></tr>" +
109
+ "</table>",
110
+
111
+ DEFAULTS: {
112
+ title: null, // titlebar text. titlebar will not be visible if not set.
113
+ closeable: true, // display close link in titlebar?
114
+ draggable: true, // can this dialog be dragged?
115
+ clone: false, // clone content prior to insertion into dialog?
116
+ actuator: null, // element which opened this dialog
117
+ center: true, // center dialog in viewport?
118
+ show: true, // show dialog immediately?
119
+ modal: false, // make dialog modal?
120
+ fixed: true, // use fixed positioning, if supported? absolute positioning used otherwise
121
+ closeText: '[close]', // text to use for default close link
122
+ unloadOnHide: false, // should this dialog be removed from the DOM after being hidden?
123
+ clickToFront: false, // bring dialog to foreground on any click (not just titlebar)?
124
+ behaviours: Boxy.EF, // function used to apply behaviours to all content embedded in dialog.
125
+ afterDrop: Boxy.EF, // callback fired after dialog is dropped. executes in context of Boxy instance.
126
+ afterShow: Boxy.EF, // callback fired after dialog becomes visible. executes in context of Boxy instance.
127
+ afterHide: Boxy.EF, // callback fired after dialog is hidden. executed in context of Boxy instance.
128
+ beforeUnload: Boxy.EF // callback fired after dialog is unloaded. executed in context of Boxy instance.
129
+ },
130
+
131
+ DEFAULT_X: 50,
132
+ DEFAULT_Y: 50,
133
+ zIndex: 1337,
134
+ dragConfigured: false, // only set up one drag handler for all boxys
135
+ resizeConfigured: false,
136
+ dragging: null,
137
+
138
+ // load a URL and display in boxy
139
+ // url - url to load
140
+ // options keys (any not listed below are passed to boxy constructor)
141
+ // type: HTTP method, default: GET
142
+ // cache: cache retrieved content? default: false
143
+ // filter: jQuery selector used to filter remote content
144
+ load: function(url, options) {
145
+
146
+ options = options || {};
147
+
148
+ var ajax = {
149
+ url: url, type: 'GET', dataType: 'html', cache: false, success: function(html) {
150
+ html = jQuery(html);
151
+ if (options.filter) html = jQuery(options.filter, html);
152
+ new Boxy(html, options);
153
+ }
154
+ };
155
+
156
+ jQuery.each(['type', 'cache'], function() {
157
+ if (this in options) {
158
+ ajax[this] = options[this];
159
+ delete options[this];
160
+ }
161
+ });
162
+
163
+ jQuery.ajax(ajax);
164
+
165
+ },
166
+
167
+ // allows you to get a handle to the containing boxy instance of any element
168
+ // e.g. <a href='#' onclick='alert(Boxy.get(this));'>inspect!</a>.
169
+ // this returns the actual instance of the boxy 'class', not just a DOM element.
170
+ // Boxy.get(this).hide() would be valid, for instance.
171
+ get: function(ele) {
172
+ var p = jQuery(ele).parents('.boxy-wrapper');
173
+ return p.length ? jQuery.data(p[0], 'boxy') : null;
174
+ },
175
+
176
+ // returns the boxy instance which has been linked to a given element via the
177
+ // 'actuator' constructor option.
178
+ linkedTo: function(ele) {
179
+ return jQuery.data(ele, 'active.boxy');
180
+ },
181
+
182
+ // displays an alert box with a given message, calling optional callback
183
+ // after dismissal.
184
+ alert: function(message, callback, options) {
185
+ return Boxy.ask(message, ['OK'], callback, options);
186
+ },
187
+
188
+ // displays an alert box with a given message, calling after callback iff
189
+ // user selects OK.
190
+ confirm: function(message, after, options) {
191
+ return Boxy.ask(message, ['OK', 'Cancel'], function(response) {
192
+ if (response == 'OK') after();
193
+ }, options);
194
+ },
195
+
196
+ // asks a question with multiple responses presented as buttons
197
+ // selected item is returned to a callback method.
198
+ // answers may be either an array or a hash. if it's an array, the
199
+ // the callback will received the selected value. if it's a hash,
200
+ // you'll get the corresponding key.
201
+ ask: function(question, answers, callback, options) {
202
+
203
+ options = jQuery.extend({modal: true, closeable: false},
204
+ options || {},
205
+ {show: true, unloadOnHide: true});
206
+
207
+ var body = jQuery('<div></div>').append(jQuery('<div class="question"></div>').html(question));
208
+
209
+ // ick
210
+ var map = {}, answerStrings = [];
211
+ if (answers instanceof Array) {
212
+ for (var i = 0; i < answers.length; i++) {
213
+ map[answers[i]] = answers[i];
214
+ answerStrings.push(answers[i]);
215
+ }
216
+ } else {
217
+ for (var k in answers) {
218
+ map[answers[k]] = k;
219
+ answerStrings.push(answers[k]);
220
+ }
221
+ }
222
+
223
+ var buttons = jQuery('<form class="answers"></form>');
224
+ buttons.html(jQuery.map(answerStrings, function(v) {
225
+ return "<input type='button' value='" + v + "' />";
226
+ }).join(' '));
227
+
228
+ jQuery('input[type=button]', buttons).click(function() {
229
+ var clicked = this;
230
+ Boxy.get(this).hide(function() {
231
+ if (callback) callback(map[clicked.value]);
232
+ });
233
+ });
234
+
235
+ body.append(buttons);
236
+
237
+ new Boxy(body, options);
238
+
239
+ },
240
+
241
+ // returns true if a modal boxy is visible, false otherwise
242
+ isModalVisible: function() {
243
+ return jQuery('.boxy-modal-blackout').length > 0;
244
+ },
245
+
246
+ _u: function() {
247
+ for (var i = 0; i < arguments.length; i++)
248
+ if (typeof arguments[i] != 'undefined') return false;
249
+ return true;
250
+ },
251
+
252
+ _handleResize: function(evt) {
253
+ var d = jQuery(document);
254
+ jQuery('.boxy-modal-blackout').css('display', 'none').css({
255
+ width: d.width(), height: d.height()
256
+ }).css('display', 'block');
257
+ },
258
+
259
+ _handleDrag: function(evt) {
260
+ var d;
261
+ if (d = Boxy.dragging) {
262
+ d[0].boxy.css({left: evt.pageX - d[1], top: evt.pageY - d[2]});
263
+ }
264
+ },
265
+
266
+ _nextZ: function() {
267
+ return Boxy.zIndex++;
268
+ },
269
+
270
+ _viewport: function() {
271
+ var d = document.documentElement, b = document.body, w = window;
272
+ return jQuery.extend(
273
+ jQuery.browser.msie ?
274
+ { left: b.scrollLeft || d.scrollLeft, top: b.scrollTop || d.scrollTop } :
275
+ { left: w.pageXOffset, top: w.pageYOffset },
276
+ !Boxy._u(w.innerWidth) ?
277
+ { width: w.innerWidth, height: w.innerHeight } :
278
+ (!Boxy._u(d) && !Boxy._u(d.clientWidth) && d.clientWidth != 0 ?
279
+ { width: d.clientWidth, height: d.clientHeight } :
280
+ { width: b.clientWidth, height: b.clientHeight }) );
281
+ }
282
+
283
+ });
284
+
285
+ Boxy.prototype = {
286
+
287
+ // Returns the size of this boxy instance without displaying it.
288
+ // Do not use this method if boxy is already visible, use getSize() instead.
289
+ estimateSize: function() {
290
+ this.boxy.css({visibility: 'hidden', display: 'block'});
291
+ var dims = this.getSize();
292
+ this.boxy.css('display', 'none').css('visibility', 'visible');
293
+ return dims;
294
+ },
295
+
296
+ // Returns the dimensions of the entire boxy dialog as [width,height]
297
+ getSize: function() {
298
+ return [this.boxy.width(), this.boxy.height()];
299
+ },
300
+
301
+ // Returns the dimensions of the content region as [width,height]
302
+ getContentSize: function() {
303
+ var c = this.getContent();
304
+ return [c.width(), c.height()];
305
+ },
306
+
307
+ // Returns the position of this dialog as [x,y]
308
+ getPosition: function() {
309
+ var b = this.boxy[0];
310
+ return [b.offsetLeft, b.offsetTop];
311
+ },
312
+
313
+ // Returns the center point of this dialog as [x,y]
314
+ getCenter: function() {
315
+ var p = this.getPosition();
316
+ var s = this.getSize();
317
+ return [Math.floor(p[0] + s[0] / 2), Math.floor(p[1] + s[1] / 2)];
318
+ },
319
+
320
+ // Returns a jQuery object wrapping the inner boxy region.
321
+ // Not much reason to use this, you're probably more interested in getContent()
322
+ getInner: function() {
323
+ return jQuery('.boxy-inner', this.boxy);
324
+ },
325
+
326
+ // Returns a jQuery object wrapping the boxy content region.
327
+ // This is the user-editable content area (i.e. excludes titlebar)
328
+ getContent: function() {
329
+ return jQuery('.boxy-content', this.boxy);
330
+ },
331
+
332
+ // Replace dialog content
333
+ setContent: function(newContent) {
334
+ newContent = jQuery(newContent).css({display: 'block'}).addClass('boxy-content');
335
+ if (this.options.clone) newContent = newContent.clone(true);
336
+ this.getContent().remove();
337
+ this.getInner().append(newContent);
338
+ this._setupDefaultBehaviours(newContent);
339
+ this.options.behaviours.call(this, newContent);
340
+ return this;
341
+ },
342
+
343
+ // Move this dialog to some position, funnily enough
344
+ moveTo: function(x, y) {
345
+ this.moveToX(x).moveToY(y);
346
+ return this;
347
+ },
348
+
349
+ // Move this dialog (x-coord only)
350
+ moveToX: function(x) {
351
+ if (typeof x == 'number') this.boxy.css({left: x});
352
+ else this.centerX();
353
+ return this;
354
+ },
355
+
356
+ // Move this dialog (y-coord only)
357
+ moveToY: function(y) {
358
+ if (typeof y == 'number') this.boxy.css({top: y});
359
+ else this.centerY();
360
+ return this;
361
+ },
362
+
363
+ // Move this dialog so that it is centered at (x,y)
364
+ centerAt: function(x, y) {
365
+ var s = this[this.visible ? 'getSize' : 'estimateSize']();
366
+ if (typeof x == 'number') this.moveToX(x - s[0] / 2);
367
+ if (typeof y == 'number') this.moveToY(y - s[1] / 2);
368
+ return this;
369
+ },
370
+
371
+ centerAtX: function(x) {
372
+ return this.centerAt(x, null);
373
+ },
374
+
375
+ centerAtY: function(y) {
376
+ return this.centerAt(null, y);
377
+ },
378
+
379
+ // Center this dialog in the viewport
380
+ // axis is optional, can be 'x', 'y'.
381
+ center: function(axis) {
382
+ var v = Boxy._viewport();
383
+ var o = this.options.fixed ? [0, 0] : [v.left, v.top];
384
+ if (!axis || axis == 'x') this.centerAt(o[0] + v.width / 2, null);
385
+ if (!axis || axis == 'y') this.centerAt(null, o[1] + v.height / 2);
386
+ return this;
387
+ },
388
+
389
+ // Center this dialog in the viewport (x-coord only)
390
+ centerX: function() {
391
+ return this.center('x');
392
+ },
393
+
394
+ // Center this dialog in the viewport (y-coord only)
395
+ centerY: function() {
396
+ return this.center('y');
397
+ },
398
+
399
+ // Resize the content region to a specific size
400
+ resize: function(width, height, after) {
401
+ if (!this.visible) return;
402
+ var bounds = this._getBoundsForResize(width, height);
403
+ this.boxy.css({left: bounds[0], top: bounds[1]});
404
+ this.getContent().css({width: bounds[2], height: bounds[3]});
405
+ if (after) after(this);
406
+ return this;
407
+ },
408
+
409
+ // Tween the content region to a specific size
410
+ tween: function(width, height, after) {
411
+ if (!this.visible) return;
412
+ var bounds = this._getBoundsForResize(width, height);
413
+ var self = this;
414
+ this.boxy.stop().animate({left: bounds[0], top: bounds[1]});
415
+ this.getContent().stop().animate({width: bounds[2], height: bounds[3]}, function() {
416
+ if (after) after(self);
417
+ });
418
+ return this;
419
+ },
420
+
421
+ // Returns true if this dialog is visible, false otherwise
422
+ isVisible: function() {
423
+ return this.visible;
424
+ },
425
+
426
+ // Make this boxy instance visible
427
+ show: function() {
428
+ if (this.visible) return;
429
+ if (this.options.modal) {
430
+ var self = this;
431
+ if (!Boxy.resizeConfigured) {
432
+ Boxy.resizeConfigured = true;
433
+ jQuery(window).resize(function() { Boxy._handleResize(); });
434
+ }
435
+ this.modalBlackout = jQuery('<div class="boxy-modal-blackout"></div>')
436
+ .css({zIndex: Boxy._nextZ(),
437
+ opacity: 0.7,
438
+ width: jQuery(document).width(),
439
+ height: jQuery(document).height()})
440
+ .appendTo(document.body);
441
+ this.toTop();
442
+ if (this.options.closeable) {
443
+ jQuery(document.body).bind('keypress.boxy', function(evt) {
444
+ var key = evt.which || evt.keyCode;
445
+ if (key == 27) {
446
+ self.hide();
447
+ jQuery(document.body).unbind('keypress.boxy');
448
+ }
449
+ });
450
+ }
451
+ }
452
+ this.boxy.stop().css({opacity: 1}).show();
453
+ this.visible = true;
454
+ this._fire('afterShow');
455
+ return this;
456
+ },
457
+
458
+ // Hide this boxy instance
459
+ hide: function(after) {
460
+ if (!this.visible) return;
461
+ var self = this;
462
+ if (this.options.modal) {
463
+ jQuery(document.body).unbind('keypress.boxy');
464
+ this.modalBlackout.animate({opacity: 0}, function() {
465
+ jQuery(this).remove();
466
+ });
467
+ }
468
+ this.boxy.stop().animate({opacity: 0}, 300, function() {
469
+ self.boxy.css({display: 'none'});
470
+ self.visible = false;
471
+ self._fire('afterHide');
472
+ if (after) after(self);
473
+ if (self.options.unloadOnHide) self.unload();
474
+ });
475
+ return this;
476
+ },
477
+
478
+ toggle: function() {
479
+ this[this.visible ? 'hide' : 'show']();
480
+ return this;
481
+ },
482
+
483
+ hideAndUnload: function(after) {
484
+ this.options.unloadOnHide = true;
485
+ this.hide(after);
486
+ return this;
487
+ },
488
+
489
+ unload: function() {
490
+ this._fire('beforeUnload');
491
+ this.boxy.remove();
492
+ if (this.options.actuator) {
493
+ jQuery.data(this.options.actuator, 'active.boxy', false);
494
+ }
495
+ },
496
+
497
+ // Move this dialog box above all other boxy instances
498
+ toTop: function() {
499
+ this.boxy.css({zIndex: Boxy._nextZ()});
500
+ return this;
501
+ },
502
+
503
+ // Returns the title of this dialog
504
+ getTitle: function() {
505
+ return jQuery('> .title-bar h2', this.getInner()).html();
506
+ },
507
+
508
+ // Sets the title of this dialog
509
+ setTitle: function(t) {
510
+ jQuery('> .title-bar h2', this.getInner()).html(t);
511
+ return this;
512
+ },
513
+
514
+ //
515
+ // Don't touch these privates
516
+
517
+ _getBoundsForResize: function(width, height) {
518
+ var csize = this.getContentSize();
519
+ var delta = [width - csize[0], height - csize[1]];
520
+ var p = this.getPosition();
521
+ return [Math.max(p[0] - delta[0] / 2, 0),
522
+ Math.max(p[1] - delta[1] / 2, 0), width, height];
523
+ },
524
+
525
+ _setupTitleBar: function() {
526
+ if (this.options.title) {
527
+ var self = this;
528
+ var tb = jQuery("<div class='title-bar'></div>").html("<h2>" + this.options.title + "</h2>");
529
+ if (this.options.closeable) {
530
+ tb.append(jQuery("<a href='#' class='close'></a>").html(this.options.closeText));
531
+ }
532
+ if (this.options.draggable) {
533
+ tb[0].onselectstart = function() { return false; }
534
+ tb[0].unselectable = 'on';
535
+ tb[0].style.MozUserSelect = 'none';
536
+ if (!Boxy.dragConfigured) {
537
+ jQuery(document).mousemove(Boxy._handleDrag);
538
+ Boxy.dragConfigured = true;
539
+ }
540
+ tb.mousedown(function(evt) {
541
+ self.toTop();
542
+ Boxy.dragging = [self, evt.pageX - self.boxy[0].offsetLeft, evt.pageY - self.boxy[0].offsetTop];
543
+ jQuery(this).addClass('dragging');
544
+ }).mouseup(function() {
545
+ jQuery(this).removeClass('dragging');
546
+ Boxy.dragging = null;
547
+ self._fire('afterDrop');
548
+ });
549
+ }
550
+ this.getInner().prepend(tb);
551
+ this._setupDefaultBehaviours(tb);
552
+ }
553
+ },
554
+
555
+ _setupDefaultBehaviours: function(root) {
556
+ var self = this;
557
+ if (this.options.clickToFront) {
558
+ root.click(function() { self.toTop(); });
559
+ }
560
+ jQuery('.close', root).click(function() {
561
+ self.hide();
562
+ return false;
563
+ }).mousedown(function(evt) { evt.stopPropagation(); });
564
+ },
565
+
566
+ _fire: function(event) {
567
+ this.options[event].call(this);
568
+ }
569
+
570
+ };