mango 0.1.1 → 0.5.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/.gitignore +6 -0
  2. data/.yardopts +6 -0
  3. data/README.mdown +62 -29
  4. data/Rakefile +62 -0
  5. data/VERSION +1 -0
  6. data/bin/mango +5 -0
  7. data/doc/HISTORY.mdown +71 -0
  8. data/doc/ROAD-MAP.mdown +10 -0
  9. data/lib/mango.rb +7 -0
  10. data/lib/mango/application.rb +334 -0
  11. data/lib/mango/content_page.rb +193 -0
  12. data/lib/mango/dependencies.rb +125 -0
  13. data/lib/mango/flavored_markdown.rb +82 -0
  14. data/lib/mango/rack/debugger.rb +22 -0
  15. data/lib/mango/runner.rb +95 -0
  16. data/lib/mango/templates/Gemfile +4 -0
  17. data/lib/mango/templates/README.md +1 -0
  18. data/lib/mango/templates/config.ru +4 -0
  19. data/lib/mango/templates/content/index.md +5 -0
  20. data/lib/mango/templates/themes/default/public/images/particles.gif +0 -0
  21. data/lib/mango/templates/themes/default/public/javascripts/fireworks.js +546 -0
  22. data/lib/mango/templates/themes/default/public/javascripts/timer.js +5 -0
  23. data/lib/mango/templates/themes/default/public/robots.txt +5 -0
  24. data/lib/mango/templates/themes/default/public/styles/fireworks.css +55 -0
  25. data/lib/mango/templates/themes/default/public/styles/reset.css +54 -0
  26. data/lib/mango/templates/themes/default/styles/screen.sass +17 -0
  27. data/lib/mango/templates/themes/default/views/404.haml +21 -0
  28. data/lib/mango/templates/themes/default/views/layout.haml +20 -0
  29. data/lib/mango/templates/themes/default/views/page.haml +3 -0
  30. data/lib/mango/version.rb +6 -0
  31. data/mango.gemspec +35 -0
  32. data/spec/app_root/content/about/index.haml +1 -0
  33. data/spec/app_root/content/about/us.haml +1 -0
  34. data/spec/app_root/content/engines/haml.haml +7 -0
  35. data/spec/app_root/content/engines/markdown.markdown +7 -0
  36. data/spec/app_root/content/engines/md.md +7 -0
  37. data/spec/app_root/content/engines/mdown.mdown +7 -0
  38. data/spec/app_root/content/index.haml +1 -0
  39. data/spec/app_root/content/override.haml +1 -0
  40. data/spec/app_root/content/page_with_missing_view.haml +4 -0
  41. data/spec/app_root/content/turner+hooch.haml +1 -0
  42. data/spec/app_root/security_hole.haml +1 -0
  43. data/spec/app_root/themes/default/public/default.css +3 -0
  44. data/spec/app_root/themes/default/public/images/index.html +10 -0
  45. data/spec/app_root/themes/default/public/images/ripe-mango.jpg +0 -0
  46. data/spec/app_root/themes/default/public/override +10 -0
  47. data/spec/app_root/themes/default/public/robots.txt +2 -0
  48. data/spec/app_root/themes/default/public/styles/override.css +3 -0
  49. data/spec/app_root/themes/default/public/styles/reset.css +27 -0
  50. data/spec/app_root/themes/default/public/styles/subfolder/another.css +3 -0
  51. data/spec/app_root/themes/default/security_hole.sass +1 -0
  52. data/spec/app_root/themes/default/security_hole.txt +1 -0
  53. data/spec/app_root/themes/default/styles/override.sass +2 -0
  54. data/spec/app_root/themes/default/styles/screen.sass +13 -0
  55. data/spec/app_root/themes/default/styles/subfolder/screen.sass +12 -0
  56. data/spec/app_root/themes/default/views/404.haml +7 -0
  57. data/spec/app_root/themes/default/views/layout.haml +7 -0
  58. data/spec/app_root/themes/default/views/page.haml +4 -0
  59. data/spec/mango/application/routing_content_pages_spec.rb +357 -0
  60. data/spec/mango/application/routing_public_files_spec.rb +181 -0
  61. data/spec/mango/application/routing_style_sheets_spec.rb +286 -0
  62. data/spec/mango/application_spec.rb +34 -0
  63. data/spec/mango/content_page/finding_spec.rb +213 -0
  64. data/spec/mango/content_page/initializing_spec.rb +298 -0
  65. data/spec/mango/content_page_spec.rb +44 -0
  66. data/spec/mango/dependencies_spec.rb +189 -0
  67. data/spec/mango/flavored_markdown_spec.rb +52 -0
  68. data/spec/mango/rack/debugger_spec.rb +114 -0
  69. data/spec/mango/version_spec.rb +18 -0
  70. data/spec/quality_spec.rb +32 -0
  71. data/spec/spec.opts +3 -0
  72. data/spec/spec_helper.rb +18 -0
  73. data/spec/support/matchers/malformed_whitespace_matchers.rb +60 -0
  74. metadata +304 -17
