1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5(function() {
6  'use strict';
7
8  /**
9   * Moves |target| element above |anchor| element, in order to match the
10   * bottom lines.
11   * @param {HTMLElement} target Target element.
12   * @param {HTMLElement} anchor Anchor element.
13   */
14  function matchBottomLine(target, anchor) {
15    var targetRect = target.getBoundingClientRect();
16    var anchorRect = anchor.getBoundingClientRect();
17
18    var pos = {
19      left: anchorRect.left + anchorRect.width / 2 - targetRect.width / 2,
20      bottom: window.innerHeight - anchorRect.bottom,
21    };
22
23    target.style.position = 'fixed';
24    target.style.left = pos.left + 'px';
25    target.style.bottom = pos.bottom + 'px';
26  }
27
28  /**
29   * Converts the time into human friendly string.
30   * @param {number} time Time to be converted.
31   * @return {string} String representation of the given time
32   */
33  function time2string(time) {
34    return ~~(time / 60000) + ':' + ('0' + ~~(time / 1000 % 60)).slice(-2);
35  }
36
37  Polymer('control-panel', {
38    /**
39     * Initializes an element. This method is called automatically when the
40     * element is ready.
41     */
42    ready: function() {
43      var onFocusoutBound = this.onVolumeControllerFocusout_.bind(this);
44      this.$.volumeSlider.addEventListener('focusout', onFocusoutBound);
45      this.$.volumeButton.addEventListener('focusout', onFocusoutBound);
46    },
47
48    /**
49     * Model object of the Audio Player.
50     * @type {AudioPlayerModel}
51     */
52    model: null,
53
54    /**
55     * Invoked when the model changed.
56     * @param {AudioPlayerModel} oldValue Old Value.
57     * @param {AudioPlayerModel} newValue New Value.
58     */
59    modelChanged: function(oldValue, newValue) {
60      this.$.volumeSlider.model = newValue;
61    },
62
63    /**
64     * Current elapsed time in the current music in millisecond.
65     * @type {number}
66     */
67    time: 0,
68
69    /**
70     * String representation of 'time'.
71     * @type {number}
72     * @private
73     */
74    get timeString_() {
75      return time2string(this.time);
76    },
77
78    /**
79     * Total length of the current music in millisecond.
80     * @type {number}
81     */
82    duration: 0,
83
84    /**
85     * String representation of 'duration'.
86     * @type {string}
87     * @private
88     */
89    get durationString_() {
90      return time2string(this.duration);
91    },
92
93    /**
94     * Flag whether the volume slider is expanded or not.
95     * @type {boolean}
96     */
97    volumeSliderShown: false,
98
99    /**
100     * Flag whether the audio is playing or paused. True if playing, or false
101     * paused.
102     * @type {boolean}
103     */
104    playing: false,
105
106    /**
107     * Invoked when the 'duration' property is changed.
108     * @param {number} oldValue old value.
109     * @param {number} newValue new value.
110     */
111    durationChanged: function(oldValue, newValue) {
112      // Reset the current playback position.
113      this.time = 0;
114    },
115
116    /**
117     * Invoked when the next button is clicked.
118     */
119    nextClick: function() {
120      this.fire('next-clicked');
121    },
122
123    /**
124     * Invoked when the play button is clicked.
125     */
126    playClick: function() {
127      this.playing = !this.playing;
128    },
129
130    /**
131     * Invoked when the previous button is clicked.
132     */
133    previousClick: function() {
134      this.fire('previous-clicked');
135    },
136
137    /**
138     * Invoked the volume button is clicked.
139     * @type {Event} event The event.
140     */
141    volumeButtonClick: function(event) {
142      this.showVolumeController_(this.volumeSliderShown);
143      event.stopPropagation();
144    },
145
146    /**
147     * Invoked when the focus goes out of the volume elements.
148     * @param {FocusEvent} event The focusout event.
149     * @private
150     */
151    onVolumeControllerFocusout_: function(event) {
152      if (this.volumeSliderShown) {
153        // If the focus goes out of the volume, hide the volume control.
154        if (!event.relatedTarget ||
155            (event.relatedTarget !== this.$.volumeButton &&
156             event.relatedTarget !== this.$.volumeSlider)) {
157          this.showVolumeController_(false);
158          this.volumeSliderShown = false;
159        }
160      }
161    },
162
163    /**
164     * Shows/hides the volume controller.
165     * @param {boolean} show True to show the controller, false to hide.
166     * @private
167     */
168    showVolumeController_: function(show) {
169      if (show) {
170        matchBottomLine(this.$.volumeContainer, this.$.volumeButton);
171        this.$.volumeContainer.style.visibility = 'visible';
172      } else {
173        this.$.volumeContainer.style.visibility = 'hidden';
174      }
175    },
176  });
177})();  // Anonymous closure
178