source: audio-player/trunk/source/classes/Application.as @ 348

Revision 347, 21.2 KB checked in by doryphores, 9 years ago (diff)

Renabled playerID sanitizing

Line 
1import net.onepixelout.audio.*;
2import flash.external.ExternalInterface;
3
4class Application
5{
6        // Audio Player
7        private static var _player:Player;
8
9        // UI Elements
10        private static var masked_mc:MovieClip;
11        private static var background_mc:MovieClip;
12        private static var progress_mc:MovieClip;
13        private static var loading_mc:MovieClip;
14        private static var next_mc:MovieClip;
15        private static var previous_mc:MovieClip;
16        private static var mask_mc:MovieClip;
17        private static var display_mc:MovieClip;
18        private static var control_mc:MovieClip;
19        private static var volume_mc:MovieClip;
20
21        // State variables
22        private static var _state:Number;
23
24        private static var CLOSED:Number = 0;
25        private static var CLOSING:Number = 1;
26        private static var OPENING:Number = 2;
27        private static var OPEN:Number = 3;
28
29        // Interval ID for animation
30        private static var _clearID:Number;
31
32        // List of color keys
33        private static var _colorKeys:Array = ["bg","leftbg","lefticon","voltrack","volslider","rightbg","rightbghover","righticon","righticonhover","text","track","border","loader","tracker","skip"];
34
35        // Holds the current colour scheme (initialise with default colour scheme)
36        private static var _colorScheme:Object = {
37                bg:0xE5E5E5,
38                leftbg:0xCCCCCC,
39                lefticon:0x333333,
40                voltrack:0xF2F2F2,
41                volslider:0x666666,
42                rightbg:0xB4B4B4,
43                rightbghover:0x999999,
44                righticon:0x333333,
45                righticonhover:0xFFFFFF,
46                skip:0x666666,
47                text:0x333333,
48                track:0xFFFFFF,
49                border:0xCCCCCC,
50                loader:0x009900,
51                tracker:0xDDDDDD
52        };
53
54        // Options structure
55        private static var _options:Object = {
56                playerID:"",
57                encode:false,
58                autostart:false,
59                loop:false,
60                animation:true,
61                remaining:false,
62                noinfo:false,
63                killdownload:false,
64                checkpolicy:false,
65                demomode:false,
66                bufferTime:5,
67                volume:60,
68                rtl:false
69        };
70
71        // A list for javascript listeners
72        private static var listeners:Array = [];
73
74        /**
75        * Starts app
76        * @param sourceFile a list of mp3 files to play
77        * @param options a structure of options
78        */
79        public static function start(sourceFile:String, options:Object):Void
80        {
81                if(options != undefined) _setOptions(options);
82
83                trace(_options.playerID);
84
85                if(!_options.demomode && _options.encode) sourceFile = _sixBitDecode(sourceFile);
86
87                if(!_options.demomode) {
88                        var playerParams:Object = new Object();
89
90                        playerParams.initialVolume = _options.volume;
91                        playerParams.bufferTime = _options.bufferTime;
92                        playerParams.enableCycling = _options.loop;
93                        playerParams.playerID = _options.playerID;
94                        playerParams.checkPolicy = _options.checkpolicy;
95
96                        // Create audio player instance and load playlist
97                        _player = new Player(playerParams);
98
99                        var trackTitles:String = (_options.titles != undefined) ? _options.titles : "";
100                        var trackArtists:String = (_options.artists != undefined) ? _options.artists : "";
101                        _player.loadPlaylist(sourceFile, trackTitles, trackArtists);
102
103                        if(!_options.demomode) _player.addListener(Application);
104                }
105
106                // Initial player state
107                _state = CLOSED;
108                if(_options.demomode || !_options.animation || _options.autostart) _state = OPEN;
109
110                _setStage();
111
112                _setColors(true);
113
114                if (ExternalInterface.available) {
115                        ExternalInterface.addCallback("load", Application, Application.ei_loadFile);
116                        ExternalInterface.addCallback("close", Application, Application.ei_closePlayer);
117                        ExternalInterface.addCallback("open", Application, Application.ei_openPlayer);
118                        ExternalInterface.addCallback("setVolume", Application, Application.ei_setVolume);
119
120                        //add event listeners for js
121                        ExternalInterface.addCallback("addListener", Application, Application.addJSListener);
122                        ExternalInterface.addCallback("removeListener", Application, Application.removeJSListener);
123
124
125                        // Ask any other existing players for the current volume
126                        var newVolume:Number = Number(ExternalInterface.call("AudioPlayer.getVolume", _options.playerID));
127                        if (newVolume > -1) {
128                                _player.setVolume(newVolume, true);
129                        }
130                }
131
132
133                // Start player automatically if requested
134                if(!_options.demomode && _options.autostart) onPlay();
135
136                setInterval(_update, 100);
137
138                // Notification that the app has loaded//started
139                if (ExternalInterface.available) {
140                        ExternalInterface.call("onWPPlayerReady", _options.playerID);
141                }
142        }
143
144        /**
145        * Writes options object to internal options struct
146        * @param        options
147        */
148        private static function _setOptions(options:Object):Void
149        {
150                for(var key:String in options) _options[key] = options[key];
151                _options.playerID = _sanitize(_options.playerID);
152        }
153
154        /**
155        * Initial stage setup
156        * Adds elements to stage and links up various listeners
157        */
158        private static function _setStage():Void
159        {
160                // Align UI to left and make sure it isn't scaled
161                Stage.align = "L";
162                Stage.scaleMode = "noScale";
163
164                // Add elements to stage
165
166                // Depth counter
167                var nextDepth:Number = _root.getNextHighestDepth();
168
169                // Masked elements
170                masked_mc = _root.createEmptyMovieClip("masked_mc", nextDepth++);
171                background_mc = masked_mc.attachMovie("Background", "background_mc", 0);
172                progress_mc = masked_mc.attachMovie("Progress", "progress_mc", 1);
173                progress_mc.addListener(Application);
174                loading_mc = masked_mc.attachMovie("Loading", "loading_mc", 2);
175
176                // Next and previous buttons (if needed)
177                if(_options.demomode || _player.getTrackCount() > 1)
178                {
179                        next_mc = masked_mc.attachMovie("Toggle", "next_mc", 3);
180                        previous_mc = masked_mc.attachMovie("Toggle", "previous_mc", 4);
181                        // Make it point the other way
182                        previous_mc._rotation = -180;
183
184                        if(!_options.demomode) {
185                                // Add event handlers
186                                next_mc.onRelease = function() {
187                                        Application._player.next();
188                                        // Reset time display
189                                        Application.display_mc.setTime(0);
190                                };
191                                previous_mc.onRelease = function() {
192                                        Application._player.previous();
193                                        // Reset time display
194                                        Application.display_mc.setTime(0);
195                                };
196                        }
197                }
198
199                // Mask
200                mask_mc = _root.attachMovie("Mask", "mask_mc", nextDepth++);
201                masked_mc.setMask(mask_mc);
202                mask_mc._width = 8;
203
204                // Text display
205                display_mc = _root.attachMovie("Display", "display_mc", nextDepth++);
206                if(_state == CLOSED) display_mc._visible = false;
207
208                // Volume control
209                volume_mc = _root.attachMovie("Volume", "volume_mc", nextDepth++);
210                volume_mc.addListener(Application);
211
212                // Play/pause control
213                control_mc = _root.attachMovie("Control", "control_mc", nextDepth++, { state:_options.autostart ? "pause" : "play" });
214                control_mc.addListener(Application);
215
216                // Align and resize elements to the stage
217                _alignAndResize();
218
219                if(_options.demomode) {
220                        control_mc.toggle();
221                        volume_mc.toggleControl(true);
222                        volume_mc.update(_options.volume);
223                        progress_mc.updateProgress(0.3);
224                        loading_mc.update(0.6);
225                        display_mc.setText("1 Pixel Out: Demo Mode", 0, true);
226                        display_mc.setTime(356560, _options.remaining);
227                        previous_mc._alpha = 50;
228                }
229
230                // Set stage listener in case the stage is resized
231                Stage.addListener(Application);
232        }
233
234        /**
235        * Positions and resizes elements on the stage
236        */
237        private static function _alignAndResize():Void
238        {
239                // ------------------------------------------------------------
240                // Align elements
241                background_mc._x = volume_mc.realWidth - 7;
242
243                var trackCount = _player.getTrackCount();
244
245                progress_mc._x = volume_mc.realWidth + 4;
246                if(_options.demomode || trackCount > 1) progress_mc._x += 8;
247                progress_mc._y = 2;
248
249                loading_mc._x = volume_mc.realWidth + 4;
250                if(_options.demomode || trackCount > 1) loading_mc._x += 8;
251                loading_mc._y = 20;
252
253                if(_options.demomode || trackCount > 1)
254                {
255                        next_mc._x = Stage.width - 43;
256                        next_mc._y = 12;
257                        previous_mc._x = volume_mc.realWidth + 6;
258                        previous_mc._y = 12;
259                }
260
261                mask_mc._x = volume_mc.realWidth - 7;
262
263                display_mc._x = volume_mc.realWidth + 6;
264                if(_options.demomode || trackCount > 1) display_mc._x += 8;
265                display_mc._y = 2;
266
267                // Control element alignment depends on whether player is open or closed
268                if(_state == CLOSED) control_mc._x = volume_mc.realWidth - 6;
269                else control_mc._x = Stage.width - control_mc.realWidth;
270
271                // RTL
272                if(_options.rtl)
273                {
274                        control_mc.flip();
275                        volume_mc.flip();
276
277                        volume_mc._x = Stage.width - volume_mc.realWidth;
278
279                        background_mc._x = control_mc.realWidth - 7;
280
281                        progress_mc._x = control_mc.realWidth + 4;
282                        if(_options.demomode || trackCount > 1) progress_mc._x += 4;
283                        progress_mc._y = 2;
284
285                        loading_mc._x = control_mc.realWidth + 4;
286                        if(_options.demomode || trackCount > 1) loading_mc._x += 4;
287                        loading_mc._y = 20;
288
289                        if(_options.demomode || trackCount > 1)
290                        {
291                                next_mc._x = Stage.width - 52;
292                                next_mc._y = 12;
293                                previous_mc._x = control_mc.realWidth + 2;
294                                previous_mc._y = 12;
295                        }
296
297                        mask_mc._rotation = 180;
298                        mask_mc._y = mask_mc._height;
299                        mask_mc._x = volume_mc._x + 7;
300
301                        display_mc._x = control_mc.realWidth + 6;
302                        if(_options.demomode || trackCount > 1) display_mc._x += 4;
303                        display_mc._y = 2;
304
305                        // Control element alignment depends on whether player is open or closed
306                        if(_state == CLOSED) control_mc._x = volume_mc._x - control_mc.realWidth + 6;
307                        else control_mc._x = 0;
308                }
309
310                // ------------------------------------------------------------
311                // Resize elements
312
313                // Available space between volume and control elements
314                var availSpace:Number = Stage.width - (control_mc.realWidth + volume_mc.realWidth);
315
316                background_mc._width = availSpace + 14;
317                // Only resize mask if player is open
318                if(_state == OPEN) mask_mc._width = availSpace + 14;
319
320                if(_options.demomode || trackCount > 1) availSpace -= 12;
321
322                // Call resize methods on composite elements
323                progress_mc.resize(availSpace - 8);
324                loading_mc.resize(availSpace - 8);
325                display_mc.resize(availSpace - 12);
326        }
327
328        /**
329        * Applies colour scheme to player
330        * @param        force if true, don't check _root.setcolors
331        */
332        private static function _setColors(force:Boolean):Void
333        {
334                var i:Number;
335                var colorValue:String;
336
337                if (!force && !_root.setcolors) {
338                        return;
339                }
340
341                // Update colour scheme from root variables (set via javascript)
342                for (i = 0;i < _colorKeys.length;i++)
343                {
344                        if (_root[_colorKeys[i]] != undefined) {
345                                // Handle missing '0x' prefixes
346                                colorValue = _root[_colorKeys[i]];
347                                if (colorValue.indexOf("0x") == -1) {
348                                        colorValue = "0x" + colorValue;
349                                }
350                                _colorScheme[_colorKeys[i]] = colorValue;
351                        }
352                }
353
354                _root.setcolors = 0;
355
356                // Map colours to player elements
357                var colorTransforms:Array = [
358                        { target:background_mc, color:_colorScheme.bg },
359                        { target:volume_mc.background_mc, color:_colorScheme.leftbg },
360                        { target:volume_mc.icon_mc, color:_colorScheme.lefticon },
361                        { target:volume_mc.control_mc.track_mc, color:_colorScheme.voltrack },
362                        { target:volume_mc.control_mc.bar_mc, color:_colorScheme.volslider },
363                        { target:control_mc.background_mc.normal_mc, color:_colorScheme.rightbg },
364                        { target:control_mc.background_mc.hover_mc, color:_colorScheme.rightbghover },
365                        { target:control_mc.play_mc.normal_mc, color:_colorScheme.righticon },
366                        { target:control_mc.play_mc.hover_mc, color:_colorScheme.righticonhover },
367                        { target:control_mc.pause_mc.normal_mc, color:_colorScheme.righticon },
368                        { target:control_mc.pause_mc.hover_mc, color:_colorScheme.righticonhover },
369                        { target:loading_mc.bar_mc, color:_colorScheme.loader },
370                        { target:loading_mc.track_mc, color:_colorScheme.track },
371                        { target:progress_mc.track_mc, color:_colorScheme.track },
372                        { target:progress_mc.bar_mc, color:_colorScheme.tracker },
373                        { target:progress_mc.border_mc, color:_colorScheme.border },
374                        { target:next_mc, color:_colorScheme.skip },
375                        { target:previous_mc, color:_colorScheme.skip },
376                        { target:display_mc.message_txt, color:_colorScheme.text },
377                        { target:display_mc.time_txt, color:_colorScheme.text }
378                ];
379
380                // Apply colours
381                var tempColor:Color;
382                for(i = 0;i<colorTransforms.length;i++)
383                {
384                        if(typeof(colorTransforms[i].target) == "movieclip")
385                        {
386                                tempColor = new Color(colorTransforms[i].target);
387                                tempColor.setRGB(colorTransforms[i].color);
388                        } else colorTransforms[i].target.textColor = colorTransforms[i].color;
389                }
390        }
391
392        // ------------------------------------------------------------
393        // Event handlers
394
395        /**
396        * onResize event handler
397        */
398        public static function onResize():Void
399        {
400                _alignAndResize();
401        }
402
403        /**
404        * onPlay event handler
405        */
406        public static function onPlay(trackIndex:Number):Void
407        {
408                _player.play(trackIndex, false);
409
410                // Tell any other players to stop playing (don't want no cacophony do we?)
411                if (ExternalInterface.available) {
412                        ExternalInterface.call("AudioPlayer.activate", _options.playerID, _player.getState());
413                }
414
415                // forward any relevent calls to js listeners
416                var tempObj:Object = _player.getState();
417                forward("PLAY", tempObj.trackInfo);
418
419                // Show volume control
420                volume_mc.toggleControl(true);
421
422                // If player is closed and animation is enabled, open the player
423                if(_state < OPENING && _options.animation) openPlayer();
424        }
425
426        /**
427        * onStop event handler
428        */
429        public static function onStop():Void
430        {
431                // If player is open and animation is enabled, close the player
432                if(_options.animation && _state > CLOSING) closePlayer();
433
434                // Hide volume control
435                volume_mc.toggleControl(false);
436
437                // Toggle play button state (only if it's in pause state)
438                if (control_mc.state == "pause") control_mc.toggle();
439
440                // forward any relevent calls to js listeners
441                forward("STOP");
442        }
443
444        /**
445        * onPause event handler
446        */
447        public static function onPause():Void
448        {
449                // Tell any other players to stop playing (don't want no cacophony do we?)
450                if (ExternalInterface.available) {
451                        ExternalInterface.call("AudioPlayer.onStop", _options.playerID);
452                }
453
454                _player.pause();
455
456                // Hide volume control
457                volume_mc.toggleControl(false);
458
459                // If player is open and animation is enabled, close the player
460                if(_state > CLOSING && _options.animation) closePlayer();
461
462                // forward any relevent calls to js listeners
463                forward("PAUSE");
464        }
465
466        /**
467        * onMoveHead event handler
468        * @param        newPositon number form 0 to 1
469        */
470        public static function onMoveHead(newPosition:Number):Void
471        {
472                _player.moveHead(newPosition);
473        }
474
475        /**
476         * onSetVolume event handler
477         */
478        public static function onSetVolume(volume:Number, final:Boolean):Void
479        {
480                if(final == undefined) final = true;
481                // Set the volume and force a broadcast of the changed volume
482                _player.setVolume(volume, final);
483
484                // Tell any other players that the volume has changed
485                if (ExternalInterface.available && final) {
486                        ExternalInterface.call("AudioPlayer.syncVolumes", _options.playerID, volume);
487                }
488        }
489
490        /**
491        * onMetaData event handler
492        * called from Player.as by broadcastmessage
493        */
494        public static function onMetaData():Void
495        {
496                var tempObj:Object = _player.getState();
497                forward("METADATA", tempObj.trackInfo);
498        }
499
500        // ------------------------------------------------------------
501        // Open / close animation
502
503        /**
504        * Starts open animation
505        */
506        public static function openPlayer():Void
507        {
508                _state = OPENING;
509
510                var targetPosition:Number = _options.rtl ? 0 : Stage.width - control_mc.realWidth;
511
512                if(_clearID != null) clearInterval(_clearID);
513                _clearID = setInterval(_animate, 40, targetPosition);
514        }
515
516        /**
517        * Starts close animation
518        */
519        public static function closePlayer():Void
520        {
521                _state = CLOSING;
522
523                // Hide text display (doesn't work under a mask)
524                display_mc._visible = false;
525
526                var targetPosition:Number = _options.rtl ? volume_mc._x - control_mc.realWidth + 6 : volume_mc.realWidth - 6;
527
528                if(_clearID != null) clearInterval(_clearID);
529                _clearID = setInterval(_animate, 40, targetPosition);
530        }
531
532        /**
533        * Moves control element to the given target position (with easing)
534        * @param        targetX target position of control element
535        */
536        private static function _animate(targetX:Number):Void
537        {
538                var dx:Number = targetX - control_mc._x;
539                var speed:Number = 0.5;
540
541                dx = dx * speed;
542
543                // Stop animation when we are at less than a pixel from the target
544                if(Math.abs(dx) < 1)
545                {
546                        // Position the control element to the exact target position
547                        control_mc._x = targetX;
548                        if(_options.rtl) mask_mc._width -= (dx*2);
549                        else mask_mc._width += (dx*2);
550                        clearInterval(_clearID);
551                        if(_state == OPENING)
552                        {
553                                // Show text display
554                                display_mc._visible = true;
555                                _state = OPEN;
556                        }
557                        else{
558                                _state = CLOSED;
559                        }
560                        return;
561                }
562
563                control_mc._x += dx;
564                if(_options.rtl) mask_mc._width -= dx;
565                else mask_mc._width += dx;
566        }
567
568        // ------------------------------------------------------------
569        // Periodical update method
570
571        /**
572        * General periodical update method. It performs the following:
573        * Updates various UI element states (volume, control, progress bar and loading bar)
574        */
575        private static function _update():Void
576        {
577                // Set colour scheme at runtime
578                _setColors(false);
579
580                if(_options.demomode) {
581                        return;
582                }
583
584                // Get player state (head positions, stats etc)
585                var playerState:Object = _player.getState();
586
587                // Update volume control state
588                volume_mc.update(playerState.volume);
589
590                // Enable / disable control button
591                control_mc.enabled = true;
592
593                // Update progress bar if necessary
594                if(playerState.state != Player.PAUSED) progress_mc.updateProgress(playerState.played);
595
596                // Tell progress bar how far it can go
597                progress_mc.setMaxValue(playerState.loaded);
598
599                // Update loading bar state
600                loading_mc.update(playerState.loaded);
601
602                if(playerState.trackCount > 1)
603                {
604                        next_mc.enabled = playerState.hasNext;
605                        previous_mc.enabled = playerState.hasPrevious;
606                        if(playerState.hasNext) next_mc._alpha = 100;
607                        else next_mc._alpha = 50;
608                        if(playerState.hasPrevious) previous_mc._alpha = 100;
609                        else previous_mc._alpha = 50;
610                }
611
612                var trackNumber:String = "";
613
614                // Update text display
615                switch(playerState.state)
616                {
617                        case Player.NOTFOUND:
618                                if(playerState.trackCount > 1) trackNumber = (playerState.trackIndex + 1) + " - ";
619                                display_mc.setText(trackNumber + "File not found", 0);
620                                display_mc.setTime(0);
621                                break;
622                        default:
623                                var message = "";
624                                if(playerState.connecting) message = "Connecting...";
625                                else
626                                {
627                                        if(!_options.noinfo && playerState.trackCount > 1) message = (playerState.trackIndex + 1) + ": ";
628                                        if(playerState.buffering) message += "Buffering...";
629                                        else if(!_options.noinfo) {
630                                                if(playerState.trackInfo.artist.length > 0 || playerState.trackInfo.title.length > 0)
631                                                {
632                                                        if(playerState.trackInfo.artist.length > 0) message += playerState.trackInfo.artist + " - ";
633                                                        message += playerState.trackInfo.title;
634                                                }
635                                                else message = "Track #" + (playerState.trackIndex + 1);
636                                        }
637                                }
638                                display_mc.setText(message, 0, true);
639                                display_mc.setTime(_options.remaining ? playerState.duration - playerState.position : playerState.position, _options.remaining);
640                                break;
641                }
642        }
643
644        /**
645        * Decodes a 6-bit encoded string
646        * Thanks to mattiasdh (mattias_d@excite.com) for this
647        * http://modxcms.com/forums/index.php/topic,9340.0.html
648        * @param        source the string to decode
649        * @return       the decoded string
650        */
651        private static function _sixBitDecode(sourceStr)
652        {
653                var ntexto = "";
654                var nntexto = "";
655                var codeKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"
656                var charCode, charChar, charCodeBin, i;
657                for(i=0; i<sourceStr.length; i++)
658                {
659                        charCode = codeKey.indexOf(sourceStr.substr(i,1)); // char index
660                        charCodeBin = ("000000" + charCode.toString(2)).substr(-6,6); // char index in binary, 6 bits
661                        ntexto += charCodeBin;
662                }
663                for (i=0; i< ntexto.length; i+=8) {
664                        charCodeBin = ntexto.substr(i, 8); // char code in binary
665                        charCode = parseInt(charCodeBin, 2);
666                        charChar = String.fromCharCode(charCode);
667                        nntexto += charChar;
668                }
669                return (nntexto);
670        }
671
672        private static function ei_closePlayer():Void
673        {
674                var playerState:Object = _player.getState();
675                // Another player has asked us to stop
676                if(playerState.state == Player.PLAYING || playerState.state == Player.NOTFOUND)
677                {
678                        // If the track is still loading, stop everything including the download
679                        if(playerState.loaded < 1 || _options.killdownload) {
680                                _player.stop(false);
681                        }
682                        // Otherwise, just pause the track
683                        else _player.pause();
684                        onStop();
685                }
686        }
687
688        private static function ei_openPlayer(trackIndex:Number):Void
689        {
690                if (_state == CLOSED) control_mc.toggle();
691                onPlay(trackIndex);
692        }
693
694
695        private static function ei_setVolume(newVolume:Number):Void
696        {
697                _player.setVolume(newVolume);
698        }
699
700        private static function ei_loadFile(sourceFile:String, titles:String, artists:String):Void
701        {
702                _player.stop(false);
703                onStop();
704
705                _player.loadPlaylist(sourceFile, titles, artists);
706        }
707
708        // new ei calls to add remove listeners and forward messages
709        private static function addJSListener(typ:String, fcn:String):Boolean
710        {
711                var upperCaseType:String = typ.toUpperCase()
712                listeners.push({type:upperCaseType, callee:fcn});
713                return true;
714        }
715
716        private static function removeJSListener(typ:String, fcn:String):Boolean
717        {
718                for(var i:Number=0; i<listeners.length; i++) {
719                        if( listeners[i]['type'] == typ && listeners[i]['callee'] == fcn) {
720                                listeners.splice(i,1);
721                                return;
722                        }
723                }
724
725                return
726        };
727
728        // Send event to listeners.
729        private static function forward(typ:String, dat:Object):Void
730        {
731                if (!dat) { dat = new Object(); }
732                dat.playerID = _options.playerID
733
734                for (var itm:String in listeners) {
735                        if (listeners[itm]['type'] == typ) {
736                                ExternalInterface.call(listeners[itm]['callee'], dat);
737                        }
738                }
739        };
740
741        // Removes illegal characters from a string
742        // Allowed: [azAZ09-_:.]
743        private static function _sanitize(str:String):String
744        {
745                var result:String = "";
746                var ascii:Number;
747                var char:String;
748
749                for (var i:Number = 0; i < str.length; i++) {
750                        char = str.charAt(i);
751                        ascii = str.toLowerCase().charCodeAt(i);
752                        if ((ascii >= 97 && ascii <= 122) || "0123456789-_:.".indexOf(char) != -1) {
753                                result += char;
754                        }
755                }
756
757                return result;
758        }
759}
Note: See TracBrowser for help on using the repository browser.