1function createControls(root, video, host)
2{
3    return new ControllerGtk(root, video, host);
4};
5
6function ControllerGtk(root, video, host)
7{
8    Controller.call(this, root, video, host);
9};
10
11function contains(list, obj)
12{
13    var i = list.length;
14    while (i--)
15        if (list[i] === obj)
16            return true;
17    return false;
18};
19
20ControllerGtk.prototype = {
21
22    createControls: function()
23    {
24        Controller.prototype.createControls.apply(this);
25
26        this.controls.currentTime.classList.add(this.ClassNames.hidden);
27        this.controls.remainingTime.classList.add(this.ClassNames.hidden);
28
29        this.controls.volumeBox.classList.add(this.ClassNames.hiding);
30
31        this.listenFor(this.controls.muteBox, 'mouseout', this.handleVolumeBoxMouseOut);
32        this.listenFor(this.controls.muteButton, 'mouseover', this.handleMuteButtonMouseOver);
33        this.listenFor(this.controls.volumeBox, 'mouseover', this.handleMuteButtonMouseOver);
34        this.listenFor(this.controls.volume, 'mouseover', this.handleMuteButtonMouseOver);
35        this.listenFor(this.controls.captionButton, 'mouseover', this.handleCaptionButtonMouseOver);
36        this.listenFor(this.controls.captionButton, 'mouseout', this.handleCaptionButtonMouseOut);
37
38        var enclosure = this.controls.enclosure = document.createElement('div');
39        enclosure.setAttribute('pseudo', '-webkit-media-controls-enclosure');
40    },
41
42    configureInlineControls: function()
43    {
44        this.controls.panel.appendChild(this.controls.playButton);
45        this.controls.panel.appendChild(this.controls.timeline);
46        this.controls.panel.appendChild(this.controls.currentTime);
47        this.controls.panel.appendChild(this.controls.remainingTime);
48        this.controls.panel.appendChild(this.controls.captionButton);
49        this.controls.panel.appendChild(this.controls.fullscreenButton);
50        this.controls.panel.appendChild(this.controls.muteBox);
51        this.controls.muteBox.appendChild(this.controls.muteButton);
52        this.controls.muteBox.appendChild(this.controls.volumeBox);
53        this.controls.volumeBox.appendChild(this.controls.volume);
54        this.controls.enclosure.appendChild(this.controls.panel);
55    },
56
57    configureControls: function() {
58        if (this.controls.configured)
59            return;
60
61        this.configureInlineControls();
62        this.controls.configured = true;
63        this.addControls();
64    },
65
66    reconnectControls: function()
67    {
68        this.configureControls();
69    },
70
71    setStatusHidden: function(hidden)
72    {
73    },
74
75    updateTime: function()
76    {
77        var currentTime = this.video.currentTime;
78        var duration = this.video.duration;
79
80        this.controls.currentTime.innerText = this.formatTime(currentTime);
81        this.controls.timeline.value = currentTime;
82        if (duration === Infinity || duration === NaN)
83            this.controls.remainingTime.classList.add(this.ClassNames.hidden);
84        else {
85            this.controls.currentTime.innerText += " / " + this.formatTime(duration);
86            this.controls.remainingTime.innerText = this.formatTime(duration);
87            if (this.controls.currentTime.classList.contains(this.ClassNames.hidden))
88                this.controls.remainingTime.classList.remove(this.ClassNames.hidden);
89        }
90
91        if (currentTime > 0)
92            this.showCurrentTime();
93    },
94
95    showCurrentTime: function()
96    {
97        this.controls.currentTime.classList.remove(this.ClassNames.hidden);
98        this.controls.remainingTime.classList.add(this.ClassNames.hidden);
99    },
100
101    handlePlay: function(event)
102    {
103        Controller.prototype.handlePlay.apply(this, arguments);
104        this.showCurrentTime();
105        if (!this.isLive)
106            this.showCurrentTime();
107    },
108
109    handleTimeUpdate: function(event)
110    {
111        this.updateTime();
112    },
113
114    handleMuteButtonMouseOver: function(event)
115    {
116        if (this.video.offsetTop + this.controls.enclosure.offsetTop < 105) {
117            this.controls.volumeBox.classList.add(this.ClassNames.down);
118            this.controls.panel.classList.add(this.ClassNames.down);
119        } else {
120            this.controls.volumeBox.classList.remove(this.ClassNames.down);
121            this.controls.panel.classList.remove(this.ClassNames.down);
122        }
123        this.controls.volumeBox.classList.remove(this.ClassNames.hiding);
124        return true;
125    },
126
127    handleVolumeBoxMouseOut: function(event)
128    {
129        this.controls.volumeBox.classList.add(this.ClassNames.hiding);
130        return true;
131    },
132
133    addControls: function()
134    {
135        this.base.appendChild(this.controls.enclosure);
136    },
137
138    updateReadyState: function()
139    {
140        if (this.host.supportsFullscreen && this.video.videoTracks.length)
141            this.controls.fullscreenButton.classList.remove(this.ClassNames.hidden);
142        else
143            this.controls.fullscreenButton.classList.add(this.ClassNames.hidden);
144        this.updateVolume();
145    },
146
147    updateDuration: function()
148    {
149        Controller.prototype.updateDuration.apply(this, arguments);
150        if (this.isLive)
151            this.controls.timeline.max = 0;
152    },
153
154    setIsLive: function(live)
155    {
156        Controller.prototype.setIsLive.apply(this, arguments);
157        this.controls.timeline.disabled = this.isLive;
158    },
159
160    updatePlaying: function()
161    {
162        Controller.prototype.updatePlaying.apply(this, arguments);
163        if (!this.canPlay())
164            this.showControls();
165    },
166
167    handleCaptionButtonClicked: function(event)
168    {
169        this.handleCaptionButtonShowMenu(event)
170        return true;
171    },
172
173    buildCaptionMenu: function()
174    {
175        Controller.prototype.buildCaptionMenu.apply(this, arguments);
176
177        this.listenFor(this.captionMenu, 'mouseout', this.handleCaptionMouseOut);
178        this.listenFor(this.captionMenu, 'transitionend', this.captionMenuTransitionEnd);
179
180        this.captionMenu.captionMenuTreeElements = this.captionMenu.getElementsByTagName("*");
181
182        // Caption menu has to be centered to the caption button.
183        var captionButtonCenter =  this.controls.panel.offsetLeft + this.controls.captionButton.offsetLeft +
184            this.controls.captionButton.offsetWidth / 2;
185        var captionMenuLeft = (captionButtonCenter - this.captionMenu.offsetWidth / 2);
186        if (captionMenuLeft + this.captionMenu.offsetWidth > this.controls.panel.offsetLeft + this.controls.panel.offsetWidth)
187            this.captionMenu.classList.add(this.ClassNames.out);
188        this.captionMenu.style.left = captionMenuLeft + 'px';
189        // As height is not in the css, it needs to be specified to animate it.
190        this.captionMenu.height = this.captionMenu.offsetHeight;
191        this.captionMenu.style.height = 0;
192    },
193
194    destroyCaptionMenu: function()
195    {
196        this.hideCaptionMenu();
197    },
198
199    showCaptionMenu: function()
200    {
201        this.captionMenu.style.height = this.captionMenu.height + 'px';
202    },
203
204    hideCaptionMenu: function()
205    {
206        this.captionMenu.style.height = 0;
207    },
208
209    captionMenuTransitionEnd: function(event)
210    {
211        if (this.captionMenu.offsetHeight === 0)
212            Controller.prototype.destroyCaptionMenu.apply(this, arguments);
213    },
214
215    handleCaptionButtonMouseOver: function(event)
216    {
217        this.handleCaptionButtonShowMenu(event);
218        return true;
219    },
220
221    handleCaptionButtonShowMenu: function(event)
222    {
223        if (!this.captionMenu)
224            this.buildCaptionMenu();
225        if (!contains(this.captionMenu.captionMenuTreeElements, event.relatedTarget))
226            this.showCaptionMenu();
227        return true;
228    },
229
230    handleCaptionButtonMouseOut: function(event)
231    {
232        if (this.captionMenu && !contains(this.captionMenu.captionMenuTreeElements, event.relatedTarget))
233            this.hideCaptionMenu();
234        return true;
235    },
236
237    handleCaptionMouseOut: function(event)
238    {
239        if (event.relatedTarget != this.controls.captionButton &&
240            !contains(this.captionMenu.captionMenuTreeElements, event.relatedTarget))
241            this.hideCaptionMenu();
242        return true;
243    },
244};
245
246Object.create(Controller.prototype).extend(ControllerGtk.prototype);
247Object.defineProperty(ControllerGtk.prototype, 'constructor', { enumerable:false, value:ControllerGtk });
248