mango 0.1.1 → 0.5.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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);