ff-herdict-preso
view js/ff-herdict-preso.js @ 16:851edaba4c87
Linked my name to the related blog post for this project.
| author | Atul Varma <varmaa@toolness.com> |
|---|---|
| date | Wed Feb 10 16:34:49 2010 -0800 (24 months ago) |
| parents | c1a987fe8044 |
| children |
line source
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is Firefox-Herdict Integration Pitch.
15 *
16 * The Initial Developer of the Original Code is Mozilla.
17 * Portions created by the Initial Developer are Copyright (C) 2010
18 * the Initial Developer. All Rights Reserved.
19 *
20 * Contributor(s):
21 * Atul Varma <atul@mozilla.com>
22 *
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
34 *
35 * ***** END LICENSE BLOCK ***** */
37 // This function synchronizes any visual HTML content with the current
38 // position of audio content. It's a generic function that can be used
39 // to provide e.g. the visuals for a narrated slide-show, or
40 // subtitles for a movie.
41 //
42 // The options object should contain the following keys, all
43 // required unless otherwise specified:
44 //
45 // audio - CSS selector that points to a single HTML5
46 // <audio> element. The visuals will be synchronized
47 // with this.
48 //
49 // visuals - CSS selector that points to a collection
50 // of DOM elements, each of which is a visual
51 // to be displayed at some point in the audio.
52 // When the page is first loaded, these elements
53 // shouldn't be visible.
54 //
55 // visibleClass - Class to add to a visual element when it is
56 // being displayed. CSS should be defined such that
57 // adding this class to a visual element actually
58 // makes it visible. Defaults to "visible".
59 //
60 // syncAttr - Attribute name on each visual element that
61 // identifies the time into the audio, in seconds, at
62 // which the visual element it's attached to should
63 // be displayed. Every visual element must have
64 // this attribute, or else an exception will be
65 // thrown when this function is called. Defaults to
66 // "data-at".
67 function syncVisualsWithAudio(options) {
68 var syncInfo = [];
69 var audio = $(options.audio).get(0);
70 var visuals = $(options.visuals);
71 var visibleClass = options.visibleClass || "visible";
72 var syncAttr = options.syncAttr || "data-at";
74 visuals.each(
75 function() {
76 var rawTimestamp = $(this).attr(syncAttr);
77 var timestamp = parseFloat(rawTimestamp);
78 if (isNaN(timestamp))
79 throw new Error("bad '" + syncAttr + "' attribute: " +
80 rawTimestamp);
81 syncInfo.push({timestamp: timestamp, visual: this});
82 });
84 // Return the DOM element that should be displayed as the active
85 // visual the given number of seconds into the audio.
86 function findVisualForTime(timestamp) {
87 var bestVisual;
89 for (var i = 0; i < syncInfo.length; i++) {
90 var info = syncInfo[i];
91 if (info.timestamp <= timestamp)
92 bestVisual = info.visual;
93 }
95 return bestVisual;
96 }
98 // Potentially change the current visual depending on
99 // how far we are into the movie.
100 function maybeChangeVisual() {
101 var visual = findVisualForTime(audio.currentTime);
102 if (visual && !$(visual).hasClass(visibleClass)) {
103 visuals.removeClass(visibleClass);
104 $(visual).addClass(visibleClass);
105 }
106 }
108 audio.addEventListener("timeupdate", maybeChangeVisual, false);
109 maybeChangeVisual();
110 }
112 $(window).ready(
113 function() {
114 // Whenever the current time in the audio soundtrack
115 // changes, alter the current slide if necessary. This
116 // effectively makes the audio UI work just like a
117 // movie UI.
118 syncVisualsWithAudio({audio: "audio#main",
119 visuals: "#slides > div"});
121 // Sync the audio with subtitles.
122 syncVisualsWithAudio({audio: "audio#main",
123 visuals: "#subtitles > p[data-at]"});
125 // Hook up the subtitle UI.
126 $("#show-subtitles").click(function() {
127 $("#subtitles").slideDown();
128 $(this).hide();
129 $("#hide-subtitles").show();
130 });
131 $("#hide-subtitles").click(function() {
132 $("#subtitles").slideUp();
133 $(this).hide();
134 $("#show-subtitles").show();
135 });
137 // Display more license and author info when the license icon is
138 // moused-over.
139 $("#license").mouseenter(function() { $("#more-info").fadeIn(); });
140 });
