7 var Event = function(startTime, endTime) {
9 this.startTime = startTime;
10 this.endTime = endTime;
15 * Returns true if the Event should be active, i.e., the media
16 * playback time lies within the start and end times of the Event.
19 Event.prototype.shouldBeActive = function(time) {
20 return time >= this.startTime && time < this.endTime;
24 * Activates or deactivates the Event, according to the isActive flag.
27 Event.prototype.setActive = function(isActive) {
28 this.isActive = isActive;
32 * HtmlEvent constructor.
35 var HtmlEvent = function(startTime, endTime, selector, html) {
36 Event.call(this, startTime, endTime);
37 this.selector = selector;
42 HtmlEvent.prototype = new Event();
45 * Activates or deactivates the HtmlEvent.
48 HtmlEvent.prototype.setActive = function(isActive) {
49 Event.prototype.setActive.call(this, isActive);
52 $(this.selector).html(this.html);
55 $(this.selector).html("");
60 * StyleEvent constructor.
63 var StyleEvent = function(startTime, endTime, selector, cssClass) {
64 Event.call(this, startTime, endTime);
65 this.selector = selector;
66 this.cssClass = cssClass;
70 StyleEvent.prototype = new Event();
72 StyleEvent.prototype.setActive = function(isActive) {
73 Event.prototype.setActive.call(this, isActive);
76 $(this.selector).addClass(cssClass);
79 $(this.selector).removeClass(cssClass);
84 * CustomEvent constructor.
87 var CustomEvent = function(startTime, endTime, action, args) {
88 Event.call(this, startTime, endTime);
94 CustomEvent.prototype = new Event();
97 * Activates or deactivates the CustomEvent.
100 CustomEvent.prototype.setActive = function(isActive) {
101 Event.prototype.setActive.call(this, isActive);
103 if ( typeof this.action === 'function' ) this.action(isActive, this.args);
107 * EventManager constructor.
110 var EventManager = function() {
112 this.currentActiveEvent = null;
117 * Adds an Event to the EventManager.
120 EventManager.prototype.addEvent = function(event) {
121 this.events.push(event);
125 * Sorts the Events held by the EventManager by ascending start time.
128 EventManager.prototype.sort = function() {
129 this.events.sort(function(a, b) {
130 return a.startTime - b.startTime;
135 * Updates the EventManager, given the current media playback time, which
136 * may cause events to be activated or deactivated.
139 EventManager.prototype.update = function(time) {
140 var event = this.findActiveEvent(time);
142 if (event != this.currentActiveEvent) {
143 if (this.currentActiveEvent) {
144 this.currentActiveEvent.setActive(false);
147 this.currentActiveEvent = event;
150 event.setActive(true);
156 * Returns the event that should be active, given the current media
157 * playback time, or null if no event should be active.
159 * Note that this assumes there can only be one active event within
160 * each EventManager object at a time.
163 EventManager.prototype.findActiveEvent = function(time) {
167 /* Check whether the current event should still be active. If not,
168 search for a new event. */
169 if (this.currentActiveEvent && this.currentActiveEvent.shouldBeActive(time)) {
170 event = this.currentActiveEvent;
173 length = this.events.length;
175 for (i = 0; i < length; i++) {
176 if (this.events[i].shouldBeActive(time)) {
177 event = this.events[i];
186 EventManager.prototype.getEventCount = function() {
187 return this.events.length;
190 EventManager.prototype.getEvent = function(index) {
193 if (index >= 0 && index < this.events.length) {
194 event = this.events[index];
201 * TimeCounter constructor.
204 var TimeCounter = function(selector, timeFormatter) {
205 this.counterObject = $(selector);
206 this.currentFormattedTime = "";
209 this.formatTime = timeFormatter;
213 TimeCounter.prototype.update = function(time) {
214 var formattedTime = this.formatTime(time);
216 if (formattedTime != this.currentFormattedTime) {
217 this.currentFormattedTime = formattedTime;
218 this.counterObject.html(formattedTime);
222 TimeCounter.prototype.formatTime = function(time) {
223 return time.toFixed(2);
227 * Synchroniser constructor.
230 var Synchroniser = function(options) {
231 this.customEventManager = null;
232 /* Array of objects that are objects that are synchronisable, i.e., have
233 an update(time) method. */
234 this.synchronisables = [];
236 if (options.hasOwnProperty("htmlEvents")) {
237 this.initEvents(options.htmlEvents, function(event, selector) {
238 return new HtmlEvent(event.startTime, event.endTime, selector, event.html);
242 if (options.hasOwnProperty("styleEvents")) {
243 this.initEvents(options.styleEvents, function(event, selector) {
244 return new StyleEvent(event.startTime, event.endTime, selector, options.activeStyle);
248 if (options.hasOwnProperty("timeCounter")) {
249 var selector = options.timeCounter.selector;
250 var timeFormatter = options.timeCounter.timeFormatter;
253 this.initCounter(selector, timeFormatter);
257 if (options.hasOwnProperty("customEvents")) {
258 this.customEventManager = this.initEventManager(options.customEvents, function(event, selector) {
259 return new CustomEvent(event.startTime, event.endTime, event.action, event.args);
262 this.synchronisables.push(this.customEventManager);
266 Synchroniser.prototype.initEvents = function(events, factory) {
268 var eventManager; /* eventManager contains a set of events for a single selector. */
270 for (selector in events) {
271 if (events.hasOwnProperty(selector)) {
272 eventManager = this.initEventManager(events[selector], factory, selector);
274 this.synchronisables.push(eventManager);
279 Synchroniser.prototype.initEventManager = function(events, factory, selector) {
280 var eventManager = new EventManager();
281 var i, length = events.length;
284 for (i = 0; i < length; i++) {
285 /* Call the factory function to create the event object. */
286 event = factory.call(this, events[i], selector);
287 eventManager.addEvent(event);
295 Synchroniser.prototype.initCounter = function(selector, timeFormatter) {
296 var timeCounter = new TimeCounter(selector, timeFormatter);
297 this.synchronisables.push(timeCounter);
300 Synchroniser.prototype.update = function(time) {
301 var i, length = this.synchronisables.length;
303 for (i = 0; i < length; i++) {
304 this.synchronisables[i].update(time);
308 Synchroniser.prototype.getCustomEventManager = function() {
309 return this.customEventManager;
312 $.fn.sync = function(options) {
313 options = $.extend({}, $.fn.sync.defaults, options);
315 var synchroniser = new Synchroniser(options);
317 return this.each(function() {
318 $(this).data("synchroniser", synchroniser);
320 $(this).bind("timeupdate", function(event) {
321 synchroniser.update(event.target.currentTime);
326 /* Default configuration properties. */
327 $.fn.sync.defaults = {
333 /* CSS class to be added to selectors when a StyleEvent is active. */
334 activeClass: 'syncActive'