PageSourceSearch

https://adega.gal/radiocerna/js/jplayer/add-on/jplayer.playlist.js

js adega.gal collected 2026-10-02 07:47:37 UTC 15,573 bytes, 452 lines download raw bytes

1/*
2 * Playlist Object for the jPlayer Plugin
3 * http://www.jplayer.org
4 *
5 * Copyright (c) 2009 - 2011 Happyworm Ltd
6 * Dual licensed under the MIT and GPL licenses.
7 *  - http://www.opensource.org/licenses/mit-license.php
8 *  - http://www.gnu.org/copyleft/gpl.html
9 *
10 * Author: Mark J Panaghiston
11 * Version: 2.1.0 (jPlayer 2.1.0)
12 * Date: 1st September 2011
13 */
14
15/* Code verified using http://www.jshint.com/ */
16/*jshint asi:false, bitwise:false, boss:false, browser:true, curly:true, debug:false, eqeqeq:true, eqnull:false, evil:false, forin:false, immed:false, jquery:true, laxbreak:false, newcap:true, noarg:true, noempty:true, nonew:true, nomem:false, onevar:false, passfail:false, plusplus:false, regexp:false, undef:true, sub:false, strict:false, white:false */
17/*global  jPlayerPlaylist: true, jQuery:false, alert:false */
18
19(function($, undefined) {
20
21	jPlayerPlaylist = function(cssSelector, playlist, options) {
22		var self = this;
23
24		this.current = 0;
25		this.loop = false; // Flag used with the jPlayer repeat event
26		this.shuffled = false;
27		this.removing = false; // Flag is true during remove animation, disabling the remove() method until complete.
28
29		this.cssSelector = $.extend({}, this._cssSelector, cssSelector); // Object: Containing the css selectors for jPlayer and its cssSelectorAncestor
30		this.options = $.extend(true, {}, this._options, options); // Object: The jPlayer constructor options for this playlist and the playlist options
31
32		this.playlist = []; // Array of Objects: The current playlist displayed (Un-shuffled or Shuffled)
33		this.original = []; // Array of Objects: The original playlist
34
35		this._initPlaylist(playlist); // Copies playlist to this.original. Then mirrors this.original to this.playlist. Creating two arrays, where the element pointers match. (Enables pointer comparison.)
36
37		// Setup the css selectors for the extra interface items used by the playlist.
38		this.cssSelector.title = this.cssSelector.cssSelectorAncestor + " .jp-title"; // Note that the text is written to the decendant li node.
39		this.cssSelector.playlist = this.cssSelector.cssSelectorAncestor + " .jp-playlist";
40		this.cssSelector.next = this.cssSelector.cssSelectorAncestor + " .jp-next";
41		this.cssSelector.previous = this.cssSelector.cssSelectorAncestor + " .jp-previous";
42		this.cssSelector.shuffle = this.cssSelector.cssSelectorAncestor + " .jp-shuffle";
43		this.cssSelector.shuffleOff = this.cssSelector.cssSelectorAncestor + " .jp-shuffle-off";
44
45		// Override the cssSelectorAncestor given in options
46		this.options.cssSelectorAncestor = this.cssSelector.cssSelectorAncestor;
47
48		// Override the default repeat event handler
49		this.options.repeat = function(event) {
50			self.loop = event.jPlayer.options.loop;
51		};
52
53		// Create a ready event handler to initialize the playlist
54		$(this.cssSelector.jPlayer).bind($.jPlayer.event.ready, function(event) {
55			self._init();
56		});
57
58		// Create an ended event handler to move to the next item
59		$(this.cssSelector.jPlayer).bind($.jPlayer.event.ended, function(event) {
60			self.next();
61		});
62
63		// Create a play event handler to pause other instances
64		$(this.cssSelector.jPlayer).bind($.jPlayer.event.play, function(event) {
65			$(this).jPlayer("pauseOthers");
66		});
67
68		// Create a resize event handler to show the title in full screen mode.
69		$(this.cssSelector.jPlayer).bind($.jPlayer.event.resize, function(event) {
70			if(event.jPlayer.options.fullScreen) {
71				$(self.cssSelector.title).show();
72			} else {
73				$(self.cssSelector.title).hide();
74			}
75		});
76
77		// Create click handlers for the extra buttons that do playlist functions.
78		$(this.cssSelector.previous).click(function() {
79			self.previous();
80			$(this).blur();
81			return false;
82		});
83
84		$(this.cssSelector.next).click(function() {
85			self.next();
86			$(this).blur();
87			return false;
88		});
89
90		$(this.cssSelector.shuffle).click(function() {
91			self.shuffle(true);
92			return false;
93		});
94		$(this.cssSelector.shuffleOff).click(function() {
95			self.shuffle(false);
96			return false;
97		}).hide();
98
99		// Put the title in its initial display state
100		if(!this.options.fullScreen) {
101			$(this.cssSelector.title).hide();
102		}
103
104		// Remove the empty <li> from the page HTML. Allows page to be valid HTML, while not interfereing with display animations
105		$(this.cssSelector.playlist + " ul").empty();
106
107		// Create .live() handlers for the playlist items along with the free media and remove controls.
108		this._createItemHandlers();
109
110		// Instance jPlayer
111		$(this.cssSelector.jPlayer).jPlayer(this.options);
112	};
113
114	jPlayerPlaylist.prototype = {
115		_cssSelector: { // static object, instanced in constructor
116			jPlayer: "#jquery_jplayer_1",
117			cssSelectorAncestor: "#jp_container_1"
118		},
119		_options: { // static object, instanced in constructor
120			playlistOptions: {
vendor: 4,459 bytes, lines 121-260
121				autoPlay: false,
122				loopOnPrevious: false,
123				shuffleOnLoop: true,
124				enableRemoveControls: false,
125				displayTime: 'slow',
126				addTime: 'fast',
127				removeTime: 'fast',
128				shuffleTime: 'slow',
129				itemClass: "jp-playlist-item",
130				freeGroupClass: "jp-free-media",
131				freeItemClass: "jp-playlist-item-free",
132				removeItemClass: "jp-playlist-item-remove"
133			}
134		},
135		option: function(option, value) { // For changing playlist options only
136			if(value === undefined) {
137				return this.options.playlistOptions[option];
138			}
139
140			this.options.playlistOptions[option] = value;
141
142			switch(option) {
143				case "enableRemoveControls":
144					this._updateControls();
145					break;
146				case "itemClass":
147				case "freeGroupClass":
148				case "freeItemClass":
149				case "removeItemClass":
150					this._refresh(true); // Instant
151					this._createItemHandlers();
152					break;
153			}
154			return this;
155		},
156		_init: function() {
157			var self = this;
158			this._refresh(function() {
159				if(self.options.playlistOptions.autoPlay) {
160					self.play(self.current);
161				} else {
162					self.select(self.current);
163				}
164			});
165		},
166		_initPlaylist: function(playlist) {
167			this.current = 0;
168			this.shuffled = false;
169			this.removing = false;
170			this.original = $.extend(true, [], playlist); // Copy the Array of Objects
171			this._originalPlaylist();
172		},
173		_originalPlaylist: function() {
174			var self = this;
175			this.playlist = [];
176			// Make both arrays point to the same object elements. Gives us 2 different arrays, each pointing to the same actual object. ie., Not copies of the object.
177			$.each(this.original, function(i,v) {
178				self.playlist[i] = self.original[i];
179			});
180		},
181		_refresh: function(instant) {
182			/* instant: Can be undefined, true or a function.
183			 *	undefined -> use animation timings
184			 *	true -> no animation
185			 *	function -> use animation timings and excute function at half way point.
186			 */
187			var self = this;
188
189			if(instant && !$.isFunction(instant)) {
190				$(this.cssSelector.playlist + " ul").empty();
191				$.each(this.playlist, function(i,v) {
192					$(self.cssSelector.playlist + " ul").append(self._createListItem(self.playlist[i]));
193				});
194				this._updateControls();
195			} else {
196				var displayTime = $(this.cssSelector.playlist + " ul").children().length ? this.options.playlistOptions.displayTime : 0;
197
198				$(this.cssSelector.playlist + " ul").slideUp(displayTime, function() {
199					var $this = $(this);
200					$(this).empty();
201					
202					$.each(self.playlist, function(i,v) {
203						$this.append(self._createListItem(self.playlist[i]));
204					});
205					self._updateControls();
206					if($.isFunction(instant)) {
207						instant();
208					}
209					if(self.playlist.length) {
210						$(this).slideDown(self.options.playlistOptions.displayTime);
211					} else {
212						$(this).show();
213					}
214				});
215			}
216		},
217		_createListItem: function(media) {
218			var self = this;
219
220			// Wrap the <li> contents in a <div>
221			var listItem = "<li><div>";
222
223			// Create remove control
224			listItem += "<a href='javascript:;' class='" + this.options.playlistOptions.removeItemClass + "'>&times;</a>";
225
226			// Create links to free media
227			if(media.free) {
228				var first = true;
229				listItem += "<span class='" + this.options.playlistOptions.freeGroupClass + "'>(";
230				$.each(media, function(property,value) {
231					if($.jPlayer.prototype.format[property]) { // Check property is a media format.
232						if(first) {
233							first = false;
234						} else {
235							listItem += " | ";
236						}
237						listItem += "<a class='" + self.options.playlistOptions.freeItemClass + "' href='" + value + "' tabindex='1'>" + property + "</a>";
238					}
239				});
240				listItem += ")</span>";
241			}
242
243			// The title is given next in the HTML otherwise the float:right on the free media corrupts in IE6/7
244			listItem += "<a href='javascript:;' class='" + this.options.playlistOptions.itemClass + "' tabindex='1'>" + media.title + (media.artist ? " <span class='jp-artist'>by " + media.artist + "</span>" : "") + "</a>";
245			listItem += "</div></li>";
246
247			return listItem;
248		},
249		_createItemHandlers: function() {
250			var self = this;
251			// Create .live() handlers for the playlist items
252			$(this.cssSelector.playlist + " a." + this.options.playlistOptions.itemClass).die("click").live("click", function() {
253				var index = $(this).parent().parent().index();
254				if(self.current !== index) {
255					self.play(index);
256				} else {
257					$(self.cssSelector.jPlayer).jPlayer("play");
258				}
259				$(this).blur();
260				return false;
261			});
262
263			// Create .live() handlers that disable free media links to force access via right click
264			$(self.cssSelector.playlist + " a." + this.options.playlistOptions.freeItemClass).die("click").live("click", function() {
265				$(this).parent().parent().find("." + self.options.playlistOptions.itemClass).click();
266				$(this).blur();
267				return false;
268			});
269
270			// Create .live() handlers for the remove controls
271			$(self.cssSelector.playlist + " a." + this.options.playlistOptions.removeItemClass).die("click").live("click", function() {
272				var index = $(this).parent().parent().index();
273				self.remove(index);
274				$(this).blur();
275				return false;
276			});
277		},
278		_updateControls: function() {
279			if(this.options.playlistOptions.enableRemoveControls) {
280				$(this.cssSelector.playlist + " ." + this.options.playlistOptions.removeItemClass).show();
281			} else {
282				$(this.cssSelector.playlist + " ." + this.options.playlistOptions.removeItemClass).hide();
283			}
284			if(this.shuffled) {
285				$(this.cssSelector.shuffleOff).show();
286				$(this.cssSelector.shuffle).hide();
287			} else {
288				$(this.cssSelector.shuffleOff).hide();
289				$(this.cssSelector.shuffle).show();
290			}
291		},
292		_highlight: function(index) {
293			if(this.playlist.length && index !== undefined) {
294				$(this.cssSelector.playlist + " .jp-playlist-current").removeClass("jp-playlist-current");
295				$(this.cssSelector.playlist + " li:nth-child(" + (index + 1) + ")").addClass("jp-playlist-current").find(".jp-playlist-item").addClass("jp-playlist-current");
296				$(this.cssSelector.title + " li").html(this.playlist[index].title + (this.playlist[index].artist ? " <span class='jp-artist'>by " + this.playlist[index].artist + "</span>" : ""));
297			}
298		},
299		setPlaylist: function(playlist) {
300			this._initPlaylist(playlist);
301			this._init();
302		},
303		add: function(media, playNow) {
304			$(this.cssSelector.playlist + " ul").append(this._createListItem(media)).find("li:last-child").hide().slideDown(this.options.playlistOptions.addTime);
305			this._updateControls();
306			this.original.push(media);
307			this.playlist.push(media); // Both array elements share the same object pointer. Comforms with _initPlaylist(p) system.
308
309			if(playNow) {
310				this.play(this.playlist.length - 1);
311			} else {
312				if(this.original.length === 1) {
313					this.select(0);
314				}
315			}
316		},
317		remove: function(index) {
318			var self = this;
319
320			if(index === undefined) {
321				this._initPlaylist([]);
322				this._refresh(function() {
323					$(self.cssSelector.jPlayer).jPlayer("clearMedia");
324				});
325				return true;
326			} else {
327
328				if(this.removing) {
329					return false;
330				} else {
331					index = (index < 0) ? self.original.length + index : index; // Negative index relates to end of array.
332					if(0 <= index && index < this.playlist.length) {
333						this.removing = true;
334
335						$(this.cssSelector.playlist + " li:nth-child(" + (index + 1) + ")").slide
vendor: 3,457 bytes, lines 335-452
335Up(this.options.playlistOptions.removeTime, function() {
336							$(this).remove();
337
338							if(self.shuffled) {
339								var item = self.playlist[index];
340								$.each(self.original, function(i,v) {
341									if(self.original[i] === item) {
342										self.original.splice(i, 1);
343										return false; // Exit $.each
344									}
345								});
346								self.playlist.splice(index, 1);
347							} else {
348								self.original.splice(index, 1);
349								self.playlist.splice(index, 1);
350							}
351
352							if(self.original.length) {
353								if(index === self.current) {
354									self.current = (index < self.original.length) ? self.current : self.original.length - 1; // To cope when last element being selected when it was removed
355									self.select(self.current);
356								} else if(index < self.current) {
357									self.current--;
358								}
359							} else {
360								$(self.cssSelector.jPlayer).jPlayer("clearMedia");
361								self.current = 0;
362								self.shuffled = false;
363								self._updateControls();
364							}
365
366							self.removing = false;
367						});
368					}
369					return true;
370				}
371			}
372		},
373		select: function(index) {
374			index = (index < 0) ? this.original.length + index : index; // Negative index relates to end of array.
375			if(0 <= index && index < this.playlist.length) {
376				this.current = index;
377				this._highlight(index);
378				$(this.cssSelector.jPlayer).jPlayer("setMedia", this.playlist[this.current]);
379			} else {
380				this.current = 0;
381			}
382		},
383		play: function(index) {
384			index = (index < 0) ? this.original.length + index : index; // Negative index relates to end of array.
385			if(0 <= index && index < this.playlist.length) {
386				if(this.playlist.length) {
387					this.select(index);
388					$(this.cssSelector.jPlayer).jPlayer("play");
389				}
390			} else if(index === undefined) {
391				$(this.cssSelector.jPlayer).jPlayer("play");
392			}
393		},
394		pause: function() {
395			$(this.cssSelector.jPlayer).jPlayer("pause");
396		},
397		next: function() {
398			var index = (this.current + 1 < this.playlist.length) ? this.current + 1 : 0;
399
400			if(this.loop) {
401				// See if we need to shuffle before looping to start, and only shuffle if more than 1 item.
402				if(index === 0 && this.shuffled && this.options.playlistOptions.shuffleOnLoop && this.playlist.length > 1) {
403					this.shuffle(true, true); // playNow
404				} else {
405					this.play(index);
406				}
407			} else {
408				// The index will be zero if it just looped round
409				if(index > 0) {
410					this.play(index);
411				}
412			}
413		},
414		previous: function() {
415			var index = (this.current - 1 >= 0) ? this.current - 1 : this.playlist.length - 1;
416
417			if(this.loop && this.options.playlistOptions.loopOnPrevious || index < this.playlist.length - 1) {
418				this.play(index);
419			}
420		},
421		shuffle: function(shuffled, playNow) {
422			var self = this;
423
424			if(shuffled === undefined) {
425				shuffled = !this.shuffled;
426			}
427
428			if(shuffled || shuffled !== this.shuffled) {
429
430				$(this.cssSelector.playlist + " ul").slideUp(this.options.playlistOptions.shuffleTime, function() {
431					self.shuffled = shuffled;
432					if(shuffled) {
433						self.playlist.sort(function() {
434							return 0.5 - Math.random();
435						});
436					} else {
437						self._originalPlaylist();
438					}
439					self._refresh(true); // Instant
440
441					if(playNow || !$(self.cssSelector.jPlayer).data("jPlayer").status.paused) {
442						self.play(0);
443					} else {
444						self.select(0);
445					}
446
447					$(this).slideDown(self.options.playlistOptions.shuffleTime);
448				});
449			}
450		}
451	};
452})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.