@@ -0,0 +1,4 @@
1
+ # encoding: UTF-8
2
+ source "http://rubygems.org"
3
+
4
+ gem "mango", "0.5.0.beta1"
@@ -0,0 +1 @@
1
+ test readme
@@ -0,0 +1,4 @@
1
+ # encoding: UTF-8
2
+ require "mango"
3
+ use Mango::Rack::Debugger if ENV["RACK_ENV"].to_sym == :development
4
+ run Mango::Application
@@ -0,0 +1,5 @@
1
+ ---
2
+ title: Congratulations!
3
+ ---
4
+
5
+ ## You did it!
@@ -0,0 +1,546 @@
1
+ function FireworksController() {
2
+ var self = this;
3
+ this.intervalRate = 20; // rate (ms) to run animation at, general best default = 20
4
+ this.DEBUG = true; // debug mode disabled by default
5
+ this.oFW = null;
6
+ this.isIE = (navigator.appVersion.indexOf('MSIE')+1);
7
+ this.isOpera = (navigator.userAgent.toLowerCase().indexOf('opera')+1);
8
+ if (this.isOpera) this.isIE = false; // no impersonation allowed here!
9
+ this.fireworks = [];
10
+ this.animator = null;
11
+ this.gOID = 0; // global object ID counter (for animation queue)
12
+ this.particleTypes = 6;
13
+ this.particleXY = 10;
14
+ this.tweenFade = [100,90,80,70,60,50,40,30,20,10,0];
15
+ this.isSafari = (navigator.appVersion.toLowerCase().indexOf('safari')+1?1:0);
16
+ this.canvasX = null;
17
+ this.canvasY = null;
18
+ this.screenY = null; // screen area (not entire page)
19
+ self.scrollY = null;
20
+
21
+ self.getWindowCoords = function() {
22
+ self.canvasX = (document.documentElement.clientWidth||document.body.clientWidth||document.body.scrollWidth);
23
+ self.canvasY = (document.documentElement.clientHeight||document.body.clientHeight||document.body.scrollHeight);
24
+ self.screenY = self.canvasY;
25
+ self.scrollY = parseInt(window.scrollY||document.documentElement.scrollTop||document.body.scrollTop);
26
+ self.canvasY += self.scrollY;
27
+ }
28
+
29
+ this.getWindowCoordsAlt = function() {
30
+ self.canvasX = window.innerWidth;
31
+ self.canvasY = window.innerHeight;
32
+ self.screenY = self.canvasY;
33
+ self.scrollY = parseInt(window.scrollY||document.documentElement.scrollTop||document.body.scrollTop);
34
+ self.canvasY += self.scrollY;
35
+ }
36
+
37
+ this.getPanX = function(x) {
38
+ x = parseInt(x);
39
+ var pos = x/self.canvasX;
40
+ if (pos<0.4) {
41
+ pos *= -1;
42
+ } else if (pos >= 0.4 && pos <= 0.6) {
43
+ pos = 0.5;
44
+ }
45
+ pos = parseInt(pos*100);
46
+ // writeDebug('getPanX('+x+'): '+pos+'%');
47
+ return pos;
48
+ }
49
+
50
+ this.isEmpty = function(o) {
51
+ // needs further hacking
52
+ return (typeof(o)=='undefined'||(o==null&&o!=0)||(o==''&&o!=0)||o=='null');
53
+ }
54
+
55
+ this.init = function() {
56
+ self.oFW = document.getElementById('fw');
57
+ self.oFP = document.getElementById('fp');
58
+ if (typeof(enableDebugMode)!='undefined' && (self.DEBUG||window.location.toString().toLowerCase().indexOf('debug')>=0)) enableDebugMode();
59
+ self.getWindowCoords();
60
+ self.animator = new Animator();
61
+ }
62
+
63
+ this.destructor = function() {
64
+ for (var i=self.fireworks.length; i--;) {
65
+ self.fireworks[i] = null;
66
+ }
67
+ self.fireworks = null;
68
+ if (soundManager) {
69
+ soundManager.destructor();
70
+ soundManager = null;
71
+ }
72
+ }
73
+
74
+ if (this.isSafari || this.isOpera) this.getWindowCoords = this.getWindowCoordsAlt;
75
+
76
+ }
77
+
78
+ function Firework(oC,startX,startY,burstX,burstY,burstType,nRadius,nParticles,nCircles,allowRandom,obeyBoundaries) {
79
+ var self = this;
80
+ this.oID = 'fp'+(fc.gOID++); // may be unneeded
81
+ var p = '';
82
+ for (var i=0; i<arguments.length-1; i++) {
83
+ p += arguments[i]+',';
84
+ }
85
+ p += arguments[i];
86
+ writeDebug('firework('+p+')');
87
+ this.oC = oC;
88
+ this.o = fc.oFW.cloneNode(!fc.isIE?true:false);
89
+ this.particles = [];
90
+ this.vX = -1;
91
+ this.vY = -4;
92
+ this.x = startX;
93
+ this.y = startY;
94
+ this.allowRandom = allowRandom;
95
+ this.obeyBoundaries = obeyBoundaries;
96
+ this.frame = 0;
97
+ this.tween = [];
98
+ this.active = false;
99
+ this.moveTo = function(x,y) {
100
+ self.o.style.left = x+'px';
101
+ self.o.style.top = y+'px';
102
+ self.x = x;
103
+ self.y = y;
104
+ }
105
+
106
+ this.slideTo = function(x,y) {
107
+ self.tween = [fc.animator.createTween(self.x,x,'blast'),fc.animator.createTween(self.y,y,'blast')];
108
+ fc.animator.enqueue(self,self.animate,self.aniExplode);
109
+ }
110
+
111
+ self.aniExplode = function() {
112
+ // called from animation finish
113
+ self.o.style.background = 'none';
114
+ self.o.style.border = 'none';
115
+ for (var i=self.particles.length; --i;) {
116
+ self.particles[i].o.style.display = 'block';
117
+ fc.animator.enqueue(self.particles[i],self.particles[i].animate);
118
+ }
119
+ // attach oncomplete event handler to last particle
120
+ self.particles[i].o.style.display = 'block';
121
+ fc.animator.enqueue(self.particles[i],self.particles[i].animate,self.beginFade);
122
+ var sID = 'boom'+parseInt(Math.random()*8);
123
+ soundManager.setPan(sID,fc.getPanX(self.x));
124
+ soundManager.play(sID);
125
+ }
126
+
127
+ self.beginFade = function() {
128
+ // writeDebug('beginFade');
129
+ self.tween = fc.animator.createTween(1,0,'fade');
130
+ fc.animator.enqueue(self,self.aniFade,self.destructor);
131
+ }
132
+
133
+ this.aniFade = function() {
134
+ // writeDebug('firework.aniFade('+self.tween[self.frame].data+')');
135
+ for (var i=self.particles.length; i--;) {
136
+ self.particles[i].moveRel();
137
+ self.particles[i].nextState();
138
+ self.particles[i].setOpacity(fc.tweenFade[self.frame]);
139
+ }
140
+ if (self.frame++>=self.tween.length) {
141
+ self.active = false;
142
+ self.frame = 0;
143
+ if (self._oncomplete) self._oncomplete();
144
+ self._oncomplete = null;
145
+ return false;
146
+ }
147
+ return true;
148
+ }
149
+
150
+ this.destructor = function() {
151
+ writeDebug('firework.destructor()');
152
+ // for (var i=0; i<self.particles.length; i++) {
153
+ for (var i=self.particles.length; i--;) {
154
+ self.particles[i].destructor();
155
+ self.particles[i] = null;
156
+ }
157
+ self.particles = null;
158
+ self.oC.removeChild(self.o);
159
+ self.o = null;
160
+ self.oC = null;
161
+ }
162
+
163
+ this.animate = function() {
164
+ // generic animation method
165
+ self.moveTo(self.tween[0][self.frame].data,self.tween[1][self.frame].data,'burst');
166
+ if (self.frame++>=self.tween[0].length-1) {
167
+ self.active = false;
168
+ self.frame = 0;
169
+ if (self._oncomplete) self._oncomplete();
170
+ self._oncomplete = null;
171
+ return false;
172
+ }
173
+ return true;
174
+ }
175
+
176
+ this.createBurst = function(circles,nMax,rMax,type) {
177
+ // c: # of circles, n: # of particles per circle, r: max radius
178
+ writeDebug('firework.createBurst('+circles+','+nMax+','+rMax+','+type+')');
179
+ var i=0, j=0;
180
+ var tmp = 0;
181
+ var radiusInc = rMax/circles;
182
+ var radius = radiusInc;
183
+ var angle = 0;
184
+ var angleInc = 0; // per-loop increment
185
+ var radiusOffset = (self.allowRandom?(0.33+Math.random()):1);
186
+ var particlesPerCircle = [];
187
+ var isRandom = Math.random()>0.5;
188
+ var circleTypes = [type,circles>1?parseInt(Math.random()*fc.particleTypes):type];
189
+ var thisType = null;
190
+
191
+ for (i=0; i<circles; i++) {
192
+ particlesPerCircle[i] = parseInt(nMax*(i+1)/circles*1/circles)||1; // hack - nMax*(i+1)/circles;
193
+ angle = angleInc; // could be offset as well
194
+ angleInc = 360/particlesPerCircle[i];
195
+ thisType = circleTypes[i%2];
196
+ for (j=0; j<particlesPerCircle[i]; j++) {
197
+ self.particles[tmp] = new FireworkParticle(self.o,self.allowRandom,thisType,burstX,burstY,self.obeyBoundaries);
198
+ self.particles[tmp].slideTo(radius*Math.cos(angle*Math.PI/180),radius*radiusOffset*Math.sin(angle*Math.PI/180));
199
+ angle += angleInc;
200
+ tmp++;
201
+ }
202
+ radius += radiusInc; // increase blast radius
203
+ }
204
+ }
205
+
206
+ // startX,startY,burstX,burstY,burstType,nRadius,nParticles,nCircles
207
+
208
+ self.oC.appendChild(self.o);
209
+ self.moveTo(self.x,self.y);
210
+ self.createBurst(nCircles,nParticles,nRadius,burstType); // create an explosion
211
+ self.slideTo(burstX,burstY);
212
+ var sID = 'fire'+parseInt(Math.random()*2);
213
+ soundManager.setPan(sID,fc.getPanX(self.x));
214
+ soundManager.play(sID);
215
+ fc.animator.start();
216
+
217
+ }
218
+
219
+ function FireworkParticle(oC,isRandom,type,baseX,baseY,obeyBoundaries) {
220
+ var self = this;
221
+ this.oC = oC;
222
+ this.oID = 'fp'+(fc.gOID++); // may be unneeded
223
+ this.o = fc.oFP.cloneNode(true);
224
+ this.obeyBoundaries = obeyBoundaries;
225
+ // set type: index becomes Y offset (for background image)
226
+ this.type = null;
227
+
228
+ this.oImg = this.o.getElementsByTagName('img')[0];
229
+ this.oImg._src = this.oImg.src;
230
+ this.o.style.display = 'none';
231
+ this.baseX = baseX;
232
+ this.baseY = baseY;
233
+ this.x = 0;
234
+ this.y = 0;
235
+ this.vx = 0;
236
+ this.vy = 0;
237
+ this.frame = 0;
238
+ this.tween = [];
239
+ this.active = null;
240
+ this.tweenType = 'blast';
241
+ this.states = [];
242
+ this.state = parseInt(Math.random()*3);
243
+ this.isRandom = isRandom;
244
+ this._mt = 5;
245
+
246
+ this.moveTo = function(x,y) {
247
+ self.o.style.left = x+'px';
248
+ self.o.style.top = y+'px';
249
+ self.vx = x-self.x;
250
+ self.vy = y-self.y;
251
+ self.x = x;
252
+ self.y = y;
253
+ }
254
+
255
+ this.moveRel = function() {
256
+ // continue last moveTo() pattern, bouncing off walls if applicable
257
+ var toX = self.x+self.vx;
258
+ var toY = self.y+self.vy;
259
+ if (self.obeyBoundaries) {
260
+ var xMax = fc.canvasX-self.baseX-fc.particleXY;
261
+ var yMax = fc.canvasY-self.baseY-fc.particleXY;
262
+ var yMin = fc.scrollY;
263
+ if (self.vx>=0) {
264
+ if (toX>=xMax) self.vx *= -1;
265
+ } else if (self.vx<0 && toX+self.baseX<=0) self.vx *= -1;
266
+ if (self.vy>=0) {
267
+ if (toY>=yMax) self.vy *= -1;
268
+ } else if (self.vy<0) {
269
+ if (toY+self.baseY-yMin<=0) self.vy *= -1;
270
+ }
271
+ }
272
+ self.moveTo(self.x+self.vx,self.y+self.vy);
273
+ }
274
+
275
+ this.setOpacity = function(n) { // where n = 0..100
276
+ self.oImg.style.marginLeft = -100+(n*fc.particleXY/10)+'px';
277
+ }
278
+
279
+ this.nextState = function() {
280
+ var vis = self.o.style.visibility;
281
+ if (self.state == 2 && vis != 'hidden') {
282
+ self.o.style.visibility = 'hidden';
283
+ } else if (self.state != 2 && vis == 'hidden') {
284
+ self.o.style.visibility = 'visible';
285
+ }
286
+ self.state = parseInt(Math.random()*3);
287
+ }
288
+
289
+ this.slideTo = function(x1,y1) {
290
+ // writeDebug('slideTo (x/y): '+x1+','+y1);
291
+ if (self.isRandom) {
292
+ // randomize a bit
293
+ x1 += (x1*0.2*(Math.random()>0.5?1:-1));
294
+ y1 += (y1*0.2*(Math.random()>0.5?1:-1));
295
+ }
296
+ self.tween = [fc.animator.createTween(self.x,x1,self.tweenType),fc.animator.createTween(self.y,y1,self.tweenType)];
297
+ // prevent X overflow (scrolling)
298
+ var xMax = fc.canvasX-fc.particleXY;
299
+ var yMax = fc.canvasY-fc.particleXY;
300
+ var xMin = fc.particleXY-self.baseX;
301
+ var yMin = fc.scrollY;
302
+ var toX = null;
303
+ var toY = null;
304
+ if (self.obeyBoundaries) {
305
+ for (var i=self.tween[0].length; i--;) {
306
+ // bounce off walls where applicable
307
+ toX = self.tween[0][i].data+self.baseX;
308
+ toY = self.tween[1][i].data+self.baseY;
309
+ if (toX>=xMax) {
310
+ self.tween[0][i].data -= (toX-xMax)*2;
311
+ // self.tween[0][i].event = 'bounce';
312
+ } else if (toX<0) {
313
+ self.tween[0][i].data -= (toX*2);
314
+ // self.tween[0][i].event = 'bounce';
315
+ }
316
+ if (toY>=yMax) {
317
+ self.tween[1][i].data -= (toY-yMax)*2;
318
+ // self.tween[1][i].event = 'bounce';
319
+ } else if (toY-yMin<=0) {
320
+ self.tween[1][i].data -= (toY-yMin)*2;
321
+ // self.tween[1][i].event = 'bounce';
322
+ }
323
+ }
324
+ }
325
+ }
326
+
327
+ this.animate = function() {
328
+ var f0 = self.tween[0][self.frame].data;
329
+ var f1 = self.tween[1][self.frame].data;
330
+ self.moveTo(f0,f1);
331
+ // possible bounce event/sound hooks
332
+ // if (self.tween[0][self.frame].event) soundManager.play(self.tween[0][self.frame].event);
333
+ // if (self.tween[1][self.frame].event) soundManager.play(self.tween[1][self.frame].event);
334
+ if (self.frame++>=self.tween[0].length-1) {
335
+ if (self._oncomplete) self._oncomplete();
336
+ self._oncomplete = null;
337
+ self.active = false;
338
+ self.frame = 0;
339
+ return false;
340
+ } else if (self.frame>10) {
341
+ self.nextState();
342
+ }
343
+ return true;
344
+ }
345
+
346
+ this.destructor = function() {
347
+ self.oImg = null;
348
+ self.oC.removeChild(self.o);
349
+ self.oC = null;
350
+ self.o = null;
351
+ }
352
+
353
+ this.setType = function(t) {
354
+ self.type = t;
355
+ self.oImg.style.marginTop = -(fc.particleXY*t)+'px';
356
+ }
357
+
358
+ self.setType(type);
359
+ self.oC.appendChild(self.o);
360
+ }
361
+
362
+ function Animator() {
363
+ var self = this;
364
+ writeDebug('Animator()');
365
+ this.tweens = [];
366
+ this.tweens['default'] = [1,2,3,4,5,6,7,8,9,10,9,8,7,6,5,4,3,2,1];
367
+ this.tweens['blast'] = [12,12,11,10,10,9,8,7,6,5,4,3,2,1];
368
+ this.tweens['fade'] = [10,10,10,10,10,10,10,10,10,10];
369
+ this.queue = [];
370
+ this.queue.IDs = [];
371
+ this.active = false;
372
+ this.timer = null;
373
+
374
+ this.createTween = function(start,end,type) {
375
+ // return array of tween coordinate data (start->end)
376
+ type = type||'default';
377
+ var tween = [start];
378
+ var tmp = start;
379
+ var diff = end-start;
380
+ var x = self.tweens[type].length;
381
+ for (var i=0; i<x; i++) {
382
+ tmp += diff*self.tweens[type][i]*0.01;
383
+ tween[i] = new Object();
384
+ tween[i].data = tmp;
385
+ tween[i].event = null;
386
+ }
387
+ return tween;
388
+ }
389
+
390
+ this.enqueue = function(o,fMethod,fOnComplete) {
391
+ // add object and associated methods to animation queue
392
+ // writeDebug('animator.enqueue()');
393
+ if (!fMethod) {
394
+ writeDebug('animator.enqueue(): missing fMethod');
395
+ }
396
+ if (typeof(self.queue.IDs[o.oID])=='undefined') {
397
+ // writeDebug('animator.enqueue(): added '+o.oID);
398
+ var i = self.queue.length;
399
+ self.queue.IDs[o.oID] = i;
400
+ self.queue[i] = o;
401
+ } else {
402
+ // writeDebug('animator.enqueue(): '+o.oID+' already queued');
403
+ var i = self.queue.IDs[o.oID]; // retrieve queue index
404
+ self.queue[i].active = true;
405
+ self.queue[i].frame = 0;
406
+ }
407
+ o.active = true; // flag for animation
408
+ self.queue[i]._method = fMethod;
409
+ self.queue[i]._oncomplete = fOnComplete?fOnComplete:null;
410
+ }
411
+
412
+ this.animate = function() {
413
+ var active = 0;
414
+ for (var i=self.queue.length; i--;) {
415
+ if (self.queue[i].active) {
416
+ self.queue[i]._method();
417
+ active++;
418
+ }
419
+ }
420
+ if (active==0 && self.timer) {
421
+ // all animations finished
422
+ self.stop();
423
+ } else {
424
+ // writeDebug(active+' active');
425
+ }
426
+ }
427
+
428
+ this.start = function() {
429
+ if (self.timer || self.active) {
430
+ // writeDebug('animator.start(): already active');
431
+ return false;
432
+ }
433
+ // writeDebug('animator.start()'); // report only if started
434
+ self.active = true;
435
+ self.timer = setInterval(self.animate,fc.intervalRate);
436
+ }
437
+
438
+ this.stop = function() {
439
+ // writeDebug('animator.stop()',true);
440
+ clearInterval(self.timer);
441
+ self.timer = null;
442
+ self.active = false;
443
+ self.queue = [];
444
+ self.queue.IDs = [];
445
+ }
446
+
447
+ }
448
+
449
+ function createFirework(nRadius,nParticles,nCircles,nBurstType,startX,startY,burstX,burstY,allowRandom,obeyBoundaries) {
450
+ // check all arguments, supply random defaults if needed
451
+ var tmp = '';
452
+ for (var i in arguments) {
453
+ tmp += i+',';
454
+ }
455
+ writeDebug('createFirework('+tmp+')');
456
+
457
+ if (fc.isEmpty(startX)) {
458
+ startX = parseInt(Math.random()*fc.canvasX);
459
+ } else {
460
+ startX = parseInt(fc.canvasX*startX/100);
461
+ }
462
+
463
+ if (fc.isEmpty(startY)) {
464
+ startY = fc.canvasY-fc.particleXY;
465
+ } else {
466
+ startY = fc.canvasY-fc.screenY+parseInt(fc.screenY*startY/100);
467
+ }
468
+
469
+ if (fc.isEmpty(burstX)) {
470
+ burstX = parseInt(fc.canvasX*0.1+(Math.random()*fc.canvasX*0.8));
471
+ } else {
472
+ burstX = parseInt(fc.canvasX*burstX/100);
473
+ }
474
+
475
+ if (fc.isEmpty(burstY)) {
476
+ burstY = fc.canvasY-parseInt(Math.random()*fc.screenY);
477
+ } else {
478
+ burstY = fc.canvasY-parseInt(fc.screenY*(100-burstY)/100);
479
+ }
480
+
481
+ if (fc.isEmpty(nBurstType)) {
482
+ nBurstType = parseInt(Math.random()*fc.particleTypes);
483
+ }
484
+
485
+ if (fc.isEmpty(nRadius)) {
486
+ nRadius = 64+parseInt(Math.random()*fc.screenY*0.75);
487
+ } else if (nRadius.toString().indexOf('%')>=0) {
488
+ nRadius = parseInt(parseInt(nRadius)/100*fc.screenY);
489
+ } else if (nRadius.toString().indexOf('.')>=0) {
490
+ nRadius = parseInt(nRadius*fc.screenY);
491
+ } else {
492
+ nRadius = parseInt(nRadius*fc.screenY/100);
493
+ }
494
+
495
+ if (fc.isEmpty(nParticles)) {
496
+ nParticles = 4+parseInt(Math.random()*64);
497
+ }
498
+
499
+ if (fc.isEmpty(nCircles)) {
500
+ nCircles = Math.random()>0.5?2:1;
501
+ }
502
+
503
+ if (fc.isEmpty(allowRandom)) {
504
+ allowRandom = Math.random()>0.5;
505
+ }
506
+
507
+ if (fc.isEmpty(obeyBoundaries)) {
508
+ obeyBoundaries = Math.random()>0.5;
509
+ }
510
+
511
+ // update screen coordinates
512
+ fc.getWindowCoords();
513
+
514
+ fc.fireworks[fc.fireworks.length] = new Firework(document.getElementById('fireContainer'),startX,startY,burstX,burstY,nBurstType,nRadius,nParticles,nCircles,allowRandom,obeyBoundaries);
515
+ }
516
+
517
+ function smNull() {
518
+ // Null object for unsupported case
519
+ this.movies = []; // movie references
520
+ this.container = null;
521
+ this.unsupported = 1;
522
+ this.FlashObject = function(url) {}
523
+ this.addMovie = function(name,url) {}
524
+ this.setPan = function() {}
525
+ this.destructor = function() {}
526
+ this.play = function(movieName,soundID) {return false;}
527
+ this.defaultName = 'default';
528
+ }
529
+
530
+ var fc = new FireworksController();
531
+ // create null objects if APIs not present
532
+ if (typeof(SoundManager)=='undefined') var soundManager = new smNull();
533
+ if (typeof(writeDebug)=='undefined') var writeDebug = function(){return false;}
534
+
535
+ function addEventHandler(o,evtName,evtHandler) {
536
+ typeof(attachEvent)=='undefined'?o.addEventListener(evtName,evtHandler,false):o.attachEvent('on'+evtName,evtHandler);
537
+ }
538
+
539
+ function removeEventHandler(o,evtName,evtHandler) {
540
+ typeof(attachEvent)=='undefined'?o.removeEventListener(evtName,evtHandler,false):o.detachEvent('on'+evtName,evtHandler);
541
+ }
542
+
543
+ addEventHandler(window,'resize',fc.getWindowCoords);
544
+ addEventHandler(window,'scroll',fc.getWindowCoords);
545
+ addEventHandler(window,'load',fc.init);
546
+ addEventHandler(window,'unload',fc.destructor);