PageSourceSearch

https://radioamerica.net/modules/mod_yt_jlex/assets/js/script.js?v=5.2.7

js radioamerica.net collected 2026-10-02 10:50:39 UTC 47,045 bytes, 1,598 lines download raw bytes

1/*
2 * Youtube Feed Pro 4.x.x
3 * 
4 * Copyright 2010-2014, JLexArt.com
5 * http://jlexart.com/
6 * 
7 * Licensed under GPL2 or later
8 */
9function YTF(s) {
10	// Load libs
11	{
12		/*! 
13		 * jquery.event.drag - v 2.2
14		 * Copyright (c) 2010 Three Dub Media - http://threedubmedia.com
15		 * Open Source MIT License - http://threedubmedia.com/code/license
16		 */
17		// Created: 2008-06-04 
18		// Updated: 2012-05-21
19		// REQUIRES: jquery 1.7.x
20
21		;(function( $ ){
22
23		// add the jquery instance method
24		$.fn.drag = function( str, arg, opts ){
25			// figure out the event type
26			var type = typeof str == "string" ? str : "",
27			// figure out the event handler...
28			fn = $.isFunction( str ) ? str : $.isFunction( arg ) ? arg : null;
29			// fix the event type
30			if ( type.indexOf("drag") !== 0 ) 
31				type = "drag"+ type;
32			// were options passed
33			opts = ( str == fn ? arg : opts ) || {};
34			// trigger or bind event handler
35			return fn ? this.bind( type, opts, fn ) : this.trigger( type );
36		};
37
38		// local refs (increase compression)
39		var $event = $.event, 
40		$special = $event.special,
41		// configure the drag special event 
42		drag = $special.drag = {
43			
44			// these are the default settings
45			defaults: {
46				which: 1, // mouse button pressed to start drag sequence
47				distance: 0, // distance dragged before dragstart
48				not: ':input', // selector to suppress dragging on target elements
49				handle: null, // selector to match handle target elements
50				relative: false, // true to use "position", false to use "offset"
51				drop: true, // false to suppress drop events, true or selector to allow
52				click: false // false to suppress click events after dragend (no proxy)
53			},
54			
55			// the key name for stored drag data
56			datakey: "dragdata",
57			
58			// prevent bubbling for better performance
59			noBubble: true,
60			
61			// count bound related events
62			add: function( obj ){ 
63				// read the interaction data
64				var data = $.data( this, drag.datakey ),
65				// read any passed options 
66				opts = obj.data || {};
67				// count another realted event
68				data.related += 1;
69				// extend data options bound with this event
70				// don't iterate "opts" in case it is a node 
71				$.each( drag.defaults, function( key, def ){
72					if ( opts[ key ] !== undefined )
73						data[ key ] = opts[ key ];
74				});
75			},
76			
77			// forget unbound related events
78			remove: function(){
79				$.data( this, drag.datakey ).related -= 1;
80			},
81			
82			// configure interaction, capture settings
83			setup: function(){
84				// check for related events
85				if ( $.data( this, drag.datakey ) ) 
86					return;
87				// initialize the drag data with copied defaults
88				var data = $.extend({ related:0 }, drag.defaults );
89				// store the interaction data
90				$.data( this, drag.datakey, data );
91				// bind the mousedown event, which starts drag interactions
92				$event.add( this, "touchstart mousedown", drag.init, data );
93				// prevent image dragging in IE...
94				if ( this.attachEvent ) 
95					this.attachEvent("ondragstart", drag.dontstart ); 
96			},
97			
98			// destroy configured interaction
99			teardown: function(){
100				var data = $.data( this, drag.datakey ) || {};
101				// check for related events
102				if ( data.related ) 
103					return;
104				// remove the stored data
105				$.removeData( this, drag.datakey );
106				// remove the mousedown event
107				$event.remove( this, "touchstart mousedown", drag.init );
108				// enable text selection
109				drag.textselect( true ); 
110				// un-prevent image dragging in IE...
111				if ( this.detachEvent ) 
112					this.detachEvent("ondragstart", drag.dontstart ); 
113			},
114				
115			// initialize the interaction
116			init: function( event ){ 
117				// sorry, only one touch at a time
118				if ( drag.touched ) 
119					return;
120				// the drag/drop interaction data
121				var dd = event.data, results;
122				// check the which directive
123				if ( event.which != 0 && dd.which > 0 && event.which != dd.which ) 
124					return; 
125				// check for suppressed selector
126				if ( $( event.target ).is( dd.not ) ) 
127					return;
128				// check for handle selector
129				if ( dd.handle && !$( event.target ).closest( dd.handle, event.currentTarget ).length ) 
130					return;
131
132				drag.touched = event.type == 'touchstart' ? this : null;
133				dd.propagates = 1;
134				dd.mousedown = this;
135				dd.interactions = [ drag.interaction( this, dd ) ];
136				dd.target = event.target;
137				dd.pageX = event.pageX;
138				dd.pageY = event.pageY;
139				dd.dragging = null;
140				// handle draginit event... 
141				results = drag.hijack( event, "draginit", dd );
142				// early cancel
143				if ( !dd.propagates )
144					return;
145				// flatten the result set
146				results = drag.flatten( results );
147				// insert new interaction elements
148				if ( results && results.length ){
149					dd.interactions = [];
150					$.each( results, function(){
151						dd.interactions.push( drag.interaction( this, dd ) );
152					});
153				}
154				// remember how many interactions are propagating
155				dd.propagates = dd.interactions.length;
156				// locate and init the drop targets
157				if ( dd.drop !== false && $special.drop ) 
158					$special.drop.handler( event, dd );
159				// disable text selection
160				drag.textselect( false ); 
161				// bind additional events...
162				if ( drag.touched )
163					$event.add( drag.touched, "touchmove touchend", drag.handler, dd );
164				else 
165					$event.add( document, "mousemove mouseup", drag.handler, dd );
166				// helps prevent text selection or scrolling
167				if ( !drag.touched || dd.live )
168					return false;
169			},	
170			
171			// returns an interaction object
172			interaction: function( elem, dd ){
173				var offset = $( elem )[ dd.relative ? "position" : "offset" ]() || { top:0, left:0 };
174				return {
175					drag: elem, 
176					callback: new drag.callback(), 
177					droppable: [],
178					offset: offset
179				};
180			},
181			
182			// handle drag-releatd DOM events
183			handler: function( event ){ 
184				// read the data before hijacking anything
185				var dd = event.data;	
186				// handle various events
187				switch ( event.type ){
188					// mousemove, check distance, start dragging
189					case !dd.dragging && 'touchmove': 
190						event.preventDefault();
191					case !dd.dragging && 'mousemove':
192						//  drag tolerance, x² + y² = distance²
193						if ( Math.pow(  event.pageX-dd.pageX, 2 ) + Math.pow(  event.pageY-dd.pageY, 2 ) < Math.pow( dd.distance, 2 ) ) 
194							break; // distance tolerance not reached
195						event.target = dd.target; // force target from "mousedown" event (fix distance issue)
196						drag.hijack( event, "dragstart", dd ); // trigger "dragstart"
197						if ( dd.propagates ) // "dragstart" not rejected
198							dd.dragging = true; // activate interaction
199					// mousemove, dragging
200					case 'touchmove':
201						event.preventDefault();
202					case 'mousemove':
203						if ( dd.dragging ){
204							// trigger "drag"		
205							drag.hijack( event, "drag", dd );
206							if ( dd.propagates ){
207								// manage drop events
208								if ( dd.drop !== false && $special.drop )
209									$special.drop.handler( event, dd ); // "dropstart", "dropend"							
210								break; // "drag" not rejected, stop		
211							}
212							event.type = "mouseup"; // helps "drop" handler behave
213						}
214					// mouseup, stop dragging
215					case 'touchend': 
216					case 'mouseup': 
217					default:
218						if ( drag.touched )
219							$event.remove( drag.touched, "touchmove touchend", drag.handler ); // remove touch events
220						else 
221							$event.remove( document, "mousemove mouseup", drag.handler ); // remove page events	
222						if ( dd.dragging ){
223							if ( dd.drop !== false && $special.drop )
224								$special.drop.handler( event, dd ); // "drop"
225							drag.hijack( event, "dragend", dd ); // trigger "dragend"	
226						}
227						drag.textselect( true ); // enable text selection
228						// if suppressing click events...
229						if ( dd.click === false && dd.dragging )
230							$.data( dd.mousedown, "suppress.click", new Date().getTime() + 5 );
231						dd.dragging = drag.touched = false; // deactivate element	
232						break;
233				}
234			},
235				
236			// re-use event object for custom events
237			hijack: function( event, type, dd, x, elem ){
238				// not configured
239				if ( !dd ) 
240					return;
241				// remember the original event and type
242				var orig = { event:event.originalEvent, type:event.type },
243				// is the event drag related or drog related?
244				mode = type.indexOf("drop") ? "drag" : "drop",
245				// iteration vars
246				result, i = x || 0, ia, $elems, callback,
247				len = !isNaN( x ) ? x : dd.interactions.length;
248				// modify the event type
249				event.type = type;
250				// remove the original event
251				event.originalEvent = null;
252				// initialize the results
253				dd.results = [];
254				// handle each interacted element
255				do if ( ia = dd.interactions[ i ] ){
256					// validate the interaction
257					if ( type !== "dragend" && ia.cancelled )
258						continue;
259					// set the dragdrop properties on the event object
260					callback = drag.properties( event, dd, ia );
261					// prepare for more results
262					ia.results = [];
263					// handle each element
264					$( elem || ia[ mode ] || dd.droppable ).each(function( p, subject ){
265						// identify drag or drop targets individually
266						callback.target = subject;
267						// force propagtion of the custom event
268						event.isPropagationStopped = function(){ return false; };
269						// handle the event	
270						result = subject ? $event.dispatch.call( subject, event, callback ) : null;
271						// stop the drag interaction for this element
272						if ( result === false ){
273							if ( mode == "drag" ){
274								ia.cancelled = true;
275								dd.propagates -= 1;
276							}
277							if ( type == "drop" ){
278								ia[ mode ][p] = null;
279							}
280						}
281						// assign any dropinit elements
282						else if ( type == "dropinit" )
283							ia.droppable.push( drag.element( result ) || subject );
284						// accept a returned proxy element 
285						if ( type == "dragstart" )
286							ia.proxy = $( drag.element( result ) || ia.drag )[0];
287						// remember this result	
288						ia.results.push( result );
289						// forget the event result, for recycling
290						delete event.result;
291						// break on cancelled handler
292						if ( type !== "dropinit" )
293							return result;
294					});	
295					// flatten the results	
296					dd.results[ i ] = drag.flatten( ia.results );	
297					// accept a set of valid drop targets
298					if ( type == "dropinit" )
299						ia.droppable = drag.flatten( ia.droppable );
300					// locate drop targets
301					if ( type == "dragstart" && !ia.cancelled )
302						callback.update(); 
303				}
304				while ( ++i < len )
305				// restore the original event & type
306				event.type = orig.type;
307				event.originalEvent = orig.event;
308				// return all handler results
309				return drag.flatten( dd.results );
310			},
311				
312			// extend the callback object with drag/drop properties...
313			properties: function( event, dd, ia ){		
314				var obj = ia.callback;
315				// elements
316				obj.drag = ia.drag;
317				obj.proxy = ia.proxy || ia.drag;
318				// starting mouse position
319				obj.startX = dd.pageX;
320				obj.startY = dd.pageY;
321				// current distance dragged
322				obj.deltaX = event.pageX - dd.pageX;
323				obj.deltaY = event.pageY - dd.pageY;
324				// original element position
325				obj.originalX = ia.offset.left;
326				obj.originalY = ia.offset.top;
327				// adjusted element position
328				obj.offsetX = obj.originalX + obj.deltaX; 
329				obj.offsetY = obj.originalY + obj.deltaY;
330				// assign the drop targets information
331				obj.drop = drag.flatten( ( ia.drop || [] ).slice() );
332				obj.available = drag.flatten( ( ia.droppable || [] ).slice() );
333				return obj;	
334			},
335			
336			// determine is the argument is an element or jquery instance
337			element: function( arg ){
338				if ( arg && ( arg.jquery || arg.nodeType == 1 ) )
339					return arg;
340			},
341			
342			// flatten nested jquery objects and arrays into a single dimension array
343			flatten: function( arr ){
344				return $.map( arr, function( member ){
345					return member && member.jquery ? $.makeArray( member ) : 
346						member && member.length ? drag.flatten( member ) : member;
347				});
348			},
349			
350			// toggles text selection attributes ON (true) or OFF (false)
351			textselect: function( bool ){ 
352				$( document )[ bool ? "unbind" : "bind" ]("selectstart", drag.dontstart )
353					.css("MozUserSelect", bool ? "" : "none" );
354				// .attr("unselectable", bool ? "off" : "on" )
355				document.unselectable = bool ? "off" : "on"; 
356			},
357			
358			// suppress "selectstart" and "ondragstart" events
359			dontstart: function(){ 
360				return false; 
361			},
362			
363			// a callback instance contructor
364			callback: function(){}
365			
366		};
367
368		// callback methods
369		drag.callback.prototype = {
370			update: function(){
371				if ( $special.drop && this.available.length )
372					$.each( this.available, function( i ){
373						$special.drop.locate( this, i );
374					});
375			}
376		};
377
378		// patch $.event.$dispatch to allow suppressing clicks
379		var $dispatch = $event.dispatch;
380		$event.dispatch = function( event ){
381			if ( $.data( this, "suppress."+ event.type ) - new Date().getTime() > 0 ){
382				$.removeData( this, "suppress."+ event.type );
383				return;
384			}
385			return $dispatch.apply( this, arguments );
386		};
387
388		// event fix hooks for touch events...
389		var touchHooks = 
390		$event.fixHooks.touchstart = 
391		$event.fixHooks.touchmove = 
392		$event.fixHooks.touchend =
393		$event.fixHooks.touchcancel = {
394			props: "clientX clientY pageX pageY screenX screenY".split( " " ),
395			filter: function( event, orig ) {
396				if ( orig ){
397					var touched = ( orig.touches && orig.touches[0] )
398						|| ( orig.changedTouches && orig.changedTouches[0] )
399						|| null; 
400					// iOS webkit: touchstart, touchmove, touchend
401					if ( touched ) 
402						$.each( touchHooks.props, function( i, prop ){
403							event[ prop ] = touched[ prop ];
404						});
405				}
406				return event;
407			}
408		};
409
410		// share the same special event configuration with related events...
411		$special.draginit = $special.dragstart = $special.dragend = drag;
412
413		})( jQuery );
414	}
415
416	// Youtube module core!
417	var $j = jQuery.noConflict();
418	var _this=this,
419		$p=$j('#ytfPlayer_'+s.moduleid),
420		ytdata=[], // static of data
421		ytdataid=[],
422		vidData=[], // dynamic data
423		isReady=false,
424		vidCurrent=0,
425		player,
426		scroll=null,
427		bglist=false,
428		oldWidth=0,
429		limit=s.limit,
430		limitstart=limit,
431		keyword='';
432
433	_this.data = {
434		pending : [],
435		process :[],
436		completed: [],
437		root:[],
438		count:0
439	};
440
441	_this.player = null;
442	_this.playerIndex = 0;
443
444	if(s.style=="background")
445	{
446		// special variables for background mode
447		s.autoplay = 1;
448		s.controls = 0;
449		s.showinfo = 0;
450		s.show_desc = 0;
451		s.rel = 0;
452		s.show_list = 0;
453		s.fs = 0;
454		s.annotation = 0;
455		s.brand = 0;
456		s.intromode = 0;
457		s.bgurl = '';
458	}
459
460	if(s.style=='slider'){
461		s.showlist = 1;
462		s.showthumb = 1;
463	}
464
465	_this.passKeyword=function(title)
466	{
467		var preg_quote = function(str, delimiter){
468				return (str + '')
469		    	.replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\' + (delimiter || '') + '-]', 'g'), '\\$&')
470			},
471			regex = new RegExp(preg_quote(keyword), "i");
472
473		if(regex.test(title)) return true;
474		return false;
475	};
476
477	_this.yesReady=function(){
478		if(s.popup){
479			var wh=$j(window).height();
480			if (wh>$p.find('.ytfPopup').height()) {
481				$p.find('.ytfPopup').css('top',((wh-$p.find('.ytf-container').height())/2)+'px');
482			} else {
483				$p.find('.ytfPopup').css({'margin-top':'10px','margin-bottom':'10px'});
484			}
485		}
486
487		_this.loadThumb();
488		$p.find('.ytf-loading').fadeOut('fast');
489		$p.find('.ytf-container').addClass('ytf-ready');
490		$p.find('.ytf-player,.ytf-sidebar,.ytfOpenlist').addClass('ytf-ready');
491
492		if (s.grid_popup && (s.style=='grid' || s.style=='slider')) $p.find(".ytf-player").hide();
493	};
494
495	_this.formatTime=function(duration){
496		var parts=duration.match(/([0-9]+H)?([0-9]+M)?([0-9]+S)?$/),
497			hours = typeof parts[1]!="undefined" ? parseInt(parts[1]):0,
498	    	minutes = typeof parts[2]!="undefined" ? parseInt(parts[2]):0,
499	    	seconds = typeof parts[3]!="undefined" ? parseInt(parts[3]):0,
500	    	strtime = "";
501		if (hours>0)
502		{
503			strtime+=(hours<10?'0'+hours:hours)+':';
504		}
505
506	    strtime+=(minutes<10?'0'+minutes:minutes)+':'+(seconds<10?'0'+seconds:seconds);
507		return strtime;
508	};
509
510	_this.str2Time=function(timestring,format){
511		var n=timestring.match(/[0-9]+/g),r;
512		if (format==1) {
513			var now=new Date().getTime();
514			var vdate=new Date(n[0], parseInt(n[1])-1, n[2], n[3], n[4], n[5],0).getTime();
515			$elstime=(now-vdate)/1000;
516			if ($elstime<60) {
517				r=s.lang.RECENT;
518			} else if ($elstime < 3600) {
519				r=parseInt($elstime/60) + ' ' + s.lang.MINUTE;
520			} else if ($elstime < 24*3600) {
521				r=parseInt($elstime/3600) + ' ' + s.lang.HOURS;
522			} else if ($elstime < 24*3600*30) {
523				r=parseInt($elstime/(3600*24)) + ' '+ s.lang.DAYS;
524			} else if ($elstime < 24*3600*30*12) {
525				r=parseInt($elstime/(3600*24*30)) + ' '+ s.lang.MONTHS;
526			} else {
527				r=parseInt($elstime/(3600*24*30*12)) + ' '+ s.lang.YEARS;
528			}
529			if ($elstime>=60) r=r+' '+s.lang.AGO;
530		} else {
531			r=n[3]+':'+n[4]+':'+n[5]+' '+n[2]+'/'+n[1]+'/'+n[0];
532		}
533		return r;
534	};
535
536	_this.shortStr=function(str,maxword){
537		var t=str.split(" "),nt='',min=Math.min(t.length,maxword);
538		if (maxword>min) return str;
539		for (i=0;i<min;i++) {
540			nt+=t[i]+' ';
541		}
542		return $j.trim(nt)+'...';
543	};
544
545	/**
546	 * Apply for touch device when screen small
547	 */
548	_this.openlist=function(obj) {
549		if(s.style=='slider') return;
550
551		if ($j(obj).hasClass('opened')) {
552			$p.find('.ytf-sidebar').removeClass('opened');
553			$p.removeClass('list-open');
554			$j(obj).removeClass('opened').text(s.lang.SHOW_LIST);
555		} else {
556			$p.find('.ytf-sidebar').addClass('opened');
557			$p.addClass('list-open');
558			$j(obj).addClass('opened').text(s.lang.HIDE_LIST);
559		}
560		if (scroll) { scroll.update(); }
561	};
562
563	/**
564	 * Move list, use for hoz style
565	 * Stop this feature at v3.x
566	 */
567	_this.moveList=function(way){
568		return;
569	};
570
571	_this.swipeTo=function(index){
572		if (scroll) {
573			scroll.moveTo(index);
574		}
575	};
576
577	_this.bindHTML=function(callback){
578		/* Bind size */
579		var list_center = function(resize)
580			{
581				if (s.style!='grid' || s.listcenter==0)
582				{
583					return true;
584				}
585
586				if ($p.find('.ytfBlock').length < 2)
587				{
588					return false;
589				}
590
591				if ($p.find('.ytf-container').hasClass("ytf-xs") || $p.find('.ytf-container').hasClass("ytf-sm"))
592				{
593					$p.find('.swiper-wrapper').removeAttr("style");
594					$p.find('.ytfBlock').removeAttr("style");
595					return true;
596				}
597
598				var wItem = $p.find('.ytfBlock:eq(0)').width(),
599					wBox = $p.find('.swiper-container').width(),
600					nLine,
601					wSpace,
602					wWrap;
603
604				nLine = parseInt(wBox/wItem);
605				wSpace = parseInt( (wBox-(wItem)*nLine)/(nLine-1) );
606				$p.find('.swiper-wrapper').width(nLine*(wSpace+wItem));
607				$p.find('.ytfBlock').css('margin-right',wSpace);
608			
609				return true;
610			},
611
612			adjust_tpl = function(resize)
613			{
614				var w=$p.find('.ytf-container').outerWidth(),
615					ww=$j(window).width();
616
617				/*if (ww==oldWidth) {
618					return null;
619				} else {
620					oldWidth=ww;
621				}*/
622
623				$p.find('.ytf-container').removeClass('ytf-xs ytf-sm ytf-md ytf-lg');
624				$p.find('.ytf-player,.ytf-sidebar').css({height:'',width:''});
625				$p.find('a.opened').text(s.lang.SHOW_LIST).removeClass('opened');
626				$p.find('div.opened').removeClass('opened');
627
628				var subOfWidth = 0;
629				var activeSize = null;
630
631				if (s.show_list) {
632					var searchboxHeight = s.searchbox?35:0;
633					if (w < s.small_devices) {
634						activeSize = 'ytf-xs';
635					} else if (w < s.medium_devices && w>= s.small_devices) {
636						activeSize = 'ytf-sm';
637					} else if (w < s.large_devices && w>= s.medium_devices) {
638						activeSize = 'ytf-md';
639						if (s.style=='ver')
640						{
641							subOfWidth = 114;
642							$p.find('.ytf-sidebar').height((w-114)*(s.ratio=='4:3'?3/4:9/16)-35-searchboxHeight);
643						}	
644					} else {
645						activeSize = 'ytf-lg';
646						if (s.style=='ver') {
647							subOfWidth = 300;
648							$p.find('.ytf-sidebar').height((w-300)*(s.ratio=='4:3'?3/4:9/16)-searchboxHeight);
649						}			
650					}
651					$p.find('.ytf-container').addClass(activeSize);
652				} else {
653					$p.find('.ytf-sidebar').remove();
654				}
655
656				// size of player
657				if ((s.style=="grid"||s.style=="slider") && s.grid_popup=="1")
658				{
659					var playerWidth  = $p.find(".ytf-player").width(),
660						playerHeight = playerWidth*(s.ratio=='4:3'?3/4:9/16),
661						topOffset 	 = 0;
662
663					if (playerHeight>=$j(window).height())
664					{
665						playerHeight = $j(window).height();
666						topOffset = 0;
667					} else {
668						topOffset = ($j(window).height() - playerHeight)/2;
669					}
670
671					$p.find('.ytf-player').css({
672						'height':playerHeight+'px',
673						'top' : topOffset+'px'
674					});
675				} else {
676					if(s.style=="background")
677					{
678						// height, width, top, left
679						var bgSpace = 60,
680							bgCtHeight = $p.find('.ytf-bgContent').outerHeight(),
681							bgCtWidth = $p.find('.ytf-bgContent').outerWidth(),
682							bgHeight=0, bgWidth=0, bgTop=0, bgLeft=0;
683
684						if(bgCtWidth/bgCtHeight>(s.ratio=='4:3'?4/3:16/9)){
685							bgWidth=bgCtWidth+bgSpace*2*(s.ratio=='4:3'?4/3:16/9);
686							bgHeight=(s.ratio=='4:3'?3/4:9/16)*bgWidth+bgSpace*2;
687							bgTop=-1*(bgHeight-bgCtHeight)/2;
688							bgLeft=-1*bgSpace*(s.ratio=='4:3'?4/3:16/9);
689						} else {
690							bgHeight=bgCtHeight+bgSpace*2;
691							bgWidth=(s.ratio=='4:3'?4/3:16/9)*bgHeight;
692							bgLeft=-1*(bgWidth-bgCtWidth)/2;
693							bgTop=-1*bgSpace;
694						}
695
696						$p.find('.ytf-player').css({
697							top:bgTop+'px',
698							left:bgLeft+'px',
699							width:bgWidth+'px',
700							height:bgHeight+'px'
701						});
702					} else {
703						$p.find('.ytf-player').css({'height':((w-subOfWidth)*(s.ratio=='4:3'?3/4:9/16))+'px','width':(w-subOfWidth-1)+'px'});
704					}
705				}
706				
707				
708				/* popup */
709				if (s.popup) {
710					if ($j(window).outerHeight()>$p.find('.ytf-container').outerHeight()) {
711						$p.find('.ytfPopup').css('top',(($j(window).outerHeight()-$p.find('.ytf-container').outerHeight())/2)+'px');
712					} else {
713						$p.find('.ytfPopup').css({'margin-top':'10px','margin-bottom':'10px'});
714					}	
715				}
716
717				/* for Grid style - Center align */
718				var tm = window.setInterval(function(){
719					if(list_center(resize)==true)
720					{
721						window.clearInterval(tm);
722					}
723				}, 1000);
724			};
725		
726		$j(window).on('resize',function(){
727			adjust_tpl(true);
728		});
729
730		if (s.popup) {
731			$j('body').css('overflow','hidden');
732		}
733
734		// background
735		if (s.style=="background")
736		{
737			var html = '<div class="ytf-bgContent">';
738					html+= '<div>'+s.introtext+'</div>';
739					if (s.background_tool==1)
740					{
741						html+= '<div class="ytf-api-tools" style="display:none">';
742							html+= '<button class="_status _playing"></button>';
743							html+= '<button class="_sound _mute"></button>';
744						html+= '</div>';
745					}
746				html+= '</div>';
747
748			$p.find('.ytf-container').prepend(html);
749		}
750
751		adjust_tpl(false);
752		
753		// stop event when list not shown
754		if (!s.show_list) {
755			if (callback) {
756				window.setTimeout(function(){
757					callback();
758				},200);
759			}
760			return null;
761		}
762		
763		if (s.style=='ver')
764		{
765			//open list button
766			$j('<a class="ytfOpenlist" onclick="ytf_'+s.moduleid+'.openlist(this)">'+s.lang.SHOW_LIST+'</a>').insertAfter($p.find('.ytf-player'));
767		}
768
769		if(s.style=='slider'){
770			$p.find('.swiper-container').prepend('<div class="swiper-wrapper"></div>');
771		} else {
772			$p.find('.swiper-container').html('<div class="swiper-wrapper"></div>');
773		}
774		
775		if (s.style=='hoz')
776		{
777			var widthOfItem=$p.find('.ytfBlock:eq(0)').width();
778			$p.find('.swiper-wrapper').width(widthOfItem*$p.find('.ytfBlock').length);
779		}
780
781
782		switch(s.style){
783			case 'slider':
784				scroll=new _this.slider();
785				break;
786
787			case 'grid':
788				$p.on('click','.btn-more',function(){
789					$p.find('.ytfBlock.hidden').slice(0,limit).removeClass('hidden');
790					if (!$p.find('.ytfBlock.hidden').length) {
791						$j(this).removeClass('active');
792					}
793					limitstart+=limit;
794				});
795				break;
796
797			default:
798				scroll=new _this.scrollbar({
799					ob:'#ytfPlayer_'+s.moduleid+' .swiper-container',
800					direction:s.style
801				});
802				break;
803		}
804		
805		if (callback) {
806			window.setTimeout(function(){
807				callback();
808			},200);
809		}
810	};
811
812	_this.offset_list = 0;
813	_this.update_list=function(reset) {
814		if(typeof reset=='undefined') reset=true;
815		if(!_this.data.process.length) return;
816		if(s.style=='grid'&&s.pagination=='list'&&reset==true)
817		{
818			$p.find('.pages').empty().pagination({
819			    dataSource: _this.data.process,
820			    pageSize: s.limit,
821			    showPrevious: false,
822			    showNext: false,
823			    className:'pagination',
824			    callback: function(data, pagination) {		
825					_this.data.completed=data;
826					_this.data.process=data;
827					_this.offset_list=0;
828			        _this.update_list(false);
829			    }
830			})
831			return;
832		}
833
834		var currentOffset=_this.offset_list,
835			showViewCount=function(v)
836			{
837				v*=1;
838				if (v>Math.pow(10,9)) {
839					v=(v/Math.pow(10,9)).toFixed(1)+'B';
840				} else if (v>Math.pow(10,6)) {
841					v=(v/Math.pow(10,6)).toFixed(1)+'M';
842				} else if (v>Math.pow(10,3)) {
843					v=(v/Math.pow(10,3)).toFixed(1)+'K';
844				}
845				return v;
846			};
847
848		var html='';
849		$j.each(_this.data.process,function(k,v){
850			k+=currentOffset;
851			_this.offset_list+=1;
852
853			var thumb='https://i1.ytimg.com/vi/'+v.id+'/'+s.thumbsize;
854			
855			html+='<div class="ytfBlock swiper-slide '+(s.style=='grid' && s.pagination=='more' && k>=limitstart?'hidden':'')+'" data-index="'+k+'" data-id="'+v.id+'">';
856			
857			if(s.showthumb)
858			{
859				html+='<div class="ytfThumb"><span class="ytfThumbload" data-src="'+thumb+'" data-class="'+(s.thumbsize!='mqdefault.jpg'?'ytfAlign':'')+'" data-title="'+v.title+'"></span>';
860			
861				if(s.show_duration) html+='<span class="ytfDuration">'+_this.formatTime(v.length)+'</span>';
862					html+='<div class="_border">';
863						if (s.style=='grid') html+='<span class="_t">'+s.lang.PLAYING+'</span>';
864					html+='</div>';
865				html+='</div>';
866			}
867
868			html+='<div class="ytfMeta">';
869				if(s.title) html+='<a href="javascript:void(0);" class="ytfTitle">'+_this.shortStr(v.title, s.maxword)+'</a>';
870				if(s.show_author) html+='<span class="ytfAuthor">'+v.author+'</span>';
871				if(s.show_created) html+='<span class="ytfPublished">'+_this.str2Time(v.published,1)+'</span>';
872				if(s.show_views_count==1) html+='<span class="ytfViewsCount">'+showViewCount(v.viewCount)+' '+s.lang.VIEWS+'</span>';
873
874				if(s.show_desc&&s.desc_position=='thumb'){
875					html+='<div class="ytfDesc">'+v.description.replace(/\r\n|\r|\n/g, '<br/>')+'</div>';
876				}
877			html+='</div><i class="_clear"></i>';
878			if(s.style=='hoz') html+='<div class="ytfDeactive"></div>';
879			html+='</div>';
880
881			if(s.style=='grid' && s.pagination=='more'){
882				k>=limitstart?$p.find('.btn-more').addClass('active'):$p.find('.btn-more').removeClass('active');
883			}
884		});
885
886		$p.find('.swiper-wrapper').empty().append(html);
887
888		// update width of container
889		if(s.style=='hoz'){
890			var wi=$p.find('.ytfBlock:eq(0)').width();
891			$p.find('.swiper-wrapper').width(wi*$p.find('.ytfBlock').length);
892		}
893
894		// update scrollbar
895		if(scroll){scroll.update();}
896
897		// for grid style
898		var list_center = function(resize)
899			{
900				if(s.style!='grid'||s.listcenter==0) return true;
901				if($p.find('.ytfBlock').length<2) return false;
902
903				if($p.find('.ytf-container').hasClass("ytf-xs") || $p.find('.ytf-container').hasClass("ytf-sm"))
904				{
905					$p.find('.swiper-wrapper').removeAttr("style");
906					$p.find('.ytfBlock').removeAttr("style");
907					return true;
908				}
909
910				var wItem = $p.find('.ytfBlock:eq(0)').width(),
911					wBox = $p.find('.swiper-container').width(),
912					nLine,
913					wSpace,
914					wWrap;
915
916				nLine = parseInt(wBox/wItem);
917				wSpace = parseInt( (wBox-(wItem)*nLine)/(nLine-1) );
918				$p.find('.swiper-wrapper').width(nLine*(wSpace+wItem));
919				$p.find('.ytfBlock').css('margin-right',wSpace);
920			
921				return true;
922			};
923
924		list_center();
925	};
926
927	_this.slider=function(){
928		var o = this,
929			initSwiper = null,
930			delayUpdate = null;
931
932		o.init=function(){
933			initSwiper = new Swiper($p.find('.swiper-container'), {
934				slidesPerView:5,
935				spaceBetween:20,
936				autoHeight:true,
937
938				breakpoints: {
939					400: {slidesPerView:1,},
940					750: {slidesPerView:2,},
941					1000: {slidesPerView:3,},
942					1200: {slidesPerView:4}
943				},
944
945				// Navigation arrows
946				navigation: {
947					nextEl: $p.find('.swiper-button-next'),
948					prevEl: $p.find('.swiper-button-prev'),
949				},
950			});
951		};
952
953		o.moveTo=function(index){
954
955		};
956
957		o.update=function(){
958			initSwiper.update();
959			window.setInterval(function(){
960				initSwiper.updateAutoHeight();
961			},500);
962		};
963
964		o.init();
965	};
966
967	_this.scrollbar=function(params){
968		var oc=this,
969			$ob=$j(params.ob),
970			direction=params.direction?params.direction:'ver',
971			xy=direction=='hoz'?
972			{
973				left:'left',
974				outerWidth:'outerWidth',
975				width:'width',
976				offsetX:'offsetX',
977				deltaX:'deltaX',
978				scrollLeft:'scrollLeft',
979				pageX:'pageX'
980			}:
981			{
982				left:'top',
983				outerWidth:'outerHeight',
984				width:'height',
985				offsetX:'offsetY',
986				deltaX:'deltaY',
987				scrollLeft:'scrollTop',
988				pageX:'pageY'
989			};
990
991		this.init=function(){
992			if('ontouchstart' in document.documentElement) {
993				// Your device support touch event
994				return;
995			}
996			var lengthOfbar=direction=='hoz'?$ob.width()/$ob[0].scrollWidth:$ob.height()/$ob[0].scrollHeight;
997			if (lengthOfbar>=1) {
998				lengthOfbar=1;
999			}
1000			// Adjust width/height of contain
1001			if (direction=='ver') {
1002				$ob.removeAttr('style');
1003				$ob.width( $ob.width()+oc.getScrollBarWidth() );
1004			}
1005			$ob.append('<div class="ytf-scrollbox"><span class="ytf-scrollbar" style="'+(direction=='hoz'?'width':'height')+':'+(lengthOfbar*100)+'%"></span></div>');
1006			var $div=$ob.find('.ytf-scrollbox');
1007			var enableScroll=true;
1008			$ob.find('.ytf-scrollbar').drag("start",function( ev, dd ){
1009				enableScroll=false;
1010				dd.limit = $div.position();
1011	          	dd.limit.dp = dd.limit[xy.left] + $div[xy.outerWidth]() - $j( this )[xy.outerWidth]();
1012	          	dd.delta = ($ob.find('.swiper-wrapper')[xy.width]()-$ob[xy.width]())/($ob[xy.width]()-$j(this)[xy.width]());
1013	          	dd[xy.left] = $j(this).position()[xy.left];
1014			})
1015			.drag(function( ev, dd ){
1016				var css={};
1017				css[xy.left]=Math.min( dd.limit.dp, Math.max( dd.limit[xy.left], dd[xy.offsetX] ) );
1018				$j( this ).css(css);
1019				$ob[xy.scrollLeft](dd.delta*(dd[xy.left]+dd[xy.deltaX]));
1020			},{ relative:true })
1021			$ob.find('.ytf-scrollbar').drag("end",function( ev, dd ){
1022				window.setTimeout(function(){
1023					enableScroll=true;
1024				},500);
1025			});
1026			
1027			/* Bind scroll event */
1028			$ob.scroll(function(){
1029				if (!enableScroll) return;
1030				var delta=($j(this).find('.swiper-wrapper')[xy.width]()-$j(this)[xy.width]())/($j(this)[xy.width]()-$ob.find('.ytf-scrollbar')[xy.width]());
1031				var css={};
1032				css[xy.left]=$j(this)[xy.scrollLeft]()/delta;
1033				$ob.find('.ytf-scrollbar').css(css);
1034			});
1035			$ob.find('.ytf-scrollbox').click(function(e){
1036				if (!enableScroll) return;
1037				var delta=($ob.find('.swiper-wrapper')[xy.width]()-$j(this)[xy.width]())/($j(this)[xy.width]()-$ob.find('.ytf-scrollbar')[xy.width]());
1038				var parentOffset = jQuery(this).parent().offset(); 
1039				//or $(this).offset(); if you really just want the current element's offset
1040				var rel = e[xy.pageX] - parentOffset[xy.left];
1041				$ob[xy.scrollLeft](rel*delta);
1042			})
1043			
1044			$j(window).resize(function(){
1045				oc.update();
1046			});
1047		};
1048		this.moveTo=function(index){
1049			if (!$ob.find('.ytfBlock').eq(index).length) return;
1050			var length=$ob.find('.ytfBlock').eq(index).position()[xy.left];
1051			$ob[xy.scrollLeft](length);
1052		};
1053		this.update=function(){
1054			var delta=($ob.find('.swiper-wrapper')[xy.width]()-$ob[xy.width]())/($ob[xy.width]()-$ob.find('.ytf-scrollbar')[xy.width]());
1055			var lengthOfbar=direction=='hoz'?$ob.width()/$ob[0].scrollWidth:$ob.height()/$ob[0].scrollHeight;
1056			var css={};
1057			// Adjust width/height of contain
1058			if (direction=='ver') {
1059				$ob.removeAttr('style');
1060				$ob.width( $ob.width()+oc.getScrollBarWidth() );
1061			}
1062			//  Adjust width/height of scrollbar (percent unix)
1063			css[xy.width]=lengthOfbar*100+'%';
1064			css[xy.left]=$ob[xy.scrollLeft]()/delta;
1065			$ob.find('.ytf-scrollbar').css(css);
1066		};
1067		this.getScrollBarWidth=(function(){
1068			var inner = document.createElement('p');
1069			  inner.style.width = "100%";
1070			  inner.style.height = "200px";
1071
1072			  var outer = document.createElement('div');
1073			  outer.style.position = "absolute";
1074			  outer.style.top = "0px";
1075			  outer.style.left = "0px";
1076			  outer.style.visibility = "hidden";
1077			  outer.style.width = "200px";
1078			  outer.style.height = "150px";
1079			  outer.style.overflow = "hidden";
1080			  outer.appendChild (inner);
1081
1082			  document.body.appendChild (outer);
1083			  var w1 = inner.offsetWidth;
1084			  outer.style.overflow = 'scroll';
1085			  var w2 = inner.offsetWidth;
1086			  if (w1 == w2) w2 = outer.clientWidth;
1087
1088			  document.body.removeChild (outer);
1089
1090			  return (w1 - w2);
1091		});
1092		this.init();
1093	};
1094
1095	_this.loadThumb = function()
1096	{
1097		var loadThumbList=function(){
1098			if (!$p.find('.ytfThumb').not('.busy').length) return false;
1099			$p.find('.ytfThumb').not('.busy').slice(0,10).each(function(){
1100				var img = new Image(),
1101				$o=$j(this);
1102				$o.addClass('busy');
1103				$j(img).load(function(){
1104					$o.find('span.ytfThumbload').replaceWith( $j(this) );
1105					$o.find('img').fadeIn('fast');
1106				}).attr({
1107					src: $o.find('span.ytfThumbload').attr('data-src'),
1108					style: 'display:none',
1109					title: $o.find('span.ytfThumbload').attr('data-title'),
1110					class: $o.find('span.ytfThumbload').attr('data-class')
1111				}).error(function(){
1112					//do something if image cannot load
1113				});
1114			});
1115		}
1116		loadThumbList();
1117		window.setInterval(function(){loadThumbList()},1000);
1118	};
1119
1120	_this.getData = function(){
1121		var items=s.data,
1122			startIndex=0,
1123			maxResults=0,
1124			totalCount=0,
1125			totalResults=0,
1126			totalSelected=0;
1127
1128		// load data
1129		if(s.videos==null || !s.videos.length)
1130		{
1131			$p.find('.ytf-container').empty()
1132				.append('No video to preview. Check your API key or Feed Resource.');
1133			return;
1134		}
1135		_this.data.root = s.videos;
1136		_this.data.count = s.videos.length;
1137
1138		$j.each(s.videos, function(k,v){
1139			if(_this.passKeyword(v.title))
1140			{
1141				_this.data.completed.push(v);
1142				_this.data.process.push(v);
1143			}
1144		});
1145
1146		if(!_this.loadplayer && _this.data.count>0)
1147		{
1148			_this.loadplayer = true;
1149			_this.ytPlayer();
1150		}
1151		
1152
1153		// create intro if enable
1154		if (s.intromode)
1155		{
1156			var bgurl = !/^http/.test(s.bgurl) ? s.root+s.bgurl : s.bgurl,
1157				html = '<div class="ytf-bglist" '+(s.bgurl?'style="background-image:url('+bgurl+')"':'')+'>'+(s.introtext?s.introtext:'<span class="ytf-playbutton" onclick="ytf_'+s.moduleid+'.play(this)"></span>')+'</div>';
1158				$p.find('.ytf-player').prepend(html);
1159		}
1160
1161		_this.events();
1162	};
1163
1164	_this.showDesc=function(desc){
1165		if(s.show_desc && s.desc_position=='player')
1166		{
1167			$p.find('.ytf-video-desc').remove();
1168
1169			if(!/^\s*$/.test(desc)){
1170				$p.find('.ytf-player').after('<div class="ytf-video-desc"><button class="close-btn">X</button><div class="_inn">'+desc.replace(/\r\n|\r|\n/g, '<br/>')+'</div></div>');
1171
1172				$p.find('.ytf-video-desc .close-btn').click(function(){
1173					$j(this).parent().remove();
1174				});
1175			}
1176		}
1177	};
1178
1179	_this.events=function()
1180	{
1181		$p.on("click", ".ytf-overlay", function(){
1182			$j("html,body").removeClass("scrolldis");
1183			$p.find(".ytf-overlay").removeClass("active");
1184			$p.find(".ytf-player").fadeOut("fast");
1185
1186			// stop video
1187			_this.player.stopVideo();
1188
1189			$j(".ytfBlock.active").removeClass("active");
1190		});
1191
1192		if((s.style=="grid"||s.style=="slider") && s.grid_popup=="1")
1193		{
1194			$j('.ytf-grid-off-btn').click(function(){
1195				$j('.ytf-overlay').trigger('click');
1196			});
1197		}
1198
1199		$p.on("click", ".ytfBlock", function(e){
1200			e.preventDefault();
1201			
1202			if ($j(this).hasClass("active") || $j(e.target).is("i"))
1203			{
1204				return false;
1205			}
1206
1207			var id = $j(this).attr('data-index')*1;
1208
1209			if (typeof _this.data.completed[id]=="undefined")
1210			{
1211				return false;
1212			}
1213			
1214			$p.find(".ytfBlock[data-index="+id+"]").addClass("active").siblings().removeClass('active');
1215			
1216			if (s.style=="grid" || s.style=="slider")
1217			{
1218				if (s.grid_popup=="1")
1219				{
1220					$j("html,body").addClass("scrolldis");
1221
1222					// adjust player size
1223					$p.find('.ytf-player').removeAttr("style");
1224					var playerWidth  = $p.find(".ytf-player").width(),
1225						playerHeight = playerWidth*(s.ratio=='4:3'?3/4:9/16),
1226						topOffset 	 = 0;
1227
1228					if (playerHeight>=$j(window).height())
1229					{
1230						playerHeight = $j(window).height();
1231						topOffset = 0;
1232					} else {
1233						topOffset = ($j(window).height() - playerHeight)/2;
1234					}
1235
1236					$p.find('.ytf-player').css({
1237						'height':playerHeight+'px',
1238						'top' : topOffset+'px'
1239					});
1240
1241					$p.find(".ytf-overlay").addClass("active");
1242					$p.find(".ytf-player").fadeIn("fast");
1243				} else {
1244					$j(document).scrollTop( $p.find(".ytf-player").offset().top );
1245				}
1246			}
1247			
1248			_this.player.loadVideoById(_this.data.completed[id].id);
1249			_this.player.setPlaybackQuality(s.quality);
1250			_this.player.playVideo();
1251			vidCurrent=id;
1252
1253			_this.setHash(_this.data.completed[id].id);
1254			_this.showDesc(_this.data.completed[id].description);
1255			
1256			if (s.intromode&&!bglist)
1257			{
1258				$p.find('.ytf-playbutton').addClass('preparePlay');
1259				window.setTimeout(function(){
1260					$p.find('.ytf-playbutton').remove();
1261					$p.find('.ytf-bglist').append('<div class="loading"></div>');
1262				},700);
1263				_this.player.addEventListener("onStateChange", function(e){
1264					if (e.data==1) {
1265						$p.find('.ytf-bglist').fadeOut('fast');
1266					}
1267				});
1268			};
1269		});
1270
1271		/* filter box */
1272		if ((s.style=="ver" || s.style=="grid") && s.searchbox=="1")
1273		{
1274			$j('._yt_filter').keyup(function(e){
1275				var kw=$j.trim($j(this).val());
1276				if(kw==keyword) return;
1277
1278				// update keyword
1279				keyword = kw;
1280				$j('._yt_filter').not($j(this)).val($j(this).val());
1281				$p.find('.swiper-wrapper').empty();
1282
1283				_this.data.completed=[];
1284				_this.data.process=[];
1285				_this.offset_list=0;
1286
1287				$j.each(_this.data.root, function(k,v){
1288					if(_this.passKeyword(v.title))
1289					{
1290						_this.data.completed.push(v);
1291						_this.data.process.push(v);
1292					}
1293				});
1294
1295				_this.update_list();
1296			});
1297		}
1298	};
1299
1300	_this.loadplayer = false;
1301	_this.lock_process_vid = false;
1302
1303	_this.play = function()
1304	{
1305		if (!_this.player)
1306		{
1307			return;
1308		}
1309
1310		$p.find('.ytf-playbutton').addClass('preparePlay');
1311		
1312		window.setTimeout(function()
1313		{
1314			$p.find('.ytf-playbutton').remove();
1315			$p.find('.ytf-bglist').append('<div class="loading"></div>');
1316		},700);
1317
1318		_this.player.setPlaybackQuality(s.quality);
1319		_this.player.playVideo();
1320		_this.player.addEventListener("onStateChange", function(e){
1321			if (e.data==1) { // Play
1322				$p.find('.ytf-bglist').fadeOut('fast');
1323				bglist=true;
1324			}
1325		});
1326	};
1327
1328	_this.ytPlayer = function() {
1329		_this.bindHTML(function(){
1330			var __createPlayer = function(id){
1331				_this.setHash(id);
1332				
1333				return new YT.Player('YTF-'+s.moduleid, {
1334					height: '100%',
1335			        width: '100%',
1336					videoId:id,
1337					playerVars : {
1338						autoplay:s.autoplay?1:0,
1339						controls:s.controls?1:0,
1340						showinfo:s.showinfo?1:0,
1341						rel:s.rel?1:0,
1342						fs:s.fs?1:0,
1343						iv_load_policy:s.annotation?1:3,
1344						modestbranding:s.brand?1:0,
1345						playsinline:s.autoplay?1:0,
1346						mute:s.autoplay?1:0,
1347						cc_load_policy:3
1348					},
1349					events : {
1350						'onReady' : _this.onPlayerReady,
1351						'onStateChange' : _this.onPlayerStateChange
1352					}
1353				});
1354			};
1355
1356			var __hashVid = window.location.hash.replace('#','');
1357
1358			if(!s.hash || __hashVid=='')
1359			{
1360				_this.player=__createPlayer(_this.data.completed[0].id);
1361				_this.showDesc(_this.data.completed[0].description);
1362			} else {
1363				var __findVid = window.setInterval(function(){
1364					var __el = $p.find('[data-id='+__hashVid+']');
1365					if(__el.length)
1366					{
1367						_this.playerIndex = __el.attr('data-index')*1;
1368						_this.player = __createPlayer(__hashVid);
1369
1370						$p.find('.ytfBlock.active').removeClass('active');
1371						__el.addClass('active');
1372						_this.showDesc(_this.data.completed[_this.playerIndex].description);
1373
1374						if(s.style=='grid')
1375						{
1376							// to display current video
1377							var __isVisible = window.setInterval(function(){
1378								if(__el.is(':visible'))
1379								{
1380									window.clearInterval(__isVisible);
1381								} else {
1382									$p.find('.btn-more.active').trigger('click');
1383								}
1384							},100);
1385						}
1386
1387						window.clearInterval(__findVid);
1388					} else {
1389						if(_this.data.process.length==0)
1390						{
1391							// complete but not found this video, run by default
1392							_this.player=__createPlayer(_this.data.completed[0].id);
1393							_this.showDesc(_this.data.completed[0].description);
1394							window.clearInterval(__findVid);
1395						}
1396					}
1397				},500);
1398			}
1399
1400			if(s.style=="background")
1401			{
1402				$j("#YTF-"+s.moduleid).attr("webkit-playsinline", true);
1403			}
1404
1405			// update list
1406			_this.update_list();
1407		});
1408	};
1409
1410	_this.bgSupport = function()
1411	{
1412		var iOs = /iPhone|iPad|iPod/i.test(navigator.userAgent),
1413			BlackBerry = /BlackBerry/i.test(navigator.userAgent),
1414			isWindow = /IEMobile/i.test(navigator.userAgent);
1415
1416		return (iOs || BlackBerry || isWindow) ? false : true;
1417	};
1418
1419	_this.setHash = function(id)
1420	{
1421		if(s.hash==1) window.location.hash=id;
1422	};
1423
1424	_this.onPlayerReady=function(){
1425		_this.swipeTo(_this.playerIndex);
1426		_this.yesReady();
1427		_this.player.setPlaybackQuality(s.quality);
1428		
1429		// add events
1430		if (s.intromode&&s.bgurl) {
1431			// Bind event play
1432			$p.on('click','.ytplay',function(e){
1433				e.preventDefault();
1434				_this.play();
1435			});
1436		};
1437		var isMobile = {
1438		    Android: function() {
1439		        return /Android/i.test(navigator.userAgent);
1440		    },
1441		    BlackBerry: function() {
1442		        return /BlackBerry/i.test(navigator.userAgent);
1443		    },
1444		    iOS: function() {
1445		        return /iPhone|iPad|iPod/i.test(navigator.userAgent);
1446		    },
1447		    Windows: function() {
1448		        return /IEMobile/i.test(navigator.userAgent);
1449		    },
1450		    any: function() {
1451		        return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Windows());
1452		    }
1453		};
1454
1455		if (isMobile.any() && s.autoplay) {
1456			_this.player.loadVideoById(_this.data.completed[0].id);
1457			vidCurrent=0;
1458			_this.player.setPlaybackQuality(s.quality);
1459		}
1460
1461		if(s.style=="background")
1462		{
1463			$p.find(".ytf-api-tools").removeAttr("style");
1464			$p.find(".ytf-player").append('<span></span>');
1465
1466			_this.player.addEventListener("onStateChange", function(e){
1467				if (e.data==1)
1468				{
1469					$p.find(".ytf-api-tools ._status").removeClass("_playing _paused")
1470							.addClass("_playing");
1471				} else if (e.data==2) {
1472					$p.find(".ytf-api-tools ._status").removeClass("_playing _paused")
1473							.addClass("_paused");
1474				}
1475			});
1476
1477			$p.on("click" ,".ytf-api-tools ._status", function(){
1478				if ($j(this).hasClass("_playing"))
1479				{
1480					_this.player.pauseVideo();
1481				} else {
1482					_this.player.playVideo();
1483				}
1484			});
1485
1486			$p.on("click" ,".ytf-api-tools ._sound", function(){
1487				if ($j(this).hasClass("_mute"))
1488				{
1489					_this.player.unMute();
1490				} else {
1491					_this.player.mute();
1492				}
1493				$j(this).toggleClass("_mute").toggleClass("_unmute");
1494			});
1495		}
1496
1497		if(s.hash==1)
1498		{
1499			window.addEventListener("hashchange", function(){
1500				var __hashVid = window.location.hash;
1501					__hashVid = __hashVid.replace('#','');
1502
1503				if(__hashVid!='')
1504				{
1505					var __el = $p.find('[data-id='+__hashVid+']');
1506					if(__el.length) __el.trigger('click');
1507				}
1508			});
1509		}
1510	};
1511
1512	_this.onPlayerStateChange=function(e){
1513		if(e.data==YT.PlayerState.ENDED)
1514		{
1515			if(s.loop==1){
1516				_this.player.playVideo(); 
1517			} else if(s.autonext){
1518				if (s.random) {
1519					vidCurrent=Math.floor(Math.random() * _this.data.completed.length);
1520					_this.player.loadVideoById(_this.data.completed[vidCurrent].id);
1521					_this.setHash(_this.data.completed[vidCurrent].id);
1522				} else {
1523					if (typeof _this.data.completed[vidCurrent+1] != 'undefined'){
1524						_this.player.loadVideoById(_this.data.completed[vidCurrent+1].id);
1525						_this.setHash(_this.data.completed[vidCurrent+1].id);
1526						vidCurrent+=1;			
1527					} else {
1528						vidCurrent=0;
1529						_this.player.loadVideoById(_this.data.completed[0].id);
1530						_this.setHash(_this.data.completed[0].id);
1531					}
1532				}	
1533				_this.player.setPlaybackQuality(s.quality);
1534				$p.find('.ytfBlock[data-index='+vidCurrent+']').addClass('active').siblings().removeClass('active');
1535				_this.swipeTo(vidCurrent);
1536			}
1537		}
1538
1539		if(s.rel==0 && s.style=='background' && (e.data==YT.PlayerState.PAUSED||e.data==YT.PlayerState.ENDED)){
1540			$p.find('.ytf-player').addClass('disrel');
1541		} else {
1542			window.setTimeout(function(){
1543				$p.find('.ytf-player').removeClass('disrel');
1544			}, 500);
1545		}
1546	};
1547
1548	_this.destroy=function(){
1549		if (!s.popup_trigger) {
1550			$p.find('.ytf-bg').fadeOut('fast',function(){
1551				$j('body').css('overflow','');
1552				$j(this).remove();
1553			});
1554			window['ytf_'+s.moduleid]=null;
1555		} else {
1556			window['ytf_'+s.moduleid+'_popup']=true;
1557			$p.find('.ytf-bg').fadeOut('fast');
1558			_this.player.pauseVideo();
1559		}
1560	};
1561
1562	// The program begin run
1563	if (s.popup&&s.popup_trigger) {
1564		$j(document).on('click','.ytplay_'+s.moduleid,function(e){
1565			e.preventDefault();
1566			$p.find('.ytf-bg').show();
1567			if (window['ytf_'+s.moduleid+'_popup'])
1568			{
1569				$p.find('.ytf-bg').fadeIn('fast');
1570			} else {
1571				_this.getData();
1572			}
1573		});
1574	} else {
1575		if (! $p.is(':visible')) {
1576			var _wait=window.setInterval(function(){
1577				if ($p.is(':visible')) {
1578					window.clearInterval (_wait);
1579					_this.getData();
1580				}
1581			},500);
1582			return null;
1583		}
1584		_this.getData();
1585	};
1586
1587	if (s.popup) {
1588		$j(document).on('keyup',function(e){
1589			if (e.keyCode==27) {
1590				if ($p.is(':visible')) {
1591					_this.destroy();
1592				}
1593			}
1594		});
1595	};
1596
1597	return _this;
1598}

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.