source: trunk/fl5/src/com/longtailvideo/jwplayer/view/components/ControlbarComponentV4.as @ 979

Revision 979, 19.7 KB checked in by pablo, 3 years ago (diff)

Fixed controlbar indexes so that the buttons are ordered for accessibility as they appear visually (733)

Line 
1package com.longtailvideo.jwplayer.view.components {
2        import com.longtailvideo.jwplayer.events.MediaEvent;
3        import com.longtailvideo.jwplayer.events.PlayerEvent;
4        import com.longtailvideo.jwplayer.events.PlayerStateEvent;
5        import com.longtailvideo.jwplayer.events.PlaylistEvent;
6        import com.longtailvideo.jwplayer.events.ViewEvent;
7        import com.longtailvideo.jwplayer.player.IPlayer;
8        import com.longtailvideo.jwplayer.player.PlayerState;
9        import com.longtailvideo.jwplayer.plugins.PluginConfig;
10        import com.longtailvideo.jwplayer.utils.Animations;
11        import com.longtailvideo.jwplayer.utils.Draw;
12        import com.longtailvideo.jwplayer.utils.Logger;
13        import com.longtailvideo.jwplayer.utils.Stacker;
14        import com.longtailvideo.jwplayer.utils.Strings;
15        import com.longtailvideo.jwplayer.view.PlayerLayoutManager;
16        import com.longtailvideo.jwplayer.view.interfaces.IControlbarComponent;
17       
18        import flash.accessibility.AccessibilityProperties;
19        import flash.display.DisplayObject;
20        import flash.display.MovieClip;
21        import flash.display.Sprite;
22        import flash.events.MouseEvent;
23        import flash.geom.ColorTransform;
24        import flash.geom.Rectangle;
25        import flash.text.TextField;
26        import flash.ui.Mouse;
27        import flash.utils.clearTimeout;
28        import flash.utils.setTimeout;
29
30
31        public class ControlbarComponentV4 extends CoreComponent implements IControlbarComponent {
32                /** Reference to the original skin **/
33                private var skin:Sprite;
34                /** A list with all controls. **/
35                private var stacker:Stacker;
36                /** Timeout for hiding the  **/
37                private var hiding:Number;
38                /** When scrubbing, icon shouldn't be set. **/
39                private var scrubber:MovieClip;
40                /** Color object for frontcolor. **/
41                private var front:ColorTransform;
42                /** Color object for lightcolor. **/
43                private var light:ColorTransform;
44                /** The actions for all controlbar buttons. **/
45                private var BUTTONS:Object;
46                /** The actions for all sliders **/
47                private var SLIDERS:Object = {timeSlider: ViewEvent.JWPLAYER_VIEW_SEEK,
48                                volumeSlider: ViewEvent.JWPLAYER_VIEW_VOLUME};
49                /** The button to clone for all custom buttons. **/
50                private var clonee:MovieClip;
51                /** Saving the block state of the controlbar. **/
52                private var blocking:Boolean;
53                /** Controlbar config **/
54                private var controlbarConfig:PluginConfig;
55                /** Animations handler **/
56                private var animations:Animations;
57                /** Last inserted button **/
58                private var lastInsert:MovieClip;
59
60
61                public function ControlbarComponentV4(player:IPlayer) {
62                        super(player, "controlbar");
63                        animations = new Animations(this);
64                        controlbarConfig = _player.config.pluginConfig("controlbar");
65                        if (!controlbarConfig['margin']) controlbarConfig['margin'] = 0;       
66                        // TODO: Remove Link button
67                        BUTTONS = {playButton: ViewEvent.JWPLAYER_VIEW_PLAY,
68                                        pauseButton: ViewEvent.JWPLAYER_VIEW_PAUSE,
69                                        stopButton: ViewEvent.JWPLAYER_VIEW_STOP,
70                                        prevButton: ViewEvent.JWPLAYER_VIEW_PREV,
71                                        nextButton: ViewEvent.JWPLAYER_VIEW_NEXT,
72                                        fullscreenButton: ViewEvent.JWPLAYER_VIEW_FULLSCREEN,
73                                        normalscreenButton: ViewEvent.JWPLAYER_VIEW_FULLSCREEN,
74                                        muteButton: ViewEvent.JWPLAYER_VIEW_MUTE,
75                                        unmuteButton: ViewEvent.JWPLAYER_VIEW_MUTE};
76                        skin = _player.skin.getSWFSkin().getChildByName('controlbar') as Sprite;
77                        skin.x = 0;
78                        skin.y = 0;
79                        skin.tabChildren = true;
80                        skin.tabEnabled = false;
81                        addChild(skin);
82                        _player.addEventListener(PlayerStateEvent.JWPLAYER_PLAYER_STATE, stateHandler);
83                        _player.addEventListener(MediaEvent.JWPLAYER_MEDIA_TIME, timeHandler);
84                        _player.addEventListener(MediaEvent.JWPLAYER_MEDIA_MUTE, muteHandler);
85                        _player.addEventListener(MediaEvent.JWPLAYER_MEDIA_VOLUME, volumeHandler);
86                        _player.addEventListener(MediaEvent.JWPLAYER_MEDIA_BUFFER, timeHandler);
87                        _player.addEventListener(PlaylistEvent.JWPLAYER_PLAYLIST_LOADED, itemHandler);
88                        _player.addEventListener(PlaylistEvent.JWPLAYER_PLAYLIST_UPDATED, itemHandler);
89                        _player.addEventListener(PlaylistEvent.JWPLAYER_PLAYLIST_ITEM, itemHandler);
90                        stacker = new Stacker(skin as MovieClip);
91                        try {
92                                getSkinComponent("linkButton").visible = false;
93                        } catch (e:Error) {}
94                       
95                        setButtons();
96                        setColors();
97                        itemHandler();
98                        muteHandler();
99                        stateHandler();
100                        timeHandler();
101                        volumeHandler();
102                }
103
104
105                /**
106                 * Add a new button to the control
107                 *
108                 * @param icn   A graphic to show as icon
109                 * @param nam   Name of the button
110                   getSkinComponent('* @param hdl       The function to call when clicking the Button').
111                 **/
112                public function addButton(icon:DisplayObject, name:String, handler:Function=null):MovieClip {
113                        var btn:MovieClip;
114                        if (getSkinComponent('linkButton') && getSkinElementChild('linkButton', 'back')) {
115                                btn = Draw.clone(getSkinComponent('linkButton') as MovieClip) as MovieClip;
116                                btn.name = name + 'Button';
117                                btn.visible = true;
118                                btn.tabEnabled = true;
119                                var acs:AccessibilityProperties = new AccessibilityProperties();
120                                acs.name = name + 'Button';
121                                btn.accessibilityProperties = acs;
122                                skin.addChild(btn);
123                                var off:Number = Math.round((btn.height - icon.height) / 2);
124                                Draw.clear(btn['icon']);
125                                btn['icon'].addChild(icon);
126                                icon.x = icon.y = 0;
127                                btn['icon'].x = btn['icon'].y = off;
128                                btn['back'].width = icon.width + 2 * off;
129                                btn.buttonMode = true;
130                                btn.mouseChildren = false;
131                                btn.addEventListener(MouseEvent.CLICK, handler);
132                                if (front) {
133                                        btn['icon'].transform.colorTransform = front;
134                                        btn.addEventListener(MouseEvent.MOUSE_OVER, overHandler);
135                                        btn.addEventListener(MouseEvent.MOUSE_OUT, outHandler);
136                                }
137                                if (lastInsert) {
138                                        stacker.insert(btn, lastInsert);
139                                } else {
140                                        stacker.insert(btn, getSkinComponent('linkButton') as MovieClip);
141                                }
142                                lastInsert = btn;
143                        }
144                        return btn;
145                }
146
147
148                public function removeButton(name:String):void {
149                        skin.removeChild(getSkinComponent(name));
150                }
151
152                public function resize(width:Number, height:Number):void {
153                        if (!(PlayerLayoutManager.testPosition(controlbarConfig['position']) || controlbarConfig['position'] == "over")) {
154                                skin.visible = false;
155                                return;
156                        }
157
158                        var wid:Number = width;
159                        var margin:Number = controlbarConfig['margin'];
160
161                        if (controlbarConfig['position'] == 'over' || _player.config.fullscreen == true) {
162                                x = margin + player.config.pluginConfig('display')['x'];
163                                y = height - skin.height - margin + player.config.pluginConfig('display')['y'];
164                                wid = width - 2 * margin;
165                        }
166
167                        try {
168                                getSkinComponent('fullscreenButton').visible = false;
169                                getSkinComponent('normalscreenButton').visible = false;
170                                if (stage['displayState'] && _player.config.height > 40) {
171                                        if (_player.config.fullscreen) {
172                                                getSkinComponent('fullscreenButton').visible = false;
173                                                getSkinComponent('normalscreenButton').visible = true;
174                                        } else {
175                                                getSkinComponent('fullscreenButton').visible = true;
176                                                getSkinComponent('normalscreenButton').visible = false;
177                                        }
178                                }
179                        } catch (err:Error) {
180                        }
181                        stacker.rearrange(wid);
182                        stopFader();
183                        stateHandler();
184                        fixTime();
185                }
186
187
188                public function getButton(buttonName:String):DisplayObject {
189                        return null;
190                }
191
192
193                /** Hide the controlbar **/
194                public function block(stt:Boolean):void {
195                        blocking = stt;
196                        timeHandler();
197                }
198
199
200                /** Handle clicks from all buttons. **/
201                private function clickHandler(evt:MouseEvent):void {
202                        var act:String = BUTTONS[evt.target.name];
203                        var data:Object = null;
204                        if (blocking != true || act == ViewEvent.JWPLAYER_VIEW_FULLSCREEN || act == ViewEvent.JWPLAYER_VIEW_MUTE) {
205                                switch (act) {
206                                        case ViewEvent.JWPLAYER_VIEW_FULLSCREEN:
207                                                data = Boolean(!_player.config.fullscreen);
208                                                break;
209                                        case ViewEvent.JWPLAYER_VIEW_PAUSE:
210                                                data = Boolean(_player.state == PlayerState.IDLE || _player.state == PlayerState.PAUSED);
211                                                break;
212                                        case ViewEvent.JWPLAYER_VIEW_MUTE:
213                                                data = Boolean(!_player.config.mute);
214                                                break;
215                                }
216                                var event:ViewEvent = new ViewEvent(act, data);
217                                dispatchEvent(event);
218                        }
219                }
220
221
222                /** Handle mouse presses on sliders. **/
223                private function downHandler(evt:MouseEvent):void {
224                        if (!_player.locked) {
225                                scrubber = MovieClip(evt.target);
226                                if (blocking != true || scrubber.name == 'volumeSlider') {
227                                        var rct:Rectangle = new Rectangle(scrubber.rail.x, scrubber.icon.y, scrubber.rail.width - scrubber.icon.width, 0);
228                                        scrubber.icon.startDrag(true, rct);
229                                        stage.addEventListener(MouseEvent.MOUSE_UP, upHandler);
230                                } else {
231                                        scrubber = null;
232                                }
233                        }
234                }
235
236
237                /** Handle a change in the current item **/
238                private function itemHandler(evt:PlaylistEvent=null):void {
239                        try {
240                                if (_player.playlist && _player.playlist.length > 1) {
241                                        getSkinComponent('prevButton').visible = getSkinComponent('nextButton').visible = true;
242                                } else {
243                                        getSkinComponent('prevButton').visible = getSkinComponent('nextButton').visible = false;
244                                }
245                        } catch (err:Error) {
246                        }
247                        timeHandler();
248                        stacker.rearrange();
249                        fixTime();
250                }
251
252                /** Show a mute icon if playing. **/
253                private function muteHandler(evt:MediaEvent=null):void {
254                        if (_player.config.mute == true) {
255                                try {
256                                        getSkinComponent('muteButton').visible = false;
257                                        getSkinComponent('unmuteButton').visible = true;
258                                } catch (err:Error) {
259                                }
260                                try {
261                                        getSkinElementChild('volumeSlider', 'mark').visible = false;
262                                        getSkinElementChild('volumeSlider', 'icon').x = getSkinElementChild('volumeSlider', 'rail').x;
263                                } catch (err:Error) {
264                                }
265                        } else {
266                                try {
267                                        getSkinComponent('muteButton').visible = true;
268                                        getSkinComponent('unmuteButton').visible = false;
269                                } catch (err:Error) {
270                                }
271                                try {
272                                        getSkinElementChild('volumeSlider', 'mark').visible = true;
273                                        volumeHandler();
274                                } catch (err:Error) {
275                                }
276                        }
277                }
278
279
280                /** Handle mouseouts from all buttons **/
281                private function outHandler(evt:MouseEvent):void {
282                        if (front && evt.target['icon']) {
283                                evt.target['icon'].transform.colorTransform = front;
284                        } else {
285                                evt.target.gotoAndPlay('out');
286                        }
287                }
288
289
290                /** Handle clicks from all buttons **/
291                private function overHandler(evt:MouseEvent):void {
292                        if (front && evt.target['icon']) {
293                                evt.target['icon'].transform.colorTransform = light;
294                        } else {
295                                evt.target.gotoAndPlay('over');
296                        }
297                }
298
299
300                /** Clickhandler for all buttons. **/
301                private function setButtons():void {
302                        for (var btn:String in BUTTONS) {
303                                if (getSkinComponent(btn)) {
304                                        (getSkinComponent(btn) as MovieClip).mouseChildren = false;
305                                        (getSkinComponent(btn) as MovieClip).buttonMode = true;
306                                        getSkinComponent(btn).addEventListener(MouseEvent.CLICK, clickHandler);
307                                        getSkinComponent(btn).addEventListener(MouseEvent.MOUSE_OVER, overHandler);
308                                        getSkinComponent(btn).addEventListener(MouseEvent.MOUSE_OUT, outHandler);
309                                }
310                        }
311                        for (var sld:String in SLIDERS) {
312                                if (getSkinComponent(sld)) {
313                                        (getSkinComponent(sld) as MovieClip).mouseChildren = false;
314                                        (getSkinComponent(sld) as MovieClip).tabEnabled = false;
315                                        (getSkinComponent(sld) as MovieClip).buttonMode = true;
316                                        getSkinComponent(sld).addEventListener(MouseEvent.MOUSE_DOWN, downHandler);
317                                        getSkinComponent(sld).addEventListener(MouseEvent.MOUSE_OVER, overHandler);
318                                        getSkinComponent(sld).addEventListener(MouseEvent.MOUSE_OUT, outHandler);
319                                }
320                        }
321                }
322
323
324                /** Init the colors. **/
325                private function setColors():void {
326                        if (_player.config.backcolor && getSkinElementChild('playButton', 'icon')) {
327                                var clr:ColorTransform = new ColorTransform();
328                                clr.color = _player.config.backcolor.color;
329                                getSkinComponent('back').transform.colorTransform = clr;
330                        }
331                        if (_player.config.frontcolor) {
332                                try {
333                                        front = new ColorTransform();
334                                        front.color = _player.config.frontcolor.color;
335                                        for (var btn:String in BUTTONS) {
336                                                if (getSkinComponent(btn)) {
337                                                        getSkinElementChild(btn, 'icon').transform.colorTransform = front;
338                                                }
339                                        }
340                                        for (var sld:String in SLIDERS) {
341                                                if (getSkinComponent(sld)) {
342                                                        getSkinElementChild(sld, 'icon').transform.colorTransform = front;
343                                                        getSkinElementChild(sld, 'mark').transform.colorTransform = front;
344                                                        getSkinElementChild(sld, 'rail').transform.colorTransform = front;
345                                                }
346                                        }
347                                        (getSkinComponent('elapsedText') as TextField).textColor = front.color;
348                                        (getSkinComponent('totalText') as TextField).textColor = front.color;
349                                } catch (err:Error) {
350                                }
351                        }
352                        if (_player.config.lightcolor) {
353                                light = new ColorTransform();
354                                light.color = _player.config.lightcolor.color;
355                        } else {
356                                light = front;
357                        }
358                        if (light) {
359                                try {
360                                        getSkinElementChild('timeSlider', 'done').transform.colorTransform = light;
361                                        getSkinElementChild('volumeSlider', 'mark').transform.colorTransform = light;
362                                } catch (err:Error) {
363                                }
364                        }
365                }
366
367               
368                private function startFader():void {
369                        if (controlbarConfig['position'] == 'over' || (_player.config.fullscreen && controlbarConfig['position'] != 'none')) {
370                                if (!isNaN(hiding)) {
371                                        clearTimeout(hiding);
372                                }
373                                hiding = setTimeout(moveTimeout, 2000);
374                                _player.controls.display.addEventListener(MouseEvent.MOUSE_MOVE, moveHandler);
375                                addEventListener(MouseEvent.MOUSE_MOVE, moveHandler);
376                        }
377                }
378               
379                private function stopFader():void {
380                        if (!isNaN(hiding)) {
381                                clearTimeout(hiding);
382                                try {
383                                        _player.controls.display.removeEventListener(MouseEvent.MOUSE_MOVE, moveHandler);
384                                        removeEventListener(MouseEvent.MOUSE_MOVE, moveHandler);
385                                } catch (e:Error) {}
386                        }
387                        Mouse.show();
388                        animations.fade(1);
389                }
390               
391                /** Show above controlbar on mousemove. **/
392                private function moveHandler(evt:MouseEvent=null):void {
393                        if (alpha == 0) {
394                                animations.fade(1);
395                        }
396                        clearTimeout(hiding);
397                        hiding = setTimeout(moveTimeout, 2000);
398                        Mouse.show();
399                }
400               
401               
402                /** Hide above controlbar again when move has timed out. **/
403                private function moveTimeout():void {
404                        animations.fade(0);
405                        Mouse.hide();
406                }
407               
408                /** Process state changes **/
409                private function stateHandler(evt:PlayerEvent=null):void {
410                        // TODO: Fix non-working fading
411                        clearTimeout(hiding);
412                        try {
413                                switch (_player.state) {
414                                        case PlayerState.PLAYING:
415                                                getSkinComponent('playButton').visible = false;
416                                                getSkinComponent('pauseButton').visible = true;
417                                                startFader();
418                                                break;
419                                        case PlayerState.PAUSED:
420                                                getSkinComponent('playButton').visible = true;
421                                                getSkinComponent('pauseButton').visible = false;
422                                                stopFader();
423                                                break;
424                                        case PlayerState.BUFFERING:
425                                                getSkinComponent('playButton').visible = false;
426                                                getSkinComponent('pauseButton').visible = true;
427                                                stopFader();
428                                                break;
429                                        case PlayerState.IDLE:
430                                                getSkinComponent('playButton').visible = true;
431                                                getSkinComponent('pauseButton').visible = false;
432                                                timeHandler();
433                                                stopFader();
434                                                break;
435                                }
436                        } catch (e:Error) {
437                        }
438                }
439
440
441                /** Process time updates given by the model. **/
442                private function timeHandler(evt:MediaEvent=null):void {
443                        var dur:Number = 0;
444                        var pos:Number = 0;
445                        if (evt) {
446                                if (evt.duration >= 0) {
447                                        dur = evt.duration;
448                                }
449                                if (evt.position >= 0) {
450                                        pos = evt.position;
451                                }
452                        } else if (_player.playlist.length > 0 && _player.playlist.currentItem) {
453                                if (_player.playlist.currentItem.duration >= 0) {
454                                        dur = _player.playlist.currentItem.duration;
455                                }
456                        }
457                        var pct:Number = pos / dur;
458                        if (isNaN(pct)) {
459                                pct = 1;
460                        }
461                        try {
462                                (getSkinComponent('elapsedText') as TextField).text = Strings.digits(pos);
463                                (getSkinComponent('totalText') as TextField).text = Strings.digits(dur);
464                        } catch (err:Error) {
465                                Logger.log(err);
466                        }
467                        try {
468                                var xps:Number = Math.round(pct * (getSkinElementChild('timeSlider', 'rail').width - getSkinElementChild('timeSlider', 'icon').width));
469                                bufferHandler(evt);
470                                if (dur > 0) {
471                                        getSkinElementChild('timeSlider', 'icon').visible = _player.state != PlayerState.IDLE;
472                                        getSkinElementChild('timeSlider', 'mark').visible = _player.state != PlayerState.IDLE;
473                                        if (!scrubber || scrubber.name != 'timeSlider') {
474                                                getSkinElementChild('timeSlider', 'icon').x = xps;
475                                                getSkinElementChild('timeSlider', 'done').width = xps;
476                                        }
477                                        getSkinElementChild('timeSlider', 'done').visible = _player.state != PlayerState.IDLE;
478                                } else {
479                                        if (_player.state != PlayerState.PLAYING) {
480                                                getSkinElementChild('timeSlider', 'icon').visible = false;
481                                                getSkinElementChild('timeSlider', 'mark').visible = false;
482                                                getSkinElementChild('timeSlider', 'done').visible = false;
483                                        }
484                                }
485                        } catch (err:Error) {
486                        }
487                }
488
489
490                private function bufferHandler(evt:MediaEvent):void {
491                        if (!evt || evt.bufferPercent < 0)
492                                return;
493
494                        var mark:DisplayObject = getSkinElementChild('timeSlider', 'mark');
495                        var railWidth:Number = getSkinElementChild('timeSlider', 'rail').width;
496                        var markWidth:Number = _player.state == PlayerState.IDLE ? 0 : Math.round(evt.bufferPercent / 100 * railWidth);
497                        var offset:Number = evt.offset / evt.duration;
498
499                        try {
500                                mark.x = evt.duration > 0 ? Math.round(railWidth * offset) : 0;
501                                mark.width = markWidth;
502                                mark.visible = _player.state != PlayerState.IDLE;
503                        } catch (e:Error) {
504                                Logger.log(e);
505                        }
506                }
507
508
509                /** Fix the timeline display. **/
510                private function fixTime():void {
511                        try {
512                                var scp:Number = getSkinComponent('timeSlider').scaleX;
513                                getSkinComponent('timeSlider').scaleX = 1;
514                                getSkinElementChild('timeSlider', 'icon').x = scp * getSkinElementChild('timeSlider', 'icon').x;
515                                getSkinElementChild('timeSlider', 'mark').x = scp * getSkinElementChild('timeSlider', 'mark').x;
516                                getSkinElementChild('timeSlider', 'mark').width = scp * getSkinElementChild('timeSlider', 'mark').width;
517                                getSkinElementChild('timeSlider', 'rail').width = scp * getSkinElementChild('timeSlider', 'rail').width;
518                                getSkinElementChild('timeSlider', 'done').x = scp * getSkinElementChild('timeSlider', 'done').x;
519                                getSkinElementChild('timeSlider', 'done').width = scp * getSkinElementChild('timeSlider', 'done').width;
520                        } catch (err:Error) {
521                        }
522                }
523
524
525                /** Handle mouse releases on sliders. **/
526                private function upHandler(evt:MouseEvent):void {
527                        var mpl:Number = 0;
528                        var sliderType:String = scrubber.name;
529
530                        stage.removeEventListener(MouseEvent.MOUSE_UP, upHandler);
531                        scrubber.icon.stopDrag();
532                        if (sliderType == 'timeSlider' && _player.playlist && _player.playlist.currentItem) {
533                                mpl = _player.playlist.currentItem.duration;
534                        } else if (sliderType == 'volumeSlider') {
535                                mpl = 100;
536                        }
537                        var pct:Number = (scrubber.icon.x - scrubber.rail.x) / (scrubber.rail.width - scrubber.icon.width) * mpl;
538                        scrubber = null;
539                        if (sliderType == 'volumeSlider') {
540                                var volumeEvent:MediaEvent = new MediaEvent(MediaEvent.JWPLAYER_MEDIA_VOLUME);
541                                volumeEvent.volume = Math.round(pct);
542                                volumeHandler(volumeEvent);
543                        }
544                        dispatchEvent(new ViewEvent(SLIDERS[sliderType], Math.round(pct)));
545                }
546
547
548                /** Reflect the new volume in the controlbar **/
549                private function volumeHandler(evt:MediaEvent=null):void {
550                        try {
551                                var vsl:MovieClip = getSkinComponent('volumeSlider') as MovieClip;
552                                vsl.mark.width = _player.config.volume * (vsl.rail.width - vsl.icon.width / 2) / 100;
553                                vsl.icon.x = vsl.mark.x + _player.config.volume * (vsl.rail.width - vsl.icon.width) / 100;
554                        } catch (err:Error) {
555                        }
556                }
557
558
559                private function getSkinComponent(element:String):DisplayObject {
560                        return skin.getChildByName(element) as DisplayObject;
561                }
562
563
564                private function getSkinElementChild(element:String, child:String):DisplayObject {
565                        return (skin.getChildByName(element) as MovieClip).getChildByName(child);
566                }
567        }
568}
Note: See TracBrowser for help on using the repository browser